tinyexr: Update to current upstream master branch

This commit is contained in:
Rémi Verschelde 2017-12-05 22:00:53 +01:00
parent c2b8856f2d
commit 0036019e67
2 changed files with 316 additions and 130 deletions

View file

@ -390,7 +390,7 @@ Files extracted from upstream source:
## tinyexr ## tinyexr
- Upstream: https://github.com/syoyo/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 - License: BSD-3-Clause
Files extracted from upstream source: Files extracted from upstream source:

View file

@ -259,7 +259,8 @@ typedef struct _DeepImage {
} DeepImage; } DeepImage;
// @deprecated { to be removed. } // @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` // Application must free image data as returned by `out_rgba`
// Result image format is: float x RGBA x width x hight // 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 // 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. } // @deprecated { to be removed. }
// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. // Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels.
// components must be 3(RGB) or 4(RGBA). // components must be 1(Grayscale), 3(RGB) or 4(RGBA).
// Result image format is: float x RGB(A) x width x hight // Input image format is: `float x width x height`, or `float x RGB(A) x width x
extern int SaveEXR(const float *data, int width, int height, int components, // 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); const char *filename);
// Initialize EXRHeader struct // Initialize EXRHeader struct
@ -401,12 +407,11 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
// For emscripten. // For emscripten.
// Loads single-frame OpenEXR image from memory. Assume EXR image contains // Loads single-frame OpenEXR image from memory. Assume EXR image contains
// RGB(A) channels. // 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 // Returns negative value and may set error string in `err` when there's an
// error // error
extern int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
size_t size, const char **err); const unsigned char *memory, size_t size,
const char **err);
#ifdef __cplusplus #ifdef __cplusplus
} }
@ -439,7 +444,8 @@ extern int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory,
#if TINYEXR_USE_MINIZ #if TINYEXR_USE_MINIZ
#else #else
#include "zlib.h" // Issue #46. Please include your own zlib-compatible API header before including `tinyexr.h`
//#include "zlib.h"
#endif #endif
#if TINYEXR_USE_ZFP #if TINYEXR_USE_ZFP
@ -478,13 +484,11 @@ namespace miniz {
#pragma clang diagnostic ignored "-Wsign-conversion" #pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wc++11-extensions" #pragma clang diagnostic ignored "-Wc++11-extensions"
#pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wconversion"
#ifdef __APPLE__ #pragma clang diagnostic ignored "-Wunused-function"
#if __clang_major__ >= 8 && __clang__minor__ > 1 #if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma" #pragma clang diagnostic ignored "-Wcomma"
#endif #endif
#endif #endif
#pragma clang diagnostic ignored "-Wunused-function"
#endif
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
reading/writing/appending, PNG writing reading/writing/appending, PNG writing
@ -1913,11 +1917,11 @@ static void def_free_func(void *opaque, void *address) {
(void)opaque, (void)address; (void)opaque, (void)address;
MZ_FREE(address); MZ_FREE(address);
} }
static void *def_realloc_func(void *opaque, void *address, size_t items, // static void *def_realloc_func(void *opaque, void *address, size_t items,
size_t size) { // size_t size) {
(void)opaque, (void)address, (void)items, (void)size; // (void)opaque, (void)address, (void)items, (void)size;
return MZ_REALLOC(address, items * size); // return MZ_REALLOC(address, items * size);
} //}
const char *mz_version(void) { return MZ_VERSION; } const char *mz_version(void) { return MZ_VERSION; }
@ -2889,7 +2893,8 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
tinfl_status status = tinfl_decompress( tinfl_status status = tinfl_decompress(
&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
(mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
&dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | &dst_buf_size,
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
MZ_FREE(pBuf); MZ_FREE(pBuf);
@ -3537,7 +3542,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) {
mz_uint saved_bit_buf, saved_bits_in; mz_uint saved_bit_buf, saved_bits_in;
mz_uint8 *pSaved_output_buf; mz_uint8 *pSaved_output_buf;
mz_bool comp_block_succeeded = MZ_FALSE; mz_bool comp_block_succeeded = MZ_FALSE;
int n, use_raw_block = int n,
use_raw_block =
((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
(d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
mz_uint8 *pOutput_buf_start = mz_uint8 *pOutput_buf_start =
@ -3569,7 +3575,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) {
if (!use_raw_block) if (!use_raw_block)
comp_block_succeeded = comp_block_succeeded =
tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || tdefl_compress_block(d,
(d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
(d->m_total_lz_bytes < 48)); (d->m_total_lz_bytes < 48));
// If the block gets expanded, forget the current contents of the output // If the block gets expanded, forget the current contents of the output
@ -5215,7 +5222,8 @@ 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_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
pStat->m_comment_size = n; pStat->m_comment_size = n;
memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 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_FILENAME_LEN_OFS) +
MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
n); n);
@ -6875,6 +6883,12 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} }
#else #else
@ -7338,11 +7352,23 @@ static void CompressZip(unsigned char *dst,
compressedSize = outSize; compressedSize = outSize;
#endif #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, static void DecompressZip(unsigned char *dst,
unsigned long *uncompressed_size /* inout */, unsigned long *uncompressed_size /* inout */,
const unsigned char *src, unsigned long src_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<unsigned char> tmpBuf(*uncompressed_size); std::vector<unsigned char> tmpBuf(*uncompressed_size);
#if TINYEXR_USE_MINIZ #if TINYEXR_USE_MINIZ
@ -7402,6 +7428,22 @@ static void DecompressZip(unsigned char *dst,
#pragma clang diagnostic ignored "-Wsign-conversion" #pragma clang diagnostic ignored "-Wsign-conversion"
#endif #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 MIN_RUN_LENGTH = 3;
const int MAX_RUN_LENGTH = 127; const int MAX_RUN_LENGTH = 127;
@ -7494,6 +7536,7 @@ static int rleUncompress(int inLength, int maxLength, const signed char in[],
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
// End of RLE code from OpenEXR ----------------------------------- // End of RLE code from OpenEXR -----------------------------------
static void CompressRle(unsigned char *dst, static void CompressRle(unsigned char *dst,
@ -7554,11 +7597,24 @@ static void CompressRle(unsigned char *dst,
assert(outSize > 0); assert(outSize > 0);
compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize); compressedSize = static_cast<tinyexr::tinyexr_uint64>(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, static void DecompressRle(unsigned char *dst,
const unsigned long uncompressed_size, const unsigned long uncompressed_size,
const unsigned char *src, unsigned long src_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<unsigned char> tmpBuf(uncompressed_size); std::vector<unsigned char> tmpBuf(uncompressed_size);
int ret = rleUncompress(static_cast<int>(src_size), int ret = rleUncompress(static_cast<int>(src_size),
@ -8874,7 +8930,12 @@ static void applyLut(const unsigned short lut[USHORT_RANGE],
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif // __clang__ #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 unsigned char *inPtr, size_t inSize,
const std::vector<ChannelInfo> &channelInfo, const std::vector<ChannelInfo> &channelInfo,
int data_width, int num_lines) { 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<int>(tmpBuffer.size()), buf); hufCompress(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), buf);
memcpy(lengthPtr, &length, sizeof(int)); memcpy(lengthPtr, &length, sizeof(int));
outSize = static_cast<unsigned int>( (*outSize) = static_cast<unsigned int>(
(reinterpret_cast<unsigned char *>(buf) - outPtr) + (reinterpret_cast<unsigned char *>(buf) - outPtr) +
static_cast<unsigned int>(length)); static_cast<unsigned int>(length));
// Use uncompressed data when compressed data is larger than uncompressed.
// (Issue 40)
if ((*outSize) >= inSize) {
(*outSize) = static_cast<unsigned int>(inSize);
memcpy(outPtr, inPtr, inSize);
}
return true; return true;
} }
static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, 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, const EXRChannelInfo *channels, int data_width,
int num_lines) { int num_lines) {
if (inLen == tmpBufSize) {
// Data is not compressed(Issue 40).
memcpy(outPtr, inPtr, inLen);
return true;
}
unsigned char bitmap[BITMAP_SIZE]; unsigned char bitmap[BITMAP_SIZE];
unsigned short minNonZero; unsigned short minNonZero;
unsigned short maxNonZero; unsigned short maxNonZero;
@ -9165,6 +9239,11 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
const ZFPCompressionParam &param) { const ZFPCompressionParam &param) {
size_t uncompressed_size = dst_width * dst_num_lines * num_channels; 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_stream *zfp = NULL;
zfp_field *field = NULL; zfp_field *field = NULL;
@ -9309,12 +9388,11 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
// Allocate original data size. // Allocate original data size.
std::vector<unsigned char> outBuf(static_cast<size_t>( std::vector<unsigned char> outBuf(static_cast<size_t>(
static_cast<size_t>(width * num_lines) * pixel_data_size)); static_cast<size_t>(width * num_lines) * pixel_data_size));
size_t tmpBufLen = static_cast<size_t>( size_t tmpBufLen = outBuf.size();
static_cast<size_t>(width * num_lines) * pixel_data_size);
bool ret = tinyexr::DecompressPiz( bool ret = tinyexr::DecompressPiz(
reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen, reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen,
static_cast<int>(num_channels), channels, width, num_lines); data_len, static_cast<int>(num_channels), channels, width, num_lines);
assert(ret); assert(ret);
(void)ret; (void)ret;
@ -10039,8 +10117,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
} else if (attr_name.compare("compression") == 0) { } else if (attr_name.compare("compression") == 0) {
bool ok = false; bool ok = false;
if ((data[0] >= TINYEXR_COMPRESSIONTYPE_NONE) && if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) {
(data[0] < TINYEXR_COMPRESSIONTYPE_PIZ)) {
ok = true; ok = true;
} }
@ -10150,9 +10227,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
// Custom attribute(up to TINYEXR_MAX_ATTRIBUTES) // Custom attribute(up to TINYEXR_MAX_ATTRIBUTES)
if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) { if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) {
EXRAttribute attrib; 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); strncpy(attrib.name, attr_name.c_str(), 255);
attrib.name[255] = '\0';
strncpy(attrib.type, attr_type.c_str(), 255); strncpy(attrib.type, attr_type.c_str(), 255);
#endif
attrib.name[255] = '\0';
attrib.type[255] = '\0'; attrib.type[255] = '\0';
attrib.size = static_cast<int>(data.size()); attrib.size = static_cast<int>(data.size());
attrib.value = static_cast<unsigned char *>(malloc(data.size())); attrib.value = static_cast<unsigned char *>(malloc(data.size()));
@ -10246,7 +10328,11 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
exr_header->channels = static_cast<EXRChannelInfo *>(malloc( exr_header->channels = static_cast<EXRChannelInfo *>(malloc(
sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels))); sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels)));
for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { for (size_t c = 0; c < static_cast<size_t>(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); strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
#endif
// manually add '\0' for safety. // manually add '\0' for safety.
exr_header->channels[c].name[255] = '\0'; exr_header->channels[c].name[255] = '\0';
@ -10309,6 +10395,8 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
&channel_offset, num_channels, &channel_offset, num_channels,
exr_header->channels); exr_header->channels);
bool invalid_data = false;
if (exr_header->tiled) { if (exr_header->tiled) {
size_t num_tiles = offsets.size(); // = # of blocks size_t num_tiles = offsets.size(); // = # of blocks
@ -10403,6 +10491,9 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
// Adjust line_no with data_window.bmin.y // Adjust line_no with data_window.bmin.y
line_no -= exr_header->data_window[1]; line_no -= exr_header->data_window[1];
if (line_no < 0) {
invalid_data = true;
} else {
tinyexr::DecodePixelData( tinyexr::DecodePixelData(
exr_image->images, exr_header->requested_pixel_types, data_ptr, exr_image->images, exr_header->requested_pixel_types, data_ptr,
static_cast<size_t>(data_len), exr_header->compression_type, static_cast<size_t>(data_len), exr_header->compression_type,
@ -10412,9 +10503,14 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
exr_header->custom_attributes, exr_header->custom_attributes,
static_cast<size_t>(exr_header->num_channels), exr_header->channels, static_cast<size_t>(exr_header->num_channels), exr_header->channels,
channel_offset_list); channel_offset_list);
}
} // omp parallel } // omp parallel
} }
if (invalid_data) {
return TINYEXR_ERROR_INVALID_DATA;
}
// Overwrite `pixel_type` with `requested_pixel_type`. // Overwrite `pixel_type` with `requested_pixel_type`.
{ {
for (int c = 0; c < exr_header->num_channels; c++) { for (int c = 0; c < exr_header->num_channels; c++) {
@ -10633,6 +10729,22 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
} }
} }
if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) {
// Alpha channel only.
(*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
const float val = reinterpret_cast<float **>(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 (idxR == -1) {
if (err) { if (err) {
(*err) = "R channel not found\n"; (*err) = "R channel not found\n";
@ -10675,6 +10787,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
(*out_rgba)[4 * i + 3] = 1.0; (*out_rgba)[4 * i + 3] = 1.0;
} }
} }
}
(*width) = exr_image.width; (*width) = exr_image.width;
(*height) = exr_image.height; (*height) = exr_image.height;
@ -10712,7 +10825,11 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
if (ret != TINYEXR_SUCCESS) { if (ret != TINYEXR_SUCCESS) {
if (err && !err_str.empty()) { if (err && !err_str.empty()) {
#ifdef _WIN32
(*err) = _strdup(err_str.c_str()); // May leak
#else
(*err) = strdup(err_str.c_str()); // May leak (*err) = strdup(err_str.c_str()); // May leak
#endif
} }
} }
@ -10724,7 +10841,8 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
return ret; return ret;
} }
int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
const unsigned char *memory, size_t size,
const char **err) { const char **err) {
if (out_rgba == NULL || memory == NULL) { if (out_rgba == NULL || memory == NULL) {
if (err) { if (err) {
@ -10749,6 +10867,13 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size,
return ret; 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); InitEXRImage(&exr_image);
ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err);
if (ret != TINYEXR_SUCCESS) { if (ret != TINYEXR_SUCCESS) {
@ -10797,19 +10922,32 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size,
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} }
// Assume `out_rgba` have enough memory allocated. (*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
for (int i = 0; i < exr_image.width * exr_image.height; i++) { for (int i = 0; i < exr_image.width * exr_image.height; i++) {
out_rgba[4 * i + 0] = reinterpret_cast<float **>(exr_image.images)[idxR][i]; (*out_rgba)[4 * i + 0] =
out_rgba[4 * i + 1] = reinterpret_cast<float **>(exr_image.images)[idxG][i]; reinterpret_cast<float **>(exr_image.images)[idxR][i];
out_rgba[4 * i + 2] = reinterpret_cast<float **>(exr_image.images)[idxB][i]; (*out_rgba)[4 * i + 1] =
if (idxA > 0) { reinterpret_cast<float **>(exr_image.images)[idxG][i];
out_rgba[4 * i + 3] = (*out_rgba)[4 * i + 2] =
reinterpret_cast<float **>(exr_image.images)[idxB][i];
if (idxA != -1) {
(*out_rgba)[4 * i + 3] =
reinterpret_cast<float **>(exr_image.images)[idxA][i]; reinterpret_cast<float **>(exr_image.images)[idxA][i];
} else { }
out_rgba[4 * i + 3] = 1.0; 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; return TINYEXR_SUCCESS;
} }
@ -11304,7 +11442,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
std::vector<unsigned char> block(bufLen); std::vector<unsigned char> block(bufLen);
unsigned int outSize = static_cast<unsigned int>(block.size()); unsigned int outSize = static_cast<unsigned int>(block.size());
CompressPiz(&block.at(0), outSize, CompressPiz(&block.at(0), &outSize,
reinterpret_cast<const unsigned char *>(&buf.at(0)), reinterpret_cast<const unsigned char *>(&buf.at(0)),
buf.size(), channels, exr_image->width, h); 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; 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"); FILE *fp = fopen(filename, "rb");
if (!fp) { if (!fp) {
if (err) { if (err) {
@ -11452,6 +11600,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
} }
return TINYEXR_ERROR_CANT_OPEN_FILE; return TINYEXR_ERROR_CANT_OPEN_FILE;
} }
#endif
size_t filesize; size_t filesize;
// Compute size // Compute size
@ -11521,6 +11670,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (0 == size) { if (0 == size) {
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} else if (marker[0] == '\0') { } else if (marker[0] == '\0') {
marker++;
size--; size--;
break; break;
} }
@ -11710,12 +11860,14 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
// decode sample data. // decode sample data.
{ {
unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize); unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
if (dstLen) {
tinyexr::DecompressZip( tinyexr::DecompressZip(
reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen, reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
data_ptr + 28 + packedOffsetTableSize, data_ptr + 28 + packedOffsetTableSize,
static_cast<unsigned long>(packedSampleDataSize)); static_cast<unsigned long>(packedSampleDataSize));
assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize)); assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
} }
}
// decode sample // decode sample
int sampleSize = -1; int sampleSize = -1;
@ -11760,7 +11912,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (channels[c].pixel_type == 0) { // UINT if (channels[c].pixel_type == 0) { // UINT
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
unsigned int ui = *reinterpret_cast<unsigned int *>( unsigned int ui = *reinterpret_cast<unsigned int *>(
&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<float>(ui); // @fixme deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme
} }
data_offset += 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<size_t>(samples_per_line); x++) { for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
tinyexr::FP16 f16; tinyexr::FP16 f16;
f16.u = *reinterpret_cast<unsigned short *>( f16.u = *reinterpret_cast<unsigned short *>(
&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); tinyexr::FP32 f32 = half_to_float(f16);
deep_image->image[c][y][x] = f32.f; 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 } else { // float
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
float f = *reinterpret_cast<float *>( float f = *reinterpret_cast<float *>(
&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; deep_image->image[c][y][x] = f;
} }
data_offset += sizeof(float) * static_cast<size_t>(samples_per_line); data_offset += sizeof(float) * static_cast<size_t>(samples_per_line);
@ -11961,7 +12113,11 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
if (ret != TINYEXR_SUCCESS) { if (ret != TINYEXR_SUCCESS) {
if (err) { if (err) {
#ifdef _WIN32
(*err) = _strdup(err_str.c_str()); // may leak
#else
(*err) = strdup(err_str.c_str()); // may leak (*err) = strdup(err_str.c_str()); // may leak
#endif
} }
return ret; return ret;
} }
@ -12287,8 +12443,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
} }
int SaveEXR(const float *data, int width, int height, int components, int SaveEXR(const float *data, int width, int height, int components,
const char *outfilename) { const int save_as_fp16, const char *outfilename) {
if (components == 3 || components == 4) { if ((components == 1) || components == 3 || components == 4) {
// OK // OK
} else { } else {
return TINYEXR_ERROR_INVALID_ARGUMENT; return TINYEXR_ERROR_INVALID_ARGUMENT;
@ -12307,6 +12463,11 @@ int SaveEXR(const float *data, int width, int height, int components,
image.num_channels = components; image.num_channels = components;
std::vector<float> images[4]; std::vector<float> images[4];
if (components == 1) {
images[0].resize(static_cast<size_t>(width * height));
memcpy(images[0].data(), data, sizeof(float) * size_t(width * height));
} else {
images[0].resize(static_cast<size_t>(width * height)); images[0].resize(static_cast<size_t>(width * height));
images[1].resize(static_cast<size_t>(width * height)); images[1].resize(static_cast<size_t>(width * height));
images[2].resize(static_cast<size_t>(width * height)); images[2].resize(static_cast<size_t>(width * height));
@ -12321,6 +12482,7 @@ int SaveEXR(const float *data, int width, int height, int components,
images[3][i] = data[static_cast<size_t>(components) * i + 3]; images[3][i] = data[static_cast<size_t>(components) * i + 3];
} }
} }
}
float *image_ptr[4] = {0, 0, 0, 0}; float *image_ptr[4] = {0, 0, 0, 0};
if (components == 4) { if (components == 4) {
@ -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[1] = &(images[2].at(0)); // B
image_ptr[2] = &(images[1].at(0)); // G image_ptr[2] = &(images[1].at(0)); // G
image_ptr[3] = &(images[0].at(0)); // R image_ptr[3] = &(images[0].at(0)); // R
} else { } else if (components == 3) {
image_ptr[0] = &(images[2].at(0)); // B image_ptr[0] = &(images[2].at(0)); // B
image_ptr[1] = &(images[1].at(0)); // G image_ptr[1] = &(images[1].at(0)); // G
image_ptr[2] = &(images[0].at(0)); // R image_ptr[2] = &(images[0].at(0)); // R
} else if (components == 1) {
image_ptr[0] = &(images[0].at(0)); // A
} }
image.images = reinterpret_cast<unsigned char **>(image_ptr); image.images = reinterpret_cast<unsigned char **>(image_ptr);
@ -12343,21 +12507,41 @@ int SaveEXR(const float *data, int width, int height, int components,
sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels))); sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels)));
// Must be (A)BGR order, since most of EXR viewers expect this channel order. // Must be (A)BGR order, since most of EXR viewers expect this channel order.
if (components == 4) { 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); strncpy(header.channels[0].name, "A", 255);
header.channels[0].name[strlen("A")] = '\0';
strncpy(header.channels[1].name, "B", 255); strncpy(header.channels[1].name, "B", 255);
header.channels[1].name[strlen("B")] = '\0';
strncpy(header.channels[2].name, "G", 255); strncpy(header.channels[2].name, "G", 255);
header.channels[2].name[strlen("G")] = '\0';
strncpy(header.channels[3].name, "R", 255); 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'; 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); strncpy(header.channels[0].name, "B", 255);
header.channels[0].name[strlen("B")] = '\0';
strncpy(header.channels[1].name, "G", 255); strncpy(header.channels[1].name, "G", 255);
header.channels[1].name[strlen("G")] = '\0';
strncpy(header.channels[2].name, "R", 255); 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'; 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<int *>( header.pixel_types = static_cast<int *>(
@ -12367,9 +12551,15 @@ int SaveEXR(const float *data, int width, int height, int components,
for (int i = 0; i < header.num_channels; i++) { for (int i = 0; i < header.num_channels; i++) {
header.pixel_types[i] = header.pixel_types[i] =
TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
if (save_as_fp16 > 0) {
header.requested_pixel_types[i] = header.requested_pixel_types[i] =
TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format
// .EXR } else {
header.requested_pixel_types[i] =
TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e.
// no precision reduction)
}
} }
const char *err; const char *err;
@ -12385,9 +12575,5 @@ int SaveEXR(const float *data, int width, int height, int components,
return ret; return ret;
} }
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // TINYEXR_IMPLEMENTATION_DEIFNED #endif // TINYEXR_IMPLEMENTATION_DEIFNED
#endif // TINYEXR_IMPLEMENTATION #endif // TINYEXR_IMPLEMENTATION