From 50b8b671855d7d72a6f7d5bcb841be698834a645 Mon Sep 17 00:00:00 2001 From: castano Date: Sun, 15 Mar 2009 10:18:54 +0000 Subject: [PATCH] Hide file format especific savers. Add generic image saver. Misc fixes under OSX. --- src/CMakeLists.txt | 18 +- src/nvimage/ImageIO.cpp | 799 ++++++++++++++++--------------- src/nvimage/ImageIO.h | 36 +- src/nvtt/Texture.cpp | 66 +-- src/nvtt/Texture.h | 3 +- src/nvtt/cuda/CudaUtils.cpp | 4 + src/nvtt/tests/imperativeapi.cpp | 3 + src/nvtt/tools/decompress.cpp | 11 +- src/nvtt/tools/resize.cpp | 2 +- src/nvtt/tools/thumbnailer.cpp | 10 +- 10 files changed, 491 insertions(+), 461 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9b315f..9ef043d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,6 +70,15 @@ ELSE(MAYA_FOUND) MESSAGE(STATUS "Looking for Maya - not found") ENDIF(MAYA_FOUND) +# FreeImage +INCLUDE(${NV_CMAKE_DIR}/FindFreeImage.cmake) +IF(FREEIMAGE_FOUND) + SET(HAVE_FREEIMAGE ${FREEIMAGE_FOUND} CACHE BOOL "Set to TRUE if FreeImage is found, FALSE otherwise") + MESSAGE(STATUS "Looking for FreeImage - found") +ELSE(FREEIMAGE_FOUND) + MESSAGE(STATUS "Looking for FreeImage - not found") +ENDIF(FREEIMAGE_FOUND) + # JPEG INCLUDE(FindJPEG) IF(JPEG_FOUND) @@ -107,15 +116,6 @@ ELSE(OPENEXR_FOUND) MESSAGE(STATUS "Looking for OpenEXR - not found") ENDIF(OPENEXR_FOUND) -# FreeImage -INCLUDE(${NV_CMAKE_DIR}/FindFreeImage.cmake) -IF(FREEIMAGE_FOUND) - SET(HAVE_FREEIMAGE ${FREEIMAGE_FOUND} CACHE BOOL "Set to TRUE if FreeImage is found, FALSE otherwise") - MESSAGE(STATUS "Looking for FreeImage - found") -ELSE(FREEIMAGE_FOUND) - MESSAGE(STATUS "Looking for FreeImage - not found") -ENDIF(FREEIMAGE_FOUND) - # Qt FIND_PACKAGE(Qt4) diff --git a/src/nvimage/ImageIO.cpp b/src/nvimage/ImageIO.cpp index f08df69..f54c1ff 100644 --- a/src/nvimage/ImageIO.cpp +++ b/src/nvimage/ImageIO.cpp @@ -14,6 +14,10 @@ #include // Extern +#if defined(HAVE_FREEIMAGE) +# include +#else + #if defined(HAVE_JPEG) extern "C" { # include @@ -38,32 +42,58 @@ extern "C" { # include #endif -#if defined(HAVE_FREEIMAGE) -# include -#endif +#endif // defined(HAVE_FREEIMAGE) using namespace nv; -namespace { +namespace nv +{ + namespace ImageIO + { + #if defined(HAVE_FREEIMAGE) - // Array of image load plugins. -// static HashMap s_plugin_load_map; + static Image * loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s); + static FloatImage * loadFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s); - // Array of image save plugins. -// static HashMap s_plugin_save_map; - - struct Color555 { - uint16 b : 5; - uint16 g : 5; - uint16 r : 5; - }; - -} // namespace + static bool saveFreeImage(FREE_IMAGE_FORMAT fif, Stream & s, const Image * img, const ImageMetaData * tags/*=NULL*/); + static bool saveFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s, const FloatImage * img); -#if defined(HAVE_FREEIMAGE) -static Image * loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s); -static FloatImage * loadFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s); -#endif + #else // defined(HAVE_FREEIMAGE) + + struct Color555 { + uint16 b : 5; + uint16 g : 5; + uint16 r : 5; + }; + + static Image * loadTGA(Stream & s); + static bool saveTGA(Stream & s, const Image * img); + + static Image * loadPSD(Stream & s); + + #if defined(HAVE_PNG) + static Image * loadPNG(Stream & s); + static bool savePNG(Stream & s, const Image * img, const PngCommentsMap & comments = PngCommentsMap()); + #endif + + #if defined(HAVE_JPEG) + static Image * loadJPG(Stream & s); + #endif + + #if defined(HAVE_TIFF) + static FloatImage * loadFloatTIFF(const char * fileName, Stream & s); + static bool saveFloatTIFF(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); + #endif + + #if defined(HAVE_OPENEXR) + static FloatImage * loadFloatEXR(const char * fileName, Stream & s); + static bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); + #endif + + #endif // defined(HAVE_FREEIMAGE) + + } // ImageIO namespace +} // nv namespace Image * nv::ImageIO::load(const char * fileName) { @@ -85,15 +115,15 @@ Image * nv::ImageIO::load(const char * fileName, Stream & s) const char * extension = Path::extension(fileName); - if (strCaseCmp(extension, ".tga") == 0) { - return ImageIO::loadTGA(s); - } #if defined(HAVE_FREEIMAGE) FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName); if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { return loadFreeImage(fif, s); } -#endif +#else // defined(HAVE_FREEIMAGE) + if (strCaseCmp(extension, ".tga") == 0) { + return loadTGA(s); + } #if defined(HAVE_JPEG) if (strCaseCmp(extension, ".jpg") == 0 || strCaseCmp(extension, ".jpeg") == 0) { return loadJPG(s); @@ -104,17 +134,15 @@ Image * nv::ImageIO::load(const char * fileName, Stream & s) return loadPNG(s); } #endif - if (strCaseCmp(extension, ".psd") == 0) { return loadPSD(s); } - - // @@ use image plugins? +#endif // defined(HAVE_FREEIMAGE) return NULL; } -bool nv::ImageIO::save(const char * fileName, Stream & s, const Image * img) +bool nv::ImageIO::save(const char * fileName, Stream & s, const Image * img, const ImageMetaData * tags/*=NULL*/) { nvDebugCheck(fileName != NULL); nvDebugCheck(s.isSaving()); @@ -122,19 +150,27 @@ bool nv::ImageIO::save(const char * fileName, Stream & s, const Image * img) const char * extension = Path::extension(fileName); +#if defined(HAVE_FREEIMAGE) + FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName); + if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsWriting(fif)) { +#pragma message(NV_FILE_LINE "TODO: implement saveFreeImage") + //return saveFreeImage(fif, s, img, tags); + } +#else if (strCaseCmp(extension, ".tga") == 0) { - return ImageIO::saveTGA(s, img); + return saveTGA(s, img); } #if defined(HAVE_PNG) if (strCaseCmp(extension, ".png") == 0) { - return ImageIO::savePNG(s, img); + return savePNG(s, img, tags); } +#endif #endif return false; } -bool nv::ImageIO::save(const char * fileName, const Image * img) +bool nv::ImageIO::save(const char * fileName, const Image * img, const ImageMetaData * tags/*=NULL*/) { nvDebugCheck(fileName != NULL); nvDebugCheck(img != NULL); @@ -145,7 +181,7 @@ bool nv::ImageIO::save(const char * fileName, const Image * img) return false; } - return ImageIO::save(fileName, stream, img); + return ImageIO::save(fileName, stream, img, tags); } FloatImage * nv::ImageIO::loadFloat(const char * fileName) @@ -166,7 +202,13 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s) nvDebugCheck(fileName != NULL); const char * extension = Path::extension(fileName); - + +#if defined(HAVE_FREEIMAGE) + FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName); + if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { + return loadFloatFreeImage(fif, s); + } +#else // defined(HAVE_FREEIMAGE) #if defined(HAVE_TIFF) if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) { return loadFloatTIFF(fileName, s); @@ -177,12 +219,7 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s) return loadFloatEXR(fileName, s); } #endif -#if defined(HAVE_FREEIMAGE) - FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName); - if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { - return loadFloatFreeImage(fif, s); - } -#endif +#endif // defined(HAVE_FREEIMAGE) return NULL; } @@ -192,17 +229,22 @@ bool nv::ImageIO::saveFloat(const char * fileName, const FloatImage * fimage, ui { const char * extension = Path::extension(fileName); +#if defined(HAVE_FREEIMAGE) + FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName); + if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsWriting(fif)) { +#pragma message(NV_FILE_LINE "TODO: Implement saveFloatFreeImage") + //return saveFloatFreeImage(fif, s); + return false; + } +#else // defined(HAVE_FREEIMAGE) #if defined(HAVE_OPENEXR) - if (strCaseCmp(extension, ".exr") == 0) - { - return ImageIO::saveFloatEXR(fileName, fimage, base_component, num_components); + if (strCaseCmp(extension, ".exr") == 0) { + return saveFloatEXR(fileName, fimage, base_component, num_components); } #endif - #if defined(HAVE_TIFF) - if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) - { - return ImageIO::saveFloatTIFF(fileName, fimage, base_component, num_components); + if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) { + return saveFloatTIFF(fileName, fimage, base_component, num_components); } #endif @@ -229,10 +271,208 @@ bool nv::ImageIO::saveFloat(const char * fileName, const FloatImage * fimage, ui return ImageIO::save(fileName, image.ptr()); } +#endif // defined(HAVE_FREEIMAGE) return false; } +#if defined(HAVE_FREEIMAGE) + +unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) +{ + Stream * s = (Stream *) handle; + s->serialize(buffer, size * count); + return count; +} + +int DLL_CALLCONV SeekProc(fi_handle handle, long offset, int origin) +{ + Stream * s = (Stream *) handle; + + switch(origin) { + case SEEK_SET : + s->seek(offset); + break; + case SEEK_CUR : + s->seek(s->tell() + offset); + break; + default : + return 1; + } + + return 0; +} + +long DLL_CALLCONV TellProc(fi_handle handle) +{ + Stream * s = (Stream *) handle; + return s->tell(); +} + + +Image * nv::ImageIO::loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s) +{ + nvCheck(!s.isError()); + + FreeImageIO io; + io.read_proc = ReadProc; + io.write_proc = NULL; + io.seek_proc = SeekProc; + io.tell_proc = TellProc; + + FIBITMAP * bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)&s, 0); + + if (bitmap == NULL) + { + return NULL; + } + + const int w = FreeImage_GetWidth(bitmap); + const int h = FreeImage_GetHeight(bitmap); + + if (FreeImage_GetImageType(bitmap) == FIT_BITMAP) + { + if (FreeImage_GetBPP(bitmap) != 32) + { + FIBITMAP * tmp = FreeImage_ConvertTo32Bits(bitmap); + FreeImage_Unload(bitmap); + bitmap = tmp; + } + } + else + { + // @@ Use tone mapping? + FIBITMAP * tmp = FreeImage_ConvertToType(bitmap, FIT_BITMAP, true); + FreeImage_Unload(bitmap); + bitmap = tmp; + } + + + Image * image = new Image(); + image->allocate(w, h); + + // Copy the image over to our internal format, FreeImage has the scanlines bottom to top though. + for (int y=0; y < h; y++) + { + const void * src = FreeImage_GetScanLine(bitmap, h - y - 1); + void * dst = image->scanline(y); + + memcpy(dst, src, 4 * w); + } + + FreeImage_Unload(bitmap); + + return image; +} + +FloatImage * nv::ImageIO::loadFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s) +{ + nvCheck(!s.isError()); + + FreeImageIO io; + io.read_proc = ReadProc; + io.write_proc = NULL; + io.seek_proc = SeekProc; + io.tell_proc = TellProc; + + FIBITMAP * bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)&s, 0); + + if (bitmap == NULL) + { + return NULL; + } + + const int w = FreeImage_GetWidth(bitmap); + const int h = FreeImage_GetHeight(bitmap); + + FREE_IMAGE_TYPE fit = FreeImage_GetImageType(bitmap); + + FloatImage * floatImage = new FloatImage(); + + switch (fit) + { + case FIT_FLOAT: + floatImage->allocate(1, w, h); + + for (int y=0; y < h; y++) + { + const float * src = (const float *)FreeImage_GetScanLine(bitmap, h - y - 1 ); + float * dst = floatImage->scanline(y, 0); + + for (int x=0; x < w; x++) + { + dst[x] = src[x]; + } + } + break; + case FIT_COMPLEX: + floatImage->allocate(2, w, h); + + for (int y=0; y < h; y++) + { + const FICOMPLEX * src = (const FICOMPLEX *)FreeImage_GetScanLine(bitmap, h - y - 1 ); + + float * dst_real = floatImage->scanline(y, 0); + float * dst_imag = floatImage->scanline(y, 1); + + for (int x=0; x < w; x++) + { + dst_real[x] = (float)src[x].r; + dst_imag[x] = (float)src[x].i; + } + } + break; + case FIT_RGBF: + floatImage->allocate(3, w, h); + + for (int y=0; y < h; y++) + { + const FIRGBF * src = (const FIRGBF *)FreeImage_GetScanLine(bitmap, h - y - 1 ); + + float * dst_red = floatImage->scanline(y, 0); + float * dst_green = floatImage->scanline(y, 1); + float * dst_blue = floatImage->scanline(y, 2); + + for (int x=0; x < w; x++) + { + dst_red[x] = src[x].red; + dst_green[x] = src[x].green; + dst_blue[x] = src[x].blue; + } + } + break; + case FIT_RGBAF: + floatImage->allocate(4, w, h); + + for (int y=0; y < h; y++) + { + const FIRGBAF * src = (const FIRGBAF *)FreeImage_GetScanLine(bitmap, h - y - 1 ); + + float * dst_red = floatImage->scanline(y, 0); + float * dst_green = floatImage->scanline(y, 1); + float * dst_blue = floatImage->scanline(y, 2); + float * dst_alpha = floatImage->scanline(y, 3); + + for (int x=0; x < w; x++) + { + dst_red[x] = src[x].red; + dst_green[x] = src[x].green; + dst_blue[x] = src[x].blue; + dst_alpha[x] = src[x].alpha; + } + } + break; + default: + delete floatImage; + floatImage = NULL; + } + + FreeImage_Unload(bitmap); + + return floatImage; +} + +#else defined(HAVE_FREEIMAGE) /// Load TGA image. Image * nv::ImageIO::loadTGA(Stream & s) @@ -256,7 +496,7 @@ Image * nv::ImageIO::loadTGA(Stream & s) // no break is intended! case TGA_TYPE_INDEXED: if( tga.colormap_type!=1 || tga.colormap_size!=24 || tga.colormap_length>256 ) { - nvDebug( "*** ImageIO::loadTGA: Error, only 24bit paletted images are supported.\n" ); + nvDebug( "*** loadTGA: Error, only 24bit paletted images are supported.\n" ); return false; } pal = true; @@ -277,7 +517,7 @@ Image * nv::ImageIO::loadTGA(Stream & s) break; default: - nvDebug( "*** ImageIO::loadTGA: Error, unsupported image type.\n" ); + nvDebug( "*** loadTGA: Error, unsupported image type.\n" ); return false; } @@ -526,310 +766,110 @@ Image * nv::ImageIO::loadPSD(Stream & s) if (channel_num < 4) { // Clear the image. - img->fill(Color32(0, 0, 0, 0xFF)); - } - else - { - // Enable alpha. - img->setFormat(Image::Format_ARGB); - - // Ignore remaining channels. - channel_num = 4; - } - - - const uint pixel_count = header.height * header.width; - - static const uint components[4] = {2, 1, 0, 3}; - - if (compression) - { - s.seek(s.tell() + header.height * header.channel_count * sizeof(uint16)); - - // Read RLE data. - for (uint channel = 0; channel < channel_num; channel++) - { - uint8 * ptr = (uint8 *)img->pixels() + components[channel]; - - uint count = 0; - while( count < pixel_count ) - { - if (s.isAtEnd()) return NULL; - - uint8 c; - s << c; - - uint len = c; - if (len < 128) - { - // Copy next len+1 bytes literally. - len++; - count += len; - if (count > pixel_count) return NULL; - - while (len != 0) - { - s << *ptr; - ptr += 4; - len--; - } - } - else if (len > 128) - { - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0xFF; - len += 2; - count += len; - if (s.isAtEnd() || count > pixel_count) return NULL; - - uint8 val; - s << val; - while( len != 0 ) { - *ptr = val; - ptr += 4; - len--; - } - } - else if( len == 128 ) { - // No-op. - } - } - } - } - else - { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. - - // Read the data by channel. - for (uint channel = 0; channel < channel_num; channel++) - { - uint8 * ptr = (uint8 *)img->pixels() + components[channel]; - - // Read the data. - uint count = pixel_count; - while (count != 0) - { - s << *ptr; - ptr += 4; - count--; - } - } - } - - return img.release(); -} - - -#if defined(HAVE_FREEIMAGE) - -unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) -{ - Stream * s = (Stream *) handle; - s->serialize(buffer, size * count); - return count; -} - -int DLL_CALLCONV SeekProc(fi_handle handle, long offset, int origin) -{ - Stream * s = (Stream *) handle; - - switch(origin) { - case SEEK_SET : - s->seek(offset); - break; - case SEEK_CUR : - s->seek(s->tell() + offset); - break; - default : - return 1; - } - - return 0; -} - -long DLL_CALLCONV TellProc(fi_handle handle) -{ - Stream * s = (Stream *) handle; - return s->tell(); -} - - -Image * loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s) -{ - nvCheck(!s.isError()); - - FreeImageIO io; - io.read_proc = ReadProc; - io.write_proc = NULL; - io.seek_proc = SeekProc; - io.tell_proc = TellProc; - - FIBITMAP * bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)&s, 0); - - if (bitmap == NULL) - { - return NULL; - } - - const int w = FreeImage_GetWidth(bitmap); - const int h = FreeImage_GetHeight(bitmap); - - if (FreeImage_GetImageType(bitmap) == FIT_BITMAP) - { - if (FreeImage_GetBPP(bitmap) != 32) - { - FIBITMAP * tmp = FreeImage_ConvertTo32Bits(bitmap); - FreeImage_Unload(bitmap); - bitmap = tmp; - } - } - else - { - // @@ Use tone mapping? - FIBITMAP * tmp = FreeImage_ConvertToType(bitmap, FIT_BITMAP, true); - FreeImage_Unload(bitmap); - bitmap = tmp; - } - - - Image * image = new Image(); - image->allocate(w, h); - - // Copy the image over to our internal format, FreeImage has the scanlines bottom to top though. - for (int y=0; y < h; y++) + img->fill(Color32(0, 0, 0, 0xFF)); + } + else { - const void * src = FreeImage_GetScanLine(bitmap, h - y - 1); - void * dst = image->scanline(y); + // Enable alpha. + img->setFormat(Image::Format_ARGB); - memcpy(dst, src, 4 * w); + // Ignore remaining channels. + channel_num = 4; } - FreeImage_Unload(bitmap); - - return image; -} - -FloatImage * loadFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s) -{ - nvCheck(!s.isError()); - - FreeImageIO io; - io.read_proc = ReadProc; - io.write_proc = NULL; - io.seek_proc = SeekProc; - io.tell_proc = TellProc; - - FIBITMAP * bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)&s, 0); - if (bitmap == NULL) - { - return NULL; - } + const uint pixel_count = header.height * header.width; - const int w = FreeImage_GetWidth(bitmap); - const int h = FreeImage_GetHeight(bitmap); - - FREE_IMAGE_TYPE fit = FreeImage_GetImageType(bitmap); - - FloatImage * floatImage = new FloatImage(); + static const uint components[4] = {2, 1, 0, 3}; - switch (fit) + if (compression) { - case FIT_FLOAT: - floatImage->allocate(1, w, h); + s.seek(s.tell() + header.height * header.channel_count * sizeof(uint16)); - for (int y=0; y < h; y++) + // Read RLE data. + for (uint channel = 0; channel < channel_num; channel++) + { + uint8 * ptr = (uint8 *)img->pixels() + components[channel]; + + uint count = 0; + while( count < pixel_count ) { - const float * src = (const float *)FreeImage_GetScanLine(bitmap, h - y - 1 ); - float * dst = floatImage->scanline(y, 0); + if (s.isAtEnd()) return NULL; - for (int x=0; x < w; x++) - { - dst[x] = src[x]; - } - } - break; - case FIT_COMPLEX: - floatImage->allocate(2, w, h); - - for (int y=0; y < h; y++) - { - const FICOMPLEX * src = (const FICOMPLEX *)FreeImage_GetScanLine(bitmap, h - y - 1 ); - - float * dst_real = floatImage->scanline(y, 0); - float * dst_imag = floatImage->scanline(y, 1); + uint8 c; + s << c; - for (int x=0; x < w; x++) + uint len = c; + if (len < 128) { - dst_real[x] = (float)src[x].r; - dst_imag[x] = (float)src[x].i; - } - } - break; - case FIT_RGBF: - floatImage->allocate(3, w, h); - - for (int y=0; y < h; y++) - { - const FIRGBF * src = (const FIRGBF *)FreeImage_GetScanLine(bitmap, h - y - 1 ); - - float * dst_red = floatImage->scanline(y, 0); - float * dst_green = floatImage->scanline(y, 1); - float * dst_blue = floatImage->scanline(y, 2); - - for (int x=0; x < w; x++) + // Copy next len+1 bytes literally. + len++; + count += len; + if (count > pixel_count) return NULL; + + while (len != 0) + { + s << *ptr; + ptr += 4; + len--; + } + } + else if (len > 128) { - dst_red[x] = src[x].red; - dst_green[x] = src[x].green; - dst_blue[x] = src[x].blue; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0xFF; + len += 2; + count += len; + if (s.isAtEnd() || count > pixel_count) return NULL; + + uint8 val; + s << val; + while( len != 0 ) { + *ptr = val; + ptr += 4; + len--; + } + } + else if( len == 128 ) { + // No-op. } } - break; - case FIT_RGBAF: - floatImage->allocate(4, w, h); + } + } + else + { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. - for (int y=0; y < h; y++) + // Read the data by channel. + for (uint channel = 0; channel < channel_num; channel++) + { + uint8 * ptr = (uint8 *)img->pixels() + components[channel]; + + // Read the data. + uint count = pixel_count; + while (count != 0) { - const FIRGBAF * src = (const FIRGBAF *)FreeImage_GetScanLine(bitmap, h - y - 1 ); - - float * dst_red = floatImage->scanline(y, 0); - float * dst_green = floatImage->scanline(y, 1); - float * dst_blue = floatImage->scanline(y, 2); - float * dst_alpha = floatImage->scanline(y, 3); - - for (int x=0; x < w; x++) - { - dst_red[x] = src[x].red; - dst_green[x] = src[x].green; - dst_blue[x] = src[x].blue; - dst_alpha[x] = src[x].alpha; - } + s << *ptr; + ptr += 4; + count--; } - break; - default: - delete floatImage; - floatImage = NULL; + } } - - FreeImage_Unload(bitmap); - - return floatImage; -} - -#endif // defined(HAVE_FREEIMAGE) + return img.release(); +} #if defined(HAVE_PNG) static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { nvDebugCheck(png_ptr != NULL); - + Stream * s = (Stream *)png_ptr->io_ptr; s->serialize(data, (int)length); - + if (s->isError()) { png_error(png_ptr, "Read Error"); } @@ -839,7 +879,7 @@ static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t lengt 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); @@ -962,7 +1002,7 @@ Image * nv::ImageIO::loadPNG(Stream & s) Color32 c = img->pixel(i); img->pixel(i) = Color32(c.b, c.g, c.r, c.a); } - + // 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)) { @@ -976,10 +1016,10 @@ Image * nv::ImageIO::loadPNG(Stream & s) static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { nvDebugCheck(png_ptr != NULL); - + Stream * s = (Stream *)png_ptr->io_ptr; s->serialize(data, (int)length); - + if (s->isError()) { png_error(png_ptr, "Write Error"); } @@ -987,12 +1027,12 @@ static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t leng static void user_write_flush(png_structp png_ptr) { } -bool nv::ImageIO::savePNG(Stream & s, const Image * img, const PngCommentsMap & comments) +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); @@ -1036,19 +1076,19 @@ bool nv::ImageIO::savePNG(Stream & s, const Image * img, const PngCommentsMap & png_set_rows(png_ptr, info_ptr, row_data); png_text * text = NULL; - if (comments.size() > 0) + if (tags != NULL && tags->count() > 0) { - text = new png_text[comments.size()]; - memset(text, 0, comments.size() * sizeof(png_text)); + text = new png_text[tags->count()]; + memset(text, 0, tags->count() * sizeof(png_text)); int n = 0; - foreach (i, comments) + foreach (i, *tags) { text[n].compression = PNG_TEXT_COMPRESSION_NONE; - text[n].key = const_cast (comments[i].key.str()); - text[n].text = const_cast (comments[i].value.str()); + text[n].key = const_cast ((*tags)[i].key.str()); + text[n].text = const_cast ((*tags([i].value.str()); n++; } - png_set_text(png_ptr, info_ptr, text, comments.size()); + png_set_text(png_ptr, info_ptr, text, tags->count()); } png_write_png(png_ptr, info_ptr, @@ -1057,7 +1097,7 @@ bool nv::ImageIO::savePNG(Stream & s, const Image * img, const PngCommentsMap & // 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); @@ -1108,12 +1148,12 @@ static void term_source (j_decompress_ptr /*cinfo*/){ 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; @@ -1195,7 +1235,7 @@ static toff_t tiffSeekProc(thandle_t h, toff_t offset, int whence) { Stream * s = (Stream *)h; nvDebugCheck(s != NULL); - + if (!s->isSeekable()) { return (toff_t)-1; @@ -1244,16 +1284,16 @@ static void tiffUnmapFileProc(thandle_t, tdata_t, toff_t) FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName, Stream & s) { nvCheck(!s.isError()); - + 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; } - + ::uint16 spp, bpp, format; ::uint32 width, height; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); @@ -1261,28 +1301,28 @@ FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName, Stream & s) 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); - + int linesize = TIFFScanlineSize(tif); tdata_t buf = (::uint8 *)nv::mem::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 x = 0; x < width; x++) + for(uint x = 0; x < width; x++) { if (bpp == 8) { @@ -1310,9 +1350,9 @@ FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName, Stream & s) } nv::mem::free(buf); - + TIFFClose(tif); - + return fimage.release(); } @@ -1321,7 +1361,7 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage 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; @@ -1340,8 +1380,8 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage 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); @@ -1356,7 +1396,7 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage float * scanline = new float[iW * iC]; for (int y = 0; y < iH; y++) { - for (int c = 0; c < iC; c++) + 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]; @@ -1387,35 +1427,35 @@ namespace { 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."); } - + return m_stream.isAtEnd(); } - + virtual Imf::Int64 tellg() { return m_stream.tell(); } - + virtual void seekg(Imf::Int64 pos) { nvDebugCheck(pos >= 0 && pos < UINT_MAX); m_stream.seek((uint)pos); } - + virtual void clear() { m_stream.clearError(); } - + private: Stream & m_stream; }; @@ -1453,18 +1493,18 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) int height = box.max.x - box.min.y + 1; const Imf::ChannelList & channels = inputFile.header().channels(); - + // 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); - + // Describe image's layout with a framebuffer. Imf::FrameBuffer frameBuffer; uint i = 0; @@ -1473,11 +1513,11 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) 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); - + return fimage.release(); } @@ -1487,33 +1527,34 @@ bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage, 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 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)); } - - 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)); } - + file.setFrameBuffer(frameBuffer); file.writePixels(h); - + return true; } #endif // defined(HAVE_OPENEXR) +#endif // defined(HAVE_FREEIMAGE) diff --git a/src/nvimage/ImageIO.h b/src/nvimage/ImageIO.h index 7f67775..4fa90a8 100644 --- a/src/nvimage/ImageIO.h +++ b/src/nvimage/ImageIO.h @@ -16,43 +16,21 @@ namespace nv namespace ImageIO { + struct ImageMetaData + { + HashMap tagMap; + }; + NVIMAGE_API Image * load(const char * fileName); NVIMAGE_API Image * load(const char * fileName, Stream & s); NVIMAGE_API FloatImage * loadFloat(const char * fileName); NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s); - NVIMAGE_API bool save(const char * fileName, Stream & s, const Image * img); - NVIMAGE_API bool save(const char * fileName, const Image * img); + NVIMAGE_API bool save(const char * fileName, Stream & s, const Image * img, const ImageMetaData * tags=NULL); + NVIMAGE_API bool save(const char * fileName, const Image * img, const ImageMetaData * tags=NULL); NVIMAGE_API bool saveFloat(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); - NVIMAGE_API Image * loadTGA(Stream & s); - NVIMAGE_API bool saveTGA(Stream & s, const Image * img); - - NVIMAGE_API Image * loadPSD(Stream & s); - -#if defined(HAVE_PNG) - NVIMAGE_API Image * loadPNG(Stream & s); - typedef HashMap PngCommentsMap; - NVIMAGE_API bool savePNG(Stream & s, const Image * img, const PngCommentsMap & comments = PngCommentsMap()); -#endif - -#if defined(HAVE_JPEG) - NVIMAGE_API Image * loadJPG(Stream & s); -#endif - -#if defined(HAVE_TIFF) - NVIMAGE_API FloatImage * loadFloatTIFF(const char * fileName, Stream & s); - - NVIMAGE_API bool saveFloatTIFF(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); -#endif - -#if defined(HAVE_OPENEXR) - NVIMAGE_API FloatImage * loadFloatEXR(const char * fileName, Stream & s); - - NVIMAGE_API bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); -#endif - } // ImageIO namespace } // nv namespace diff --git a/src/nvtt/Texture.cpp b/src/nvtt/Texture.cpp index 26a233e..f9e88cd 100644 --- a/src/nvtt/Texture.cpp +++ b/src/nvtt/Texture.cpp @@ -27,6 +27,7 @@ #include #include +#include using namespace nv; using namespace nvtt; @@ -126,8 +127,19 @@ void Texture::setNormalMap(bool isNormalMap) bool Texture::load(const char * fileName) { - // @@ Not implemented. - return false; + // @@ Add support for DDS textures! + + AutoPtr img(ImageIO::loadFloat(fileName)); + + if (img == NULL) + { + return false; + } + + m->imageArray.resize(1); + m->imageArray[0] = img.release(); + + return true; } void Texture::setTexture2D(InputFormat format, int w, int h, int idx, void * data) @@ -140,7 +152,7 @@ void Texture::resize(int w, int h, ResizeFilter filter) { if (m->imageArray.count() > 0) { - if (w == m->imageArray[0].width() && h == m->imageArray[0].height()) return; + if (w == m->imageArray[0]->width() && h == m->imageArray[0]->height()) return; } // @TODO: if cubemap, make sure w == h. @@ -156,25 +168,25 @@ void Texture::resize(int w, int h, ResizeFilter filter) if (filter == ResizeFilter_Box) { BoxFilter filter; - m->imageArray[i].resize(filter, w, h, wrapMode, 3); + m->imageArray[i]->resize(filter, w, h, wrapMode, 3); } else if (filter == ResizeFilter_Triangle) { TriangleFilter filter; - m->imageArray[i].resize(filter, w, h, wrapMode, 3); + m->imageArray[i]->resize(filter, w, h, wrapMode, 3); } else if (filter == ResizeFilter_Kaiser) { //KaiserFilter filter(inputOptions.kaiserWidth); //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); KaiserFilter filter(3); - m->imageArray[i].resize(filter, w, h, wrapMode, 3); + m->imageArray[i]->resize(filter, w, h, wrapMode, 3); } else //if (filter == ResizeFilter_Mitchell) { nvDebugCheck(filter == ResizeFilter_Mitchell); MitchellFilter filter; - m->imageArray[i].resize(filter, w, h, wrapMode, 3); + m->imageArray[i]->resize(filter, w, h, wrapMode, 3); } } else @@ -182,25 +194,25 @@ void Texture::resize(int w, int h, ResizeFilter filter) if (filter == ResizeFilter_Box) { BoxFilter filter; - m->imageArray[i].resize(filter, w, h, wrapMode); + m->imageArray[i]->resize(filter, w, h, wrapMode); } else if (filter == ResizeFilter_Triangle) { TriangleFilter filter; - m->imageArray[i].resize(filter, w, h, wrapMode); + m->imageArray[i]->resize(filter, w, h, wrapMode); } else if (filter == ResizeFilter_Kaiser) { //KaiserFilter filter(inputOptions.kaiserWidth); //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); KaiserFilter filter(3); - m->imageArray[i].resize(filter, w, h, wrapMode); + m->imageArray[i]->resize(filter, w, h, wrapMode); } else //if (filter == ResizeFilter_Mitchell) { nvDebugCheck(filter == ResizeFilter_Mitchell); MitchellFilter filter; - m->imageArray[i].resize(filter, w, h, wrapMode); + m->imageArray[i]->resize(filter, w, h, wrapMode); } } } @@ -210,8 +222,8 @@ void Texture::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter) { if (m->imageArray.count() > 0) { - int w = m->imageArray[0].width(); - int h = m->imageArray[0].height(); + int w = m->imageArray[0]->width(); + int h = m->imageArray[0]->height(); nvDebugCheck(w > 0); nvDebugCheck(h > 0); @@ -255,8 +267,8 @@ bool Texture::buildNextMipmap(MipmapFilter filter) { if (m->imageArray.count() > 0) { - int w = m->imageArray[0].width(); - int h = m->imageArray[0].height(); + int w = m->imageArray[0]->width(); + int h = m->imageArray[0]->height(); nvDebugCheck(w > 0); nvDebugCheck(h > 0); @@ -278,12 +290,12 @@ bool Texture::buildNextMipmap(MipmapFilter filter) if (filter == MipmapFilter_Box) { BoxFilter filter; - m->imageArray[i].downSample(filter, wrapMode, 3); + m->imageArray[i]->downSample(filter, wrapMode, 3); } else if (filter == MipmapFilter_Triangle) { TriangleFilter filter; - m->imageArray[i].downSample(filter, wrapMode, 3); + m->imageArray[i]->downSample(filter, wrapMode, 3); } else if (filter == MipmapFilter_Kaiser) { @@ -291,19 +303,19 @@ bool Texture::buildNextMipmap(MipmapFilter filter) //KaiserFilter filter(inputOptions.kaiserWidth); //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); KaiserFilter filter(3); - m->imageArray[i].downSample(filter, wrapMode, 3); + m->imageArray[i]->downSample(filter, wrapMode, 3); } } else { if (filter == MipmapFilter_Box) { - m->imageArray[i].fastDownSample(); + m->imageArray[i]->fastDownSample(); } else if (filter == MipmapFilter_Triangle) { TriangleFilter filter; - m->imageArray[i].downSample(filter, wrapMode); + m->imageArray[i]->downSample(filter, wrapMode); } else //if (filter == MipmapFilter_Kaiser) { @@ -311,7 +323,7 @@ bool Texture::buildNextMipmap(MipmapFilter filter) //KaiserFilter filter(inputOptions.kaiserWidth); //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); KaiserFilter filter(3); - m->imageArray[i].downSample(filter, wrapMode); + m->imageArray[i]->downSample(filter, wrapMode); } } } @@ -328,7 +340,7 @@ void Texture::toLinear(float gamma) foreach(i, m->imageArray) { - m->imageArray[i].toLinear(0, 3, gamma); + m->imageArray[i]->toLinear(0, 3, gamma); } } @@ -340,7 +352,7 @@ void Texture::toGamma(float gamma) foreach(i, m->imageArray) { - m->imageArray[i].toGamma(0, 3, gamma); + m->imageArray[i]->toGamma(0, 3, gamma); } } @@ -358,7 +370,7 @@ void Texture::transform(const float w0[4], const float w1[4], const float w2[4], foreach(i, m->imageArray) { - m->imageArray[i].transform(0, xform, voffset); + m->imageArray[i]->transform(0, xform, voffset); } } @@ -370,7 +382,7 @@ void Texture::swizzle(int r, int g, int b, int a) foreach(i, m->imageArray) { - m->imageArray[i].swizzle(0, r, g, b, a); + m->imageArray[i]->swizzle(0, r, g, b, a); } } @@ -382,7 +394,7 @@ void Texture::scaleBias(int channel, float scale, float bias) foreach(i, m->imageArray) { - m->imageArray[i].scaleBias(channel, 1, scale, bias); + m->imageArray[i]->scaleBias(channel, 1, scale, bias); } } @@ -392,7 +404,7 @@ void Texture::normalizeNormals() foreach(i, m->imageArray) { - m->imageArray[i].normalize(0); + m->imageArray[i]->normalize(0); } } diff --git a/src/nvtt/Texture.h b/src/nvtt/Texture.h index c273d64..a57401c 100644 --- a/src/nvtt/Texture.h +++ b/src/nvtt/Texture.h @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -59,7 +60,7 @@ namespace nvtt AlphaMode alphaMode; bool isNormalMap; - nv::Array imageArray; + nv::Array imageArray; }; diff --git a/src/nvtt/cuda/CudaUtils.cpp b/src/nvtt/cuda/CudaUtils.cpp index e2963f5..a17cc4c 100644 --- a/src/nvtt/cuda/CudaUtils.cpp +++ b/src/nvtt/cuda/CudaUtils.cpp @@ -72,8 +72,10 @@ static bool isWow32() #endif */ + static bool isCudaDriverAvailable(int version) { +#if defined HAVE_CUDA #if NV_OS_WIN32 Library nvcuda("nvcuda.dll"); #else @@ -109,11 +111,13 @@ static bool isCudaDriverAvailable(int version) return driverVersion >= version; } +#endif // HAVE_CUDA return false; } + /// Determine if CUDA is available. bool nv::cuda::isHardwarePresent() { diff --git a/src/nvtt/tests/imperativeapi.cpp b/src/nvtt/tests/imperativeapi.cpp index 33edd40..abbe4a7 100644 --- a/src/nvtt/tests/imperativeapi.cpp +++ b/src/nvtt/tests/imperativeapi.cpp @@ -29,7 +29,10 @@ int main(int argc, char *argv[]) { nvtt::CompressionOptions compressionOptions; + compressionOptions.setFormat(nvtt::Format_BC1); + nvtt::OutputOptions outputOptions; + outputOptions.setFileName("output.dds"); nvtt::Context context; nvtt::Texture texture = context.createTexture(); diff --git a/src/nvtt/tools/decompress.cpp b/src/nvtt/tools/decompress.cpp index 0f069fd..b51df5c 100644 --- a/src/nvtt/tools/decompress.cpp +++ b/src/nvtt/tools/decompress.cpp @@ -179,16 +179,7 @@ int main(int argc, char *argv[]) return 1; } -#ifdef HAVE_PNG - if (savePNG) - { - nv::ImageIO::savePNG(stream, &mipmap); - } - else -#endif - { - nv::ImageIO::saveTGA(stream, &mipmap); - } + nv::ImageIO::save(name, stream, &mipmap); } } diff --git a/src/nvtt/tools/resize.cpp b/src/nvtt/tools/resize.cpp index f23f80f..3dc8282 100644 --- a/src/nvtt/tools/resize.cpp +++ b/src/nvtt/tools/resize.cpp @@ -176,7 +176,7 @@ int main(int argc, char *argv[]) result->setFormat(nv::Image::Format_ARGB); nv::StdOutputStream stream(output); - nv::ImageIO::saveTGA(stream, result.ptr()); // @@ Add generic save function. Add support for png too. + nv::ImageIO::save(output, stream, result.ptr()); return 0; } diff --git a/src/nvtt/tools/thumbnailer.cpp b/src/nvtt/tools/thumbnailer.cpp index 4ad3224..8f5ea2c 100644 --- a/src/nvtt/tools/thumbnailer.cpp +++ b/src/nvtt/tools/thumbnailer.cpp @@ -119,9 +119,9 @@ int main(int argc, char *argv[]) nv::Image image; if (!loadImage(image, input)) return 1; - nv::ImageIO::PngCommentsMap pngComments; - pngComments.add("Thumb::Image::Width", nv::StringBuilder().number (image.width())); - pngComments.add("Thumb::Image::Height", nv::StringBuilder().number (image.height())); + nv::ImageIO::ImageMetaData metaData; + metaData.tagMap.add("Thumb::Image::Width", nv::StringBuilder().number (image.width())); + metaData.tagMap.add("Thumb::Image::Height", nv::StringBuilder().number (image.height())); if ((image.width() > size) || (image.height() > size)) { @@ -145,12 +145,12 @@ int main(int argc, char *argv[]) result->setFormat(nv::Image::Format_ARGB); nv::StdOutputStream stream(output); - nv::ImageIO::savePNG(stream, result.ptr(), pngComments); + nv::ImageIO::save(output, stream, result.ptr(), &metaData); } else { nv::StdOutputStream stream(output); - nv::ImageIO::savePNG(stream, &image, pngComments); + nv::ImageIO::save(output, stream, &image, &metaData); } return 0;