From 0036019e67ef1074a61552b4072dec16b2666992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 5 Dec 2017 22:00:53 +0100 Subject: [PATCH] tinyexr: Update to current upstream master branch --- thirdparty/README.md | 2 +- thirdparty/tinyexr/tinyexr.h | 444 +++++++++++++++++++++++++---------- 2 files changed, 316 insertions(+), 130 deletions(-) diff --git a/thirdparty/README.md b/thirdparty/README.md index a6fbde58406..8ff64c46360 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -390,7 +390,7 @@ Files extracted from upstream source: ## tinyexr - Upstream: https://github.com/syoyo/tinyexr -- Version: 0.9.5+ (git a145d69) +- Version: 0.9.5+ (git 9f784ca - 24 October 2017) - License: BSD-3-Clause Files extracted from upstream source: diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h index 44cc287da74..606c19756a5 100644 --- a/thirdparty/tinyexr/tinyexr.h +++ b/thirdparty/tinyexr/tinyexr.h @@ -259,7 +259,8 @@ typedef struct _DeepImage { } DeepImage; // @deprecated { to be removed. } -// Loads single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. +// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel +// alpha) or RGB(A) channels. // Application must free image data as returned by `out_rgba` // Result image format is: float x RGBA x width x hight // Returns negative value and may set error string in `err` when there's an @@ -269,9 +270,14 @@ extern int LoadEXR(float **out_rgba, int *width, int *height, // @deprecated { to be removed. } // Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. -// components must be 3(RGB) or 4(RGBA). -// Result image format is: float x RGB(A) x width x hight -extern int SaveEXR(const float *data, int width, int height, int components, +// components must be 1(Grayscale), 3(RGB) or 4(RGBA). +// Input image format is: `float x width x height`, or `float x RGB(A) x width x +// hight` +// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero +// value. +// Save image as fp32(FLOAT) format when `save_as_fp16` is 0. +extern int SaveEXR(const float *data, const int width, const int height, + const int components, const int save_as_fp16, const char *filename); // Initialize EXRHeader struct @@ -401,12 +407,11 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename, // For emscripten. // Loads single-frame OpenEXR image from memory. Assume EXR image contains // RGB(A) channels. -// `out_rgba` must have enough memory(at least sizeof(float) x 4(RGBA) x width x -// hight) // Returns negative value and may set error string in `err` when there's an // error -extern int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, - size_t size, const char **err); +extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err); #ifdef __cplusplus } @@ -439,7 +444,8 @@ extern int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, #if TINYEXR_USE_MINIZ #else -#include "zlib.h" +// Issue #46. Please include your own zlib-compatible API header before including `tinyexr.h` +//#include "zlib.h" #endif #if TINYEXR_USE_ZFP @@ -478,13 +484,11 @@ namespace miniz { #pragma clang diagnostic ignored "-Wsign-conversion" #pragma clang diagnostic ignored "-Wc++11-extensions" #pragma clang diagnostic ignored "-Wconversion" -#ifdef __APPLE__ -#if __clang_major__ >= 8 && __clang__minor__ > 1 +#pragma clang diagnostic ignored "-Wunused-function" +#if __has_warning("-Wcomma") #pragma clang diagnostic ignored "-Wcomma" #endif #endif -#pragma clang diagnostic ignored "-Wunused-function" -#endif /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing @@ -1913,11 +1917,11 @@ static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } -static void *def_realloc_func(void *opaque, void *address, size_t items, - size_t size) { - (void)opaque, (void)address, (void)items, (void)size; - return MZ_REALLOC(address, items * size); -} +// static void *def_realloc_func(void *opaque, void *address, size_t items, +// size_t size) { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +//} const char *mz_version(void) { return MZ_VERSION; } @@ -2889,8 +2893,9 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, tinfl_status status = tinfl_decompress( &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, - &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; @@ -3537,9 +3542,10 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = - ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && - (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + int n, + use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) @@ -3569,8 +3575,9 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { if (!use_raw_block) comp_block_succeeded = - tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || - (d->m_total_lz_bytes < 48)); + tdefl_compress_block(d, + (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); // If the block gets expanded, forget the current contents of the output // buffer and send a raw block instead. @@ -5215,9 +5222,10 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + - MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + - MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; @@ -6875,6 +6883,12 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, #ifdef __clang__ #pragma clang diagnostic pop #endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } #else @@ -7338,11 +7352,23 @@ static void CompressZip(unsigned char *dst, compressedSize = outSize; #endif + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } } static void DecompressZip(unsigned char *dst, unsigned long *uncompressed_size /* inout */, const unsigned char *src, unsigned long src_size) { + if ((*uncompressed_size) == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return; + } std::vector tmpBuf(*uncompressed_size); #if TINYEXR_USE_MINIZ @@ -7402,6 +7428,22 @@ static void DecompressZip(unsigned char *dst, #pragma clang diagnostic ignored "-Wsign-conversion" #endif +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning( \ + disable : 4267) // 'argument': conversion from '__int64' to 'int', + // possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + + const int MIN_RUN_LENGTH = 3; const int MAX_RUN_LENGTH = 127; @@ -7494,6 +7536,7 @@ static int rleUncompress(int inLength, int maxLength, const signed char in[], #ifdef __clang__ #pragma clang diagnostic pop #endif + // End of RLE code from OpenEXR ----------------------------------- static void CompressRle(unsigned char *dst, @@ -7554,11 +7597,24 @@ static void CompressRle(unsigned char *dst, assert(outSize > 0); compressedSize = static_cast(outSize); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } } static void DecompressRle(unsigned char *dst, const unsigned long uncompressed_size, const unsigned char *src, unsigned long src_size) { + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return; + } + std::vector tmpBuf(uncompressed_size); int ret = rleUncompress(static_cast(src_size), @@ -8874,7 +8930,12 @@ static void applyLut(const unsigned short lut[USHORT_RANGE], #pragma clang diagnostic pop #endif // __clang__ -static bool CompressPiz(unsigned char *outPtr, unsigned int &outSize, +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, const unsigned char *inPtr, size_t inSize, const std::vector &channelInfo, int data_width, int num_lines) { @@ -8981,16 +9042,29 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int &outSize, hufCompress(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), buf); memcpy(lengthPtr, &length, sizeof(int)); - outSize = static_cast( + (*outSize) = static_cast( (reinterpret_cast(buf) - outPtr) + static_cast(length)); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if ((*outSize) >= inSize) { + (*outSize) = static_cast(inSize); + memcpy(outPtr, inPtr, inSize); + } return true; } static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, - size_t tmpBufSize, int num_channels, + size_t tmpBufSize, size_t inLen, int num_channels, const EXRChannelInfo *channels, int data_width, int num_lines) { + if (inLen == tmpBufSize) { + // Data is not compressed(Issue 40). + memcpy(outPtr, inPtr, inLen); + return true; + } + unsigned char bitmap[BITMAP_SIZE]; unsigned short minNonZero; unsigned short maxNonZero; @@ -9165,6 +9239,11 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines, const ZFPCompressionParam ¶m) { size_t uncompressed_size = dst_width * dst_num_lines * num_channels; + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + } + zfp_stream *zfp = NULL; zfp_field *field = NULL; @@ -9309,12 +9388,11 @@ static void DecodePixelData(/* out */ unsigned char **out_images, // Allocate original data size. std::vector outBuf(static_cast( static_cast(width * num_lines) * pixel_data_size)); - size_t tmpBufLen = static_cast( - static_cast(width * num_lines) * pixel_data_size); + size_t tmpBufLen = outBuf.size(); bool ret = tinyexr::DecompressPiz( reinterpret_cast(&outBuf.at(0)), data_ptr, tmpBufLen, - static_cast(num_channels), channels, width, num_lines); + data_len, static_cast(num_channels), channels, width, num_lines); assert(ret); (void)ret; @@ -10039,8 +10117,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, } else if (attr_name.compare("compression") == 0) { bool ok = false; - if ((data[0] >= TINYEXR_COMPRESSIONTYPE_NONE) && - (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ)) { + if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) { ok = true; } @@ -10150,9 +10227,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, // Custom attribute(up to TINYEXR_MAX_ATTRIBUTES) if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) { EXRAttribute attrib; +#ifdef _MSC_VER + strncpy_s(attrib.name, attr_name.c_str(), 255); + strncpy_s(attrib.type, attr_type.c_str(), 255); +#else strncpy(attrib.name, attr_name.c_str(), 255); - attrib.name[255] = '\0'; strncpy(attrib.type, attr_type.c_str(), 255); +#endif + attrib.name[255] = '\0'; attrib.type[255] = '\0'; attrib.size = static_cast(data.size()); attrib.value = static_cast(malloc(data.size())); @@ -10246,8 +10328,12 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { exr_header->channels = static_cast(malloc( sizeof(EXRChannelInfo) * static_cast(exr_header->num_channels))); for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { +#ifdef _MSC_VER + strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#else strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); - // manually add '\0' for safety. +#endif + // manually add '\0' for safety. exr_header->channels[c].name[255] = '\0'; exr_header->channels[c].pixel_type = info.channels[c].pixel_type; @@ -10309,6 +10395,8 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, &channel_offset, num_channels, exr_header->channels); + bool invalid_data = false; + if (exr_header->tiled) { size_t num_tiles = offsets.size(); // = # of blocks @@ -10403,18 +10491,26 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, // Adjust line_no with data_window.bmin.y line_no -= exr_header->data_window[1]; - tinyexr::DecodePixelData( - exr_image->images, exr_header->requested_pixel_types, data_ptr, - static_cast(data_len), exr_header->compression_type, - exr_header->line_order, data_width, data_height, data_width, y, - line_no, num_lines, static_cast(pixel_data_size), - static_cast(exr_header->num_custom_attributes), - exr_header->custom_attributes, - static_cast(exr_header->num_channels), exr_header->channels, - channel_offset_list); + if (line_no < 0) { + invalid_data = true; + } else { + tinyexr::DecodePixelData( + exr_image->images, exr_header->requested_pixel_types, data_ptr, + static_cast(data_len), exr_header->compression_type, + exr_header->line_order, data_width, data_height, data_width, y, + line_no, num_lines, static_cast(pixel_data_size), + static_cast(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), exr_header->channels, + channel_offset_list); + } } // omp parallel } + if (invalid_data) { + return TINYEXR_ERROR_INVALID_DATA; + } + // Overwrite `pixel_type` with `requested_pixel_type`. { for (int c = 0; c < exr_header->num_channels; c++) { @@ -10633,46 +10729,63 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, } } - if (idxR == -1) { - if (err) { - (*err) = "R channel not found\n"; + if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) { + // Alpha channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = reinterpret_cast(exr_image.images)[0][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } else { + // Assume RGB(A) + + if (idxR == -1) { + if (err) { + (*err) = "R channel not found\n"; + } + + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; } - // @todo { free exr_image } - return TINYEXR_ERROR_INVALID_DATA; - } - - if (idxG == -1) { - if (err) { - (*err) = "G channel not found\n"; + if (idxG == -1) { + if (err) { + (*err) = "G channel not found\n"; + } + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; } - // @todo { free exr_image } - return TINYEXR_ERROR_INVALID_DATA; - } - if (idxB == -1) { - if (err) { - (*err) = "B channel not found\n"; + if (idxB == -1) { + if (err) { + (*err) = "B channel not found\n"; + } + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; } - // @todo { free exr_image } - return TINYEXR_ERROR_INVALID_DATA; - } - (*out_rgba) = reinterpret_cast( - malloc(4 * sizeof(float) * static_cast(exr_image.width) * - static_cast(exr_image.height))); - for (int i = 0; i < exr_image.width * exr_image.height; i++) { - (*out_rgba)[4 * i + 0] = - reinterpret_cast(exr_image.images)[idxR][i]; - (*out_rgba)[4 * i + 1] = - reinterpret_cast(exr_image.images)[idxG][i]; - (*out_rgba)[4 * i + 2] = - reinterpret_cast(exr_image.images)[idxB][i]; - if (idxA != -1) { - (*out_rgba)[4 * i + 3] = - reinterpret_cast(exr_image.images)[idxA][i]; - } else { - (*out_rgba)[4 * i + 3] = 1.0; + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } } } @@ -10712,7 +10825,11 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, if (ret != TINYEXR_SUCCESS) { if (err && !err_str.empty()) { +#ifdef _WIN32 + (*err) = _strdup(err_str.c_str()); // May leak +#else (*err) = strdup(err_str.c_str()); // May leak +#endif } } @@ -10724,8 +10841,9 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, return ret; } -int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, - const char **err) { +int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err) { if (out_rgba == NULL || memory == NULL) { if (err) { (*err) = "Invalid argument.\n"; @@ -10748,6 +10866,13 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, if (ret != TINYEXR_SUCCESS) { return ret; } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } InitEXRImage(&exr_image); ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); @@ -10797,19 +10922,32 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, return TINYEXR_ERROR_INVALID_DATA; } - // Assume `out_rgba` have enough memory allocated. + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + for (int i = 0; i < exr_image.width * exr_image.height; i++) { - out_rgba[4 * i + 0] = reinterpret_cast(exr_image.images)[idxR][i]; - out_rgba[4 * i + 1] = reinterpret_cast(exr_image.images)[idxG][i]; - out_rgba[4 * i + 2] = reinterpret_cast(exr_image.images)[idxB][i]; - if (idxA > 0) { - out_rgba[4 * i + 3] = - reinterpret_cast(exr_image.images)[idxA][i]; - } else { - out_rgba[4 * i + 3] = 1.0; - } + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } + else { + (*out_rgba)[4 * i + 3] = 1.0; + } } + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_SUCCESS; } @@ -11304,7 +11442,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, std::vector block(bufLen); unsigned int outSize = static_cast(block.size()); - CompressPiz(&block.at(0), outSize, + CompressPiz(&block.at(0), &outSize, reinterpret_cast(&buf.at(0)), buf.size(), channels, exr_image->width, h); @@ -11445,6 +11583,16 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { return TINYEXR_ERROR_INVALID_ARGUMENT; } +#ifdef _MSC_VER + FILE *fp = NULL; + errno_t errcode = fopen_s(&fp, filename, "rb"); + if ((!errcode) || (!fp)) { + if (err) { + (*err) = "Cannot read file."; + } + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else FILE *fp = fopen(filename, "rb"); if (!fp) { if (err) { @@ -11452,6 +11600,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { } return TINYEXR_ERROR_CANT_OPEN_FILE; } +#endif size_t filesize; // Compute size @@ -11521,6 +11670,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (0 == size) { return TINYEXR_ERROR_INVALID_DATA; } else if (marker[0] == '\0') { + marker++; size--; break; } @@ -11710,11 +11860,13 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { // decode sample data. { unsigned long dstLen = static_cast(unpackedSampleDataSize); - tinyexr::DecompressZip( - reinterpret_cast(&sample_data.at(0)), &dstLen, - data_ptr + 28 + packedOffsetTableSize, - static_cast(packedSampleDataSize)); - assert(dstLen == static_cast(unpackedSampleDataSize)); + if (dstLen) { + tinyexr::DecompressZip( + reinterpret_cast(&sample_data.at(0)), &dstLen, + data_ptr + 28 + packedOffsetTableSize, + static_cast(packedSampleDataSize)); + assert(dstLen == static_cast(unpackedSampleDataSize)); + } } // decode sample @@ -11760,7 +11912,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (channels[c].pixel_type == 0) { // UINT for (size_t x = 0; x < static_cast(samples_per_line); x++) { unsigned int ui = *reinterpret_cast( - &sample_data.at(data_offset + x * sizeof(int))); + &sample_data.at(size_t(data_offset) + x * sizeof(int))); deep_image->image[c][y][x] = static_cast(ui); // @fixme } data_offset += @@ -11769,7 +11921,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { for (size_t x = 0; x < static_cast(samples_per_line); x++) { tinyexr::FP16 f16; f16.u = *reinterpret_cast( - &sample_data.at(data_offset + x * sizeof(short))); + &sample_data.at(size_t(data_offset) + x * sizeof(short))); tinyexr::FP32 f32 = half_to_float(f16); deep_image->image[c][y][x] = f32.f; } @@ -11777,7 +11929,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { } else { // float for (size_t x = 0; x < static_cast(samples_per_line); x++) { float f = *reinterpret_cast( - &sample_data.at(data_offset + x * sizeof(float))); + &sample_data.at(size_t(data_offset) + x * sizeof(float))); deep_image->image[c][y][x] = f; } data_offset += sizeof(float) * static_cast(samples_per_line); @@ -11961,7 +12113,11 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, if (ret != TINYEXR_SUCCESS) { if (err) { +#ifdef _WIN32 + (*err) = _strdup(err_str.c_str()); // may leak +#else (*err) = strdup(err_str.c_str()); // may leak +#endif } return ret; } @@ -12287,8 +12443,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images, } int SaveEXR(const float *data, int width, int height, int components, - const char *outfilename) { - if (components == 3 || components == 4) { + const int save_as_fp16, const char *outfilename) { + if ((components == 1) || components == 3 || components == 4) { // OK } else { return TINYEXR_ERROR_INVALID_ARGUMENT; @@ -12307,18 +12463,24 @@ int SaveEXR(const float *data, int width, int height, int components, image.num_channels = components; std::vector images[4]; - images[0].resize(static_cast(width * height)); - images[1].resize(static_cast(width * height)); - images[2].resize(static_cast(width * height)); - images[3].resize(static_cast(width * height)); - // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers - for (size_t i = 0; i < static_cast(width * height); i++) { - images[0][i] = data[static_cast(components) * i + 0]; - images[1][i] = data[static_cast(components) * i + 1]; - images[2][i] = data[static_cast(components) * i + 2]; - if (components == 4) { - images[3][i] = data[static_cast(components) * i + 3]; + if (components == 1) { + images[0].resize(static_cast(width * height)); + memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); + } else { + images[0].resize(static_cast(width * height)); + images[1].resize(static_cast(width * height)); + images[2].resize(static_cast(width * height)); + images[3].resize(static_cast(width * height)); + + // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers + for (size_t i = 0; i < static_cast(width * height); i++) { + images[0][i] = data[static_cast(components) * i + 0]; + images[1][i] = data[static_cast(components) * i + 1]; + images[2][i] = data[static_cast(components) * i + 2]; + if (components == 4) { + images[3][i] = data[static_cast(components) * i + 3]; + } } } @@ -12328,10 +12490,12 @@ int SaveEXR(const float *data, int width, int height, int components, image_ptr[1] = &(images[2].at(0)); // B image_ptr[2] = &(images[1].at(0)); // G image_ptr[3] = &(images[0].at(0)); // R - } else { + } else if (components == 3) { image_ptr[0] = &(images[2].at(0)); // B image_ptr[1] = &(images[1].at(0)); // G image_ptr[2] = &(images[0].at(0)); // R + } else if (components == 1) { + image_ptr[0] = &(images[0].at(0)); // A } image.images = reinterpret_cast(image_ptr); @@ -12343,21 +12507,41 @@ int SaveEXR(const float *data, int width, int height, int components, sizeof(EXRChannelInfo) * static_cast(header.num_channels))); // Must be (A)BGR order, since most of EXR viewers expect this channel order. if (components == 4) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); + strncpy_s(header.channels[1].name, "B", 255); + strncpy_s(header.channels[2].name, "G", 255); + strncpy_s(header.channels[3].name, "R", 255); +#else strncpy(header.channels[0].name, "A", 255); - header.channels[0].name[strlen("A")] = '\0'; strncpy(header.channels[1].name, "B", 255); - header.channels[1].name[strlen("B")] = '\0'; strncpy(header.channels[2].name, "G", 255); - header.channels[2].name[strlen("G")] = '\0'; strncpy(header.channels[3].name, "R", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + header.channels[1].name[strlen("B")] = '\0'; + header.channels[2].name[strlen("G")] = '\0'; header.channels[3].name[strlen("R")] = '\0'; - } else { + } else if (components == 3) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "B", 255); + strncpy_s(header.channels[1].name, "G", 255); + strncpy_s(header.channels[2].name, "R", 255); +#else strncpy(header.channels[0].name, "B", 255); - header.channels[0].name[strlen("B")] = '\0'; strncpy(header.channels[1].name, "G", 255); - header.channels[1].name[strlen("G")] = '\0'; strncpy(header.channels[2].name, "R", 255); +#endif + header.channels[0].name[strlen("B")] = '\0'; + header.channels[1].name[strlen("G")] = '\0'; header.channels[2].name[strlen("R")] = '\0'; + } else { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); +#else + strncpy(header.channels[0].name, "A", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; } header.pixel_types = static_cast( @@ -12367,9 +12551,15 @@ int SaveEXR(const float *data, int width, int height, int components, for (int i = 0; i < header.num_channels; i++) { header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image - header.requested_pixel_types[i] = - TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in - // .EXR + + if (save_as_fp16 > 0) { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format + } else { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e. + // no precision reduction) + } } const char *err; @@ -12385,9 +12575,5 @@ int SaveEXR(const float *data, int width, int height, int components, return ret; } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - #endif // TINYEXR_IMPLEMENTATION_DEIFNED #endif // TINYEXR_IMPLEMENTATION