92#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
93 defined(__i386) || defined(__i486__) || defined(__i486) || \
94 defined(i386) || defined(__ia64__) || defined(__x86_64__)
95#define TINYEXR_X86_OR_X64_CPU 1
97#define TINYEXR_X86_OR_X64_CPU 0
100#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || TINYEXR_X86_OR_X64_CPU
101#define TINYEXR_LITTLE_ENDIAN 1
103#define TINYEXR_LITTLE_ENDIAN 0
108#ifndef TINYEXR_USE_MINIZ
109#define TINYEXR_USE_MINIZ (1)
113#ifndef TINYEXR_USE_STB_ZLIB
114#define TINYEXR_USE_STB_ZLIB (0)
118#ifndef TINYEXR_USE_NANOZLIB
119#define TINYEXR_USE_NANOZLIB (0)
123#ifndef TINYEXR_USE_PIZ
124#define TINYEXR_USE_PIZ (1)
127#ifndef TINYEXR_USE_ZFP
128#define TINYEXR_USE_ZFP (0)
132#ifndef TINYEXR_USE_THREAD
133#define TINYEXR_USE_THREAD (0)
137#ifndef TINYEXR_USE_OPENMP
139#define TINYEXR_USE_OPENMP (1)
141#define TINYEXR_USE_OPENMP (0)
145#define TINYEXR_SUCCESS (0)
146#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1)
147#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2)
148#define TINYEXR_ERROR_INVALID_ARGUMENT (-3)
149#define TINYEXR_ERROR_INVALID_DATA (-4)
150#define TINYEXR_ERROR_INVALID_FILE (-5)
151#define TINYEXR_ERROR_INVALID_PARAMETER (-6)
152#define TINYEXR_ERROR_CANT_OPEN_FILE (-7)
153#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8)
154#define TINYEXR_ERROR_INVALID_HEADER (-9)
155#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10)
156#define TINYEXR_ERROR_CANT_WRITE_FILE (-11)
157#define TINYEXR_ERROR_SERIALIZATION_FAILED (-12)
158#define TINYEXR_ERROR_LAYER_NOT_FOUND (-13)
159#define TINYEXR_ERROR_DATA_TOO_LARGE (-14)
164#define TINYEXR_PIXELTYPE_UINT (0)
165#define TINYEXR_PIXELTYPE_HALF (1)
166#define TINYEXR_PIXELTYPE_FLOAT (2)
168#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
169#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
171#define TINYEXR_COMPRESSIONTYPE_NONE (0)
172#define TINYEXR_COMPRESSIONTYPE_RLE (1)
173#define TINYEXR_COMPRESSIONTYPE_ZIPS (2)
174#define TINYEXR_COMPRESSIONTYPE_ZIP (3)
175#define TINYEXR_COMPRESSIONTYPE_PIZ (4)
176#define TINYEXR_COMPRESSIONTYPE_ZFP (128)
178#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0)
179#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1)
180#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2)
182#define TINYEXR_TILE_ONE_LEVEL (0)
183#define TINYEXR_TILE_MIPMAP_LEVELS (1)
184#define TINYEXR_TILE_RIPMAP_LEVELS (2)
186#define TINYEXR_TILE_ROUND_DOWN (0)
187#define TINYEXR_TILE_ROUND_UP (1)
333extern int LoadEXR(
float **out_rgba,
int *width,
int *height,
334 const char *
filename,
const char **err);
343 const char *
filename,
const char *layer_name,
358 int *num_layers,
const char **err);
388 const int components,
const int save_as_fp16,
389 unsigned char **buffer,
const char **err);
403extern int SaveEXR(
const float *data,
const int width,
const int height,
404 const int components,
const int save_as_fp16,
405 const char *
filename,
const char **err);
433 const unsigned char *memory,
size_t size);
439 const char *
filename,
const char **err);
446 const unsigned char *memory,
size_t size,
466 const unsigned char *memory,
467 size_t size,
const char **err);
477 const char *
filename,
const char **err);
488 const unsigned char *memory,
489 const size_t size,
const char **err);
501 unsigned int num_parts,
515 unsigned int num_parts,
516 const unsigned char *memory,
517 const size_t size,
const char **err);
537 unsigned char **memory,
const char **err);
548 unsigned int num_parts,
549 const char *
filename,
const char **err);
561 unsigned int num_parts,
562 unsigned char **memory,
const char **err);
594 const unsigned char *memory,
size_t size,
603#ifdef TINYEXR_IMPLEMENTATION
604#ifndef TINYEXR_IMPLEMENTATION_DEFINED
605#define TINYEXR_IMPLEMENTATION_DEFINED
609#ifndef WIN32_LEAN_AND_MEAN
610#define WIN32_LEAN_AND_MEAN
617#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
618#define TINYEXR_USE_WIN32_MMAP (1)
621#elif defined(__linux__) || defined(__unix__)
626#define TINYEXR_USE_POSIX_MMAP (1)
643#if __cplusplus > 199711L || (defined(_MSC_VER) && _MSC_VER >= 1900)
644#define TINYEXR_HAS_CXX11 (1)
648#if TINYEXR_USE_THREAD
654#define TINYEXR_HAS_CXX11 (0)
657#if TINYEXR_USE_OPENMP
661#if defined(TINYEXR_USE_MINIZ) && (TINYEXR_USE_MINIZ==1)
669#if defined(TINYEXR_USE_NANOZLIB) && (TINYEXR_USE_NANOZLIB==1)
670#define NANOZLIB_IMPLEMENTATION
674#if TINYEXR_USE_STB_ZLIB
679extern "C" int stbi_zlib_decode_buffer(
char *obuffer,
int olen,
const char *ibuffer,
int ilen);
681extern "C" unsigned char *stbi_zlib_compress(
unsigned char *data,
int data_len,
int *out_len,
int quality);
688#pragma clang diagnostic push
689#pragma clang diagnostic ignored "-Weverything"
695#pragma clang diagnostic pop
703#define TINYEXR_CHECK_AND_RETURN_MSG(cond, msg, err) do { \
706 std::ostringstream ss_e; \
707 ss_e << __func__ << "():" << __LINE__ << msg << "\n"; \
708 (*err) += ss_e.str(); \
715#define TINYEXR_CHECK_AND_RETURN_C(cond, retcode) do { \
723#if __cplusplus > 199711L
725typedef uint64_t tinyexr_uint64;
726typedef int64_t tinyexr_int64;
731#pragma clang diagnostic push
732#pragma clang diagnostic ignored "-Wc++11-long-long"
734typedef unsigned long long tinyexr_uint64;
735typedef long long tinyexr_int64;
737#pragma clang diagnostic pop
750static void SetErrorMessage(
const std::string &msg,
const char **err) {
753 (*err) = _strdup(msg.c_str());
755 (*err) = strdup(msg.c_str());
761static void SetWarningMessage(
const std::string &msg,
const char **warn) {
764 (*warn) = _strdup(msg.c_str());
766 (*warn) = strdup(msg.c_str());
772static const unsigned int kEXRVersionSize = 8;
774static void cpy2(
unsigned short *dst_val,
const unsigned short *src_val) {
775 unsigned char *dst =
reinterpret_cast<unsigned char *
>(dst_val);
776 const unsigned char *src =
reinterpret_cast<const unsigned char *
>(src_val);
782static void swap2(
unsigned short *val) {
783#if TINYEXR_LITTLE_ENDIAN
786 unsigned short tmp = *val;
787 unsigned char *dst =
reinterpret_cast<unsigned char *
>(val);
788 unsigned char *src =
reinterpret_cast<unsigned char *
>(&tmp);
796#pragma clang diagnostic push
797#pragma clang diagnostic ignored "-Wunused-function"
801#pragma GCC diagnostic push
802#pragma GCC diagnostic ignored "-Wunused-function"
804static void cpy4(
int *dst_val,
const int *src_val) {
805 unsigned char *dst =
reinterpret_cast<unsigned char *
>(dst_val);
806 const unsigned char *src =
reinterpret_cast<const unsigned char *
>(src_val);
814static void cpy4(
unsigned int *dst_val,
const unsigned int *src_val) {
815 unsigned char *dst =
reinterpret_cast<unsigned char *
>(dst_val);
816 const unsigned char *src =
reinterpret_cast<const unsigned char *
>(src_val);
824static void cpy4(
float *dst_val,
const float *src_val) {
825 unsigned char *dst =
reinterpret_cast<unsigned char *
>(dst_val);
826 const unsigned char *src =
reinterpret_cast<const unsigned char *
>(src_val);
834#pragma clang diagnostic pop
838#pragma GCC diagnostic pop
841static void swap4(
unsigned int *val) {
842#if TINYEXR_LITTLE_ENDIAN
845 unsigned int tmp = *val;
846 unsigned char *dst =
reinterpret_cast<unsigned char *
>(val);
847 unsigned char *src =
reinterpret_cast<unsigned char *
>(&tmp);
856static void swap4(
int *val) {
857#if TINYEXR_LITTLE_ENDIAN
861 unsigned char *dst =
reinterpret_cast<unsigned char *
>(val);
862 unsigned char *src =
reinterpret_cast<unsigned char *
>(&tmp);
871static void swap4(
float *val) {
872#if TINYEXR_LITTLE_ENDIAN
876 unsigned char *dst =
reinterpret_cast<unsigned char *
>(val);
877 unsigned char *src =
reinterpret_cast<unsigned char *
>(&tmp);
887static void cpy8(tinyexr::tinyexr_uint64 *dst_val,
const tinyexr::tinyexr_uint64 *src_val) {
888 unsigned char *dst =
reinterpret_cast<unsigned char *
>(dst_val);
889 const unsigned char *src =
reinterpret_cast<const unsigned char *
>(src_val);
902static void swap8(tinyexr::tinyexr_uint64 *val) {
903#if TINYEXR_LITTLE_ENDIAN
906 tinyexr::tinyexr_uint64 tmp = (*val);
907 unsigned char *dst =
reinterpret_cast<unsigned char *
>(val);
908 unsigned char *src =
reinterpret_cast<unsigned char *
>(&tmp);
926#if TINYEXR_LITTLE_ENDIAN
927 unsigned int Mantissa : 23;
928 unsigned int Exponent : 8;
929 unsigned int Sign : 1;
931 unsigned int Sign : 1;
932 unsigned int Exponent : 8;
933 unsigned int Mantissa : 23;
939#pragma clang diagnostic push
940#pragma clang diagnostic ignored "-Wpadded"
946#if TINYEXR_LITTLE_ENDIAN
947 unsigned int Mantissa : 10;
948 unsigned int Exponent : 5;
949 unsigned int Sign : 1;
951 unsigned int Sign : 1;
952 unsigned int Exponent : 5;
953 unsigned int Mantissa : 10;
959#pragma clang diagnostic pop
962static FP32 half_to_float(FP16 h) {
963 static const FP32 magic = {113 << 23};
964 static const unsigned int shifted_exp = 0x7c00
968 o.u = (h.u & 0x7fffU) << 13U;
969 unsigned int exp_ = shifted_exp & o.u;
970 o.u += (127 - 15) << 23;
973 if (exp_ == shifted_exp)
974 o.u += (128 - 16) << 23;
981 o.u |= (h.u & 0x8000U) << 16U;
985static FP16 float_to_half_full(FP32 f) {
989 if (f.s.Exponent == 0)
991 else if (f.s.Exponent == 255)
994 o.s.Mantissa = f.s.Mantissa ? 0x200 : 0;
998 int newexp = f.s.Exponent - 127 + 15;
1001 else if (newexp <= 0)
1003 if ((14 - newexp) <= 24)
1005 unsigned int mant = f.s.Mantissa | 0x800000;
1006 o.s.Mantissa = mant >> (14 - newexp);
1007 if ((mant >> (13 - newexp)) & 1)
1011 o.s.Exponent =
static_cast<unsigned int>(newexp);
1012 o.s.Mantissa = f.s.Mantissa >> 13;
1013 if (f.s.Mantissa & 0x1000)
1018 o.s.Sign = f.s.Sign;
1037#pragma clang diagnostic push
1039#if __has_warning("-Wzero-as-null-pointer-constant")
1040#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
1045static const char *ReadString(std::string *s,
const char *ptr,
size_t len) {
1047 const char *p = ptr;
1048 const char *q = ptr;
1049 while ((
size_t(q - ptr) < len) && (*q) != 0) {
1053 if (
size_t(q - ptr) >= len) {
1058 (*s) = std::string(p, q);
1063static bool ReadAttribute(std::string *name, std::string *type,
1064 std::vector<unsigned char> *data,
size_t *marker_size,
1065 const char *marker,
size_t size) {
1066 size_t name_len = strnlen(marker,
size);
1067 if (name_len ==
size) {
1071 *name = std::string(marker, name_len);
1073 marker += name_len + 1;
1074 size -= name_len + 1;
1076 size_t type_len = strnlen(marker,
size);
1077 if (type_len ==
size) {
1080 *type = std::string(marker, type_len);
1082 marker += type_len + 1;
1083 size -= type_len + 1;
1085 if (
size <
sizeof(uint32_t)) {
1090 memcpy(&data_len, marker,
sizeof(uint32_t));
1091 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&data_len));
1093 if (data_len == 0) {
1094 if ((*type).compare(
"string") == 0) {
1097 marker +=
sizeof(uint32_t);
1098 size -=
sizeof(uint32_t);
1100 *marker_size = name_len + 1 + type_len + 1 +
sizeof(uint32_t);
1111 marker +=
sizeof(uint32_t);
1112 size -=
sizeof(uint32_t);
1114 if (
size < data_len) {
1118 data->resize(
static_cast<size_t>(data_len));
1119 memcpy(&data->at(0), marker,
static_cast<size_t>(data_len));
1121 *marker_size = name_len + 1 + type_len + 1 +
sizeof(uint32_t) + data_len;
1125static void WriteAttributeToMemory(std::vector<unsigned char> *out,
1126 const char *name,
const char *type,
1127 const unsigned char *data,
int len) {
1128 out->insert(out->end(), name, name + strlen(name) + 1);
1129 out->insert(out->end(), type, type + strlen(type) + 1);
1132 tinyexr::swap4(&outLen);
1133 out->insert(out->end(),
reinterpret_cast<unsigned char *
>(&outLen),
1134 reinterpret_cast<unsigned char *
>(&outLen) +
sizeof(
int));
1135 out->insert(out->end(), data, data + len);
1138typedef struct TChannelInfo {
1141 int requested_pixel_type;
1144 unsigned char p_linear;
1145 unsigned char pad[3];
1156 std::vector<tinyexr::ChannelInfo> channels;
1157 std::vector<EXRAttribute> attributes;
1159 Box2iInfo data_window;
1161 Box2iInfo display_window;
1162 float screen_window_center[2];
1163 float screen_window_width;
1164 float pixel_aspect_ratio;
1172 int tile_level_mode;
1173 int tile_rounding_mode;
1175 unsigned int header_len;
1177 int compression_type;
1188 data_window.min_x = 0;
1189 data_window.min_y = 0;
1190 data_window.max_x = 0;
1191 data_window.max_y = 0;
1193 display_window.min_x = 0;
1194 display_window.min_y = 0;
1195 display_window.max_x = 0;
1196 display_window.max_y = 0;
1197 screen_window_center[0] = 0.0f;
1198 screen_window_center[1] = 0.0f;
1199 screen_window_width = 0.0f;
1200 pixel_aspect_ratio = 0.0f;
1208 tile_level_mode = 0;
1209 tile_rounding_mode = 0;
1212 compression_type = 0;
1219static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
1220 const std::vector<unsigned char> &data) {
1221 const char *p =
reinterpret_cast<const char *
>(&data.at(0));
1228 info.requested_pixel_type = 0;
1230 tinyexr_int64 data_len =
static_cast<tinyexr_int64
>(data.size()) -
1231 (p -
reinterpret_cast<const char *
>(data.data()));
1236 p = ReadString(&info.name, p,
size_t(data_len));
1237 if ((p == NULL) && (info.name.empty())) {
1242 const unsigned char *data_end =
1243 reinterpret_cast<const unsigned char *
>(p) + 16;
1244 if (data_end >= (data.data() + data.size())) {
1248 memcpy(&info.pixel_type, p,
sizeof(
int));
1250 info.p_linear =
static_cast<unsigned char>(p[0]);
1252 memcpy(&info.x_sampling, p,
sizeof(
int));
1254 memcpy(&info.y_sampling, p,
sizeof(
int));
1257 tinyexr::swap4(&info.pixel_type);
1258 tinyexr::swap4(&info.x_sampling);
1259 tinyexr::swap4(&info.y_sampling);
1261 channels.push_back(info);
1267static void WriteChannelInfo(std::vector<unsigned char> &data,
1268 const std::vector<ChannelInfo> &channels) {
1272 for (
size_t c = 0; c < channels.size(); c++) {
1273 sz += channels[c].name.length() + 1;
1276 data.resize(sz + 1);
1278 unsigned char *p = &data.at(0);
1280 for (
size_t c = 0; c < channels.size(); c++) {
1281 memcpy(p, channels[c].name.c_str(), channels[c].name.length());
1282 p += channels[c].name.length();
1286 int pixel_type = channels[c].requested_pixel_type;
1287 int x_sampling = channels[c].x_sampling;
1288 int y_sampling = channels[c].y_sampling;
1289 tinyexr::swap4(&pixel_type);
1290 tinyexr::swap4(&x_sampling);
1291 tinyexr::swap4(&y_sampling);
1293 memcpy(p, &pixel_type,
sizeof(
int));
1296 (*p) = channels[c].p_linear;
1299 memcpy(p, &x_sampling,
sizeof(
int));
1302 memcpy(p, &y_sampling,
sizeof(
int));
1309static bool CompressZip(
unsigned char *dst,
1310 tinyexr::tinyexr_uint64 &compressedSize,
1311 const unsigned char *src,
unsigned long src_size) {
1312 std::vector<unsigned char> tmpBuf(src_size);
1323 const char *srcPtr =
reinterpret_cast<const char *
>(src);
1326 char *t1 =
reinterpret_cast<char *
>(&tmpBuf.at(0));
1327 char *t2 =
reinterpret_cast<char *
>(&tmpBuf.at(0)) + (src_size + 1) / 2;
1328 const char *stop = srcPtr + src_size;
1332 *(t1++) = *(srcPtr++);
1337 *(t2++) = *(srcPtr++);
1348 unsigned char *t = &tmpBuf.at(0) + 1;
1349 unsigned char *stop = &tmpBuf.at(0) + src_size;
1353 int d =
int(t[0]) - p + (128 + 256);
1355 t[0] =
static_cast<unsigned char>(d);
1360#if defined(TINYEXR_USE_MINIZ) && (TINYEXR_USE_MINIZ==1)
1367 dst, &outSize,
static_cast<const unsigned char *
>(&tmpBuf.at(0)),
1373 compressedSize = outSize;
1374#elif defined(TINYEXR_USE_STB_ZLIB) && (TINYEXR_USE_STB_ZLIB==1)
1376 unsigned char* ret = stbi_zlib_compress(
const_cast<unsigned char*
>(&tmpBuf.at(0)), src_size, &outSize, 8);
1380 memcpy(dst, ret, outSize);
1383 compressedSize = outSize;
1384#elif defined(TINYEXR_USE_NANOZLIB) && (TINYEXR_USE_NANOZLIB==1)
1385 uint64_t dstSize = nanoz_compressBound(
static_cast<uint64_t
>(src_size));
1387 unsigned char *ret = nanoz_compress(&tmpBuf.at(0), src_size, &outSize, 8);
1392 memcpy(dst, ret, outSize);
1395 compressedSize = outSize;
1398 int ret =
compress(dst, &outSize,
static_cast<const Bytef *
>(&tmpBuf.at(0)),
1404 compressedSize = outSize;
1409 if (compressedSize >= src_size) {
1410 compressedSize = src_size;
1411 memcpy(dst, src, src_size);
1417static bool DecompressZip(
unsigned char *dst,
1418 unsigned long *uncompressed_size ,
1419 const unsigned char *src,
unsigned long src_size) {
1420 if ((*uncompressed_size) == src_size) {
1422 memcpy(dst, src, src_size);
1425 std::vector<unsigned char> tmpBuf(*uncompressed_size);
1427#if defined(TINYEXR_USE_MINIZ) && (TINYEXR_USE_MINIZ==1)
1429 mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
1433#elif TINYEXR_USE_STB_ZLIB
1434 int ret = stbi_zlib_decode_buffer(
reinterpret_cast<char*
>(&tmpBuf.at(0)),
1435 *uncompressed_size,
reinterpret_cast<const char*
>(src), src_size);
1439#elif defined(TINYEXR_USE_NANOZLIB) && (TINYEXR_USE_NANOZLIB==1)
1440 uint64_t dest_size = (*uncompressed_size);
1441 uint64_t uncomp_size{0};
1442 nanoz_status_t ret =
1443 nanoz_uncompress(src, src_size, dest_size, &tmpBuf.at(0), &uncomp_size);
1444 if (NANOZ_SUCCESS != ret) {
1447 if ((*uncompressed_size) != uncomp_size) {
1451 int ret =
uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
1464 unsigned char *t = &tmpBuf.at(0) + 1;
1465 unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size);
1468 int d =
int(t[-1]) +
int(t[0]) - 128;
1469 t[0] =
static_cast<unsigned char>(d);
1476 const char *t1 =
reinterpret_cast<const char *
>(&tmpBuf.at(0));
1477 const char *t2 =
reinterpret_cast<const char *
>(&tmpBuf.at(0)) +
1478 (*uncompressed_size + 1) / 2;
1479 char *s =
reinterpret_cast<char *
>(dst);
1480 char *stop = s + (*uncompressed_size);
1501#pragma clang diagnostic push
1502#pragma clang diagnostic ignored "-Wsign-conversion"
1503#if __has_warning("-Wextra-semi-stmt")
1504#pragma clang diagnostic ignored "-Wextra-semi-stmt"
1509#pragma warning(push)
1510#pragma warning(disable : 4204)
1513#pragma warning(disable : 4244)
1515#pragma warning(disable : 4267)
1517#pragma warning(disable : 4996)
1522const int MIN_RUN_LENGTH = 3;
1523const int MAX_RUN_LENGTH = 127;
1530static int rleCompress(
int inLength,
const char in[],
signed char out[]) {
1531 const char *inEnd = in + inLength;
1532 const char *runStart = in;
1533 const char *runEnd = in + 1;
1534 signed char *outWrite = out;
1536 while (runStart < inEnd) {
1537 while (runEnd < inEnd && *runStart == *runEnd &&
1538 runEnd - runStart - 1 < MAX_RUN_LENGTH) {
1542 if (runEnd - runStart >= MIN_RUN_LENGTH) {
1547 *outWrite++ =
static_cast<char>(runEnd - runStart) - 1;
1548 *outWrite++ = *(
reinterpret_cast<const signed char *
>(runStart));
1555 while (runEnd < inEnd &&
1556 ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) ||
1557 (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) &&
1558 runEnd - runStart < MAX_RUN_LENGTH) {
1562 *outWrite++ =
static_cast<char>(runStart - runEnd);
1564 while (runStart < runEnd) {
1565 *outWrite++ = *(
reinterpret_cast<const signed char *
>(runStart++));
1572 return static_cast<int>(outWrite - out);
1581static int rleUncompress(
int inLength,
int maxLength,
const signed char in[],
1583 char *outStart = out;
1585 while (inLength > 0) {
1587 int count = -(
static_cast<int>(*in++));
1588 inLength -=
count + 1;
1591 if ((0 > (maxLength -=
count)) || (inLength < 0))
return 0;
1593 memcpy(out, in,
count);
1600 if ((0 > (maxLength -=
count + 1)) || (inLength < 0))
return 0;
1602 memset(out, *
reinterpret_cast<const char *
>(in),
count + 1);
1609 return static_cast<int>(out - outStart);
1613#pragma clang diagnostic pop
1618static bool CompressRle(
unsigned char *dst,
1619 tinyexr::tinyexr_uint64 &compressedSize,
1620 const unsigned char *src,
unsigned long src_size) {
1621 std::vector<unsigned char> tmpBuf(src_size);
1632 const char *srcPtr =
reinterpret_cast<const char *
>(src);
1635 char *t1 =
reinterpret_cast<char *
>(&tmpBuf.at(0));
1636 char *t2 =
reinterpret_cast<char *
>(&tmpBuf.at(0)) + (src_size + 1) / 2;
1637 const char *stop = srcPtr + src_size;
1641 *(t1++) = *(srcPtr++);
1646 *(t2++) = *(srcPtr++);
1657 unsigned char *t = &tmpBuf.at(0) + 1;
1658 unsigned char *stop = &tmpBuf.at(0) + src_size;
1662 int d =
int(t[0]) - p + (128 + 256);
1664 t[0] =
static_cast<unsigned char>(d);
1670 int outSize = rleCompress(
static_cast<int>(src_size),
1671 reinterpret_cast<const char *
>(&tmpBuf.at(0)),
1672 reinterpret_cast<signed char *
>(dst));
1673 TINYEXR_CHECK_AND_RETURN_C(outSize > 0,
false);
1675 compressedSize =
static_cast<tinyexr::tinyexr_uint64
>(outSize);
1679 if (compressedSize >= src_size) {
1680 compressedSize = src_size;
1681 memcpy(dst, src, src_size);
1687static bool DecompressRle(
unsigned char *dst,
1688 const unsigned long uncompressed_size,
1689 const unsigned char *src,
unsigned long src_size) {
1690 if (uncompressed_size == src_size) {
1692 memcpy(dst, src, src_size);
1698 if (src_size <= 2) {
1702 std::vector<unsigned char> tmpBuf(uncompressed_size);
1704 int ret = rleUncompress(
static_cast<int>(src_size),
1705 static_cast<int>(uncompressed_size),
1706 reinterpret_cast<const signed char *
>(src),
1707 reinterpret_cast<char *
>(&tmpBuf.at(0)));
1708 if (ret !=
static_cast<int>(uncompressed_size)) {
1719 unsigned char *t = &tmpBuf.at(0) + 1;
1720 unsigned char *stop = &tmpBuf.at(0) + uncompressed_size;
1723 int d =
int(t[-1]) +
int(t[0]) - 128;
1724 t[0] =
static_cast<unsigned char>(d);
1731 const char *t1 =
reinterpret_cast<const char *
>(&tmpBuf.at(0));
1732 const char *t2 =
reinterpret_cast<const char *
>(&tmpBuf.at(0)) +
1733 (uncompressed_size + 1) / 2;
1734 char *s =
reinterpret_cast<char *
>(dst);
1735 char *stop = s + uncompressed_size;
1756#pragma clang diagnostic push
1757#pragma clang diagnostic ignored "-Wc++11-long-long"
1758#pragma clang diagnostic ignored "-Wold-style-cast"
1759#pragma clang diagnostic ignored "-Wpadded"
1760#pragma clang diagnostic ignored "-Wsign-conversion"
1761#pragma clang diagnostic ignored "-Wc++11-extensions"
1762#pragma clang diagnostic ignored "-Wconversion"
1763#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
1765#if __has_warning("-Wcast-qual")
1766#pragma clang diagnostic ignored "-Wcast-qual"
1769#if __has_warning("-Wextra-semi-stmt")
1770#pragma clang diagnostic ignored "-Wextra-semi-stmt"
1784struct PIZChannelData {
1785 unsigned short *start;
1786 unsigned short *end;
1810inline void wenc14(
unsigned short a,
unsigned short b,
unsigned short &l,
1811 unsigned short &h) {
1812 short as =
static_cast<short>(a);
1813 short bs =
static_cast<short>(b);
1815 short ms = (as + bs) >> 1;
1818 l =
static_cast<unsigned short>(ms);
1819 h =
static_cast<unsigned short>(ds);
1822inline void wdec14(
unsigned short l,
unsigned short h,
unsigned short &a,
1823 unsigned short &b) {
1824 short ls =
static_cast<short>(l);
1825 short hs =
static_cast<short>(h);
1828 int ai = ls + (hi & 1) + (hi >> 1);
1830 short as =
static_cast<short>(ai);
1831 short bs =
static_cast<short>(ai - hi);
1833 a =
static_cast<unsigned short>(as);
1834 b =
static_cast<unsigned short>(bs);
1843const int NBITS = 16;
1844const int A_OFFSET = 1 << (NBITS - 1);
1845const int M_OFFSET = 1 << (NBITS - 1);
1846const int MOD_MASK = (1 << NBITS) - 1;
1848inline void wenc16(
unsigned short a,
unsigned short b,
unsigned short &l,
1849 unsigned short &h) {
1850 int ao = (a + A_OFFSET) & MOD_MASK;
1851 int m = ((ao + b) >> 1);
1854 if (d < 0) m = (m + M_OFFSET) & MOD_MASK;
1858 l =
static_cast<unsigned short>(m);
1859 h =
static_cast<unsigned short>(d);
1862inline void wdec16(
unsigned short l,
unsigned short h,
unsigned short &a,
1863 unsigned short &b) {
1866 int bb = (m - (d >> 1)) & MOD_MASK;
1867 int aa = (d + bb - A_OFFSET) & MOD_MASK;
1868 b =
static_cast<unsigned short>(bb);
1869 a =
static_cast<unsigned short>(aa);
1876static void wav2Encode(
1884 bool w14 = (mx < (1 << 14));
1885 int n = (nx > ny) ? ny : nx;
1894 unsigned short *py = in;
1895 unsigned short *ey = in + oy * (ny - p2);
1900 unsigned short i00, i01, i10, i11;
1906 for (; py <= ey; py += oy2) {
1907 unsigned short *px = py;
1908 unsigned short *ex = py + ox * (nx - p2);
1914 for (; px <= ex; px += ox2) {
1915 unsigned short *p01 = px + ox1;
1916 unsigned short *p10 = px + oy1;
1917 unsigned short *p11 = p10 + ox1;
1924 wenc14(*px, *p01, i00, i01);
1925 wenc14(*p10, *p11, i10, i11);
1926 wenc14(i00, i10, *px, *p10);
1927 wenc14(i01, i11, *p01, *p11);
1929 wenc16(*px, *p01, i00, i01);
1930 wenc16(*p10, *p11, i10, i11);
1931 wenc16(i00, i10, *px, *p10);
1932 wenc16(i01, i11, *p01, *p11);
1941 unsigned short *p10 = px + oy1;
1944 wenc14(*px, *p10, i00, *p10);
1946 wenc16(*px, *p10, i00, *p10);
1957 unsigned short *px = py;
1958 unsigned short *ex = py + ox * (nx - p2);
1960 for (; px <= ex; px += ox2) {
1961 unsigned short *p01 = px + ox1;
1964 wenc14(*px, *p01, i00, *p01);
1966 wenc16(*px, *p01, i00, *p01);
1985static void wav2Decode(
1993 bool w14 = (mx < (1 << 14));
1994 int n = (nx > ny) ? ny : nx;
2002 while (p <= n) p <<= 1;
2013 unsigned short *py = in;
2014 unsigned short *ey = in + oy * (ny - p2);
2019 unsigned short i00, i01, i10, i11;
2025 for (; py <= ey; py += oy2) {
2026 unsigned short *px = py;
2027 unsigned short *ex = py + ox * (nx - p2);
2033 for (; px <= ex; px += ox2) {
2034 unsigned short *p01 = px + ox1;
2035 unsigned short *p10 = px + oy1;
2036 unsigned short *p11 = p10 + ox1;
2043 wdec14(*px, *p10, i00, i10);
2044 wdec14(*p01, *p11, i01, i11);
2045 wdec14(i00, i01, *px, *p01);
2046 wdec14(i10, i11, *p10, *p11);
2048 wdec16(*px, *p10, i00, i10);
2049 wdec16(*p01, *p11, i01, i11);
2050 wdec16(i00, i01, *px, *p01);
2051 wdec16(i10, i11, *p10, *p11);
2060 unsigned short *p10 = px + oy1;
2063 wdec14(*px, *p10, i00, *p10);
2065 wdec16(*px, *p10, i00, *p10);
2076 unsigned short *px = py;
2077 unsigned short *ex = py + ox * (nx - p2);
2079 for (; px <= ex; px += ox2) {
2080 unsigned short *p01 = px + ox1;
2083 wdec14(*px, *p01, i00, *p01);
2085 wdec16(*px, *p01, i00, *p01);
2112const int HUF_ENCBITS = 16;
2113const int HUF_DECBITS = 14;
2115const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1;
2116const int HUF_DECSIZE = 1 << HUF_DECBITS;
2117const int HUF_DECMASK = HUF_DECSIZE - 1;
2121 unsigned int len : 8;
2122 unsigned int lit : 24;
2126inline long long hufLength(
long long code) {
return code & 63; }
2128inline long long hufCode(
long long code) {
return code >> 6; }
2130inline void outputBits(
int nBits,
long long bits,
long long &c,
int &lc,
2137 while (lc >= 8) *out++ =
static_cast<char>((c >> (lc -= 8)));
2140inline long long getBits(
int nBits,
long long &c,
int &lc,
const char *&in) {
2141 while (lc < nBits) {
2142 c = (c << 8) | *(reinterpret_cast<const unsigned char *>(in++));
2147 return (c >> lc) & ((1 << nBits) - 1);
2170static void hufCanonicalCodeTable(
long long hcode[HUF_ENCSIZE]) {
2179 for (
int i = 0; i <= 58; ++i) n[i] = 0;
2181 for (
int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1;
2191 for (
int i = 58; i > 0; --i) {
2192 long long nc = ((c + n[i]) >> 1);
2204 for (
int i = 0; i < HUF_ENCSIZE; ++i) {
2205 int l =
static_cast<int>(hcode[i]);
2207 if (l > 0) hcode[i] = l | (n[l]++ << 6);
2220struct FHeapCompare {
2221 bool operator()(
long long *a,
long long *b) {
return *a > *b; }
2224static bool hufBuildEncTable(
2250 std::vector<int> hlink(HUF_ENCSIZE);
2251 std::vector<long long *> fHeap(HUF_ENCSIZE);
2255 while (!frq[*im]) (*im)++;
2259 for (
int i = *im; i < HUF_ENCSIZE; i++) {
2263 fHeap[nf] = &frq[i];
2277 fHeap[nf] = &frq[*iM];
2308 std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
2310 std::vector<long long> scode(HUF_ENCSIZE);
2311 memset(scode.data(), 0,
sizeof(
long long) * HUF_ENCSIZE);
2320 int mm = fHeap[0] - frq;
2321 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
2324 int m = fHeap[0] - frq;
2325 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
2328 std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
2349 for (
int j = m;; j = hlink[j]) {
2352 TINYEXR_CHECK_AND_RETURN_C(scode[j] <= 58,
false);
2354 if (hlink[j] == j) {
2368 for (
int j = mm;; j = hlink[j]) {
2371 TINYEXR_CHECK_AND_RETURN_C(scode[j] <= 58,
false);
2373 if (hlink[j] == j)
break;
2383 hufCanonicalCodeTable(scode.data());
2384 memcpy(frq, scode.data(),
sizeof(
long long) * HUF_ENCSIZE);
2404const int SHORT_ZEROCODE_RUN = 59;
2405const int LONG_ZEROCODE_RUN = 63;
2406const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
2407const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
2409static void hufPackEncTable(
2410 const long long *hcode,
2419 for (; im <= iM; im++) {
2420 int l = hufLength(hcode[im]);
2425 while ((im < iM) && (zerun < LONGEST_LONG_RUN)) {
2426 if (hufLength(hcode[im + 1]) > 0)
break;
2432 if (zerun >= SHORTEST_LONG_RUN) {
2433 outputBits(6, LONG_ZEROCODE_RUN, c, lc, p);
2434 outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p);
2436 outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
2442 outputBits(6, l, c, lc, p);
2445 if (lc > 0) *p++ = (
unsigned char)(c << (8 - lc));
2454static bool hufUnpackEncTable(
2461 memset(hcode, 0,
sizeof(
long long) * HUF_ENCSIZE);
2463 const char *p = *pcode;
2467 for (; im <= iM; im++) {
2468 if (p - *pcode >= ni) {
2472 long long l = hcode[im] = getBits(6, c, lc, p);
2474 if (l == (
long long)LONG_ZEROCODE_RUN) {
2475 if (p - *pcode > ni) {
2479 int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN;
2481 if (im + zerun > iM + 1) {
2485 while (zerun--) hcode[im++] = 0;
2488 }
else if (l >= (
long long)SHORT_ZEROCODE_RUN) {
2489 int zerun = l - SHORT_ZEROCODE_RUN + 2;
2491 if (im + zerun > iM + 1) {
2495 while (zerun--) hcode[im++] = 0;
2501 *pcode =
const_cast<char *
>(p);
2503 hufCanonicalCodeTable(hcode);
2516static void hufClearDecTable(HufDec *hdecod)
2519 for (
int i = 0; i < HUF_DECSIZE; i++) {
2535static bool hufBuildDecTable(
const long long *hcode,
2546 for (; im <= iM; im++) {
2547 long long c = hufCode(hcode[im]);
2548 int l = hufLength(hcode[im]);
2561 if (l > HUF_DECBITS) {
2566 HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
2581 unsigned int *p = pl->p;
2582 pl->p =
new unsigned int[pl->lit];
2584 for (
unsigned int i = 0; i < pl->lit - 1u; ++i) pl->p[i] = p[i];
2588 pl->p =
new unsigned int[1];
2591 pl->p[pl->lit - 1] = im;
2597 HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
2599 for (
long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) {
2600 if (pl->len || pl->p) {
2623static void hufFreeDecTable(HufDec *hdecod)
2625 for (
int i = 0; i < HUF_DECSIZE; i++) {
2627 delete[] hdecod[i].p;
2637inline void outputCode(
long long code,
long long &c,
int &lc,
char *&out) {
2638 outputBits(hufLength(code), hufCode(code), c, lc, out);
2641inline void sendCode(
long long sCode,
int runCount,
long long runCode,
2642 long long &c,
int &lc,
char *&out) {
2650 if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) {
2651 outputCode(sCode, c, lc, out);
2652 outputCode(runCode, c, lc, out);
2653 outputBits(8, runCount, c, lc, out);
2655 while (runCount-- >= 0) outputCode(sCode, c, lc, out);
2664 (
const long long *hcode,
2665 const unsigned short *in,
2670 char *outStart = out;
2680 for (
int i = 1; i < ni; i++) {
2685 if (s == in[i] && cs < 255) {
2688 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
2699 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
2701 if (lc) *out = (c << (8 - lc)) & 0xff;
2703 return (out - outStart) * 8 + lc;
2716#define getChar(c, lc, in) \
2718 c = (c << 8) | *(unsigned char *)(in++); \
2723#define getCode(po, rlc, c, lc, in, out, ob, oe) \
2726 if (lc < 8) getChar(c, lc, in); \
2730 unsigned char cs = (c >> lc); \
2732 if (out + cs > oe) return false; \
2735 unsigned short s = out[-1]; \
2737 while (cs-- > 0) *out++ = s; \
2738 } else if (out < oe) { \
2745static bool getCode(
int po,
int rlc,
long long &c,
int &lc,
const char *&in,
2746 const char *in_end,
unsigned short *&out,
2747 const unsigned short *ob,
const unsigned short *oe) {
2762 unsigned char cs = (c >> lc);
2764 if (out + cs > oe)
return false;
2768 if ((out - 1) < ob)
return false;
2769 unsigned short s = out[-1];
2771 while (cs-- > 0) *out++ = s;
2772 }
else if (out < oe) {
2785static bool hufDecode(
const long long *hcode,
2786 const HufDec *hdecod,
2791 unsigned short *out)
2795 unsigned short *outb = out;
2796 unsigned short *oe = out + no;
2797 const char *ie = in + (ni + 7) / 8;
2810 while (lc >= HUF_DECBITS) {
2811 const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
2826 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
2841 for (j = 0; j < pl.lit; j++) {
2842 int l = hufLength(hcode[pl.p[j]]);
2844 while (lc < l && in < ie)
2848 if (hufCode(hcode[pl.p[j]]) ==
2849 ((c >> (lc - l)) & (((
long long)(1) << l) - 1))) {
2855 if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
2875 int i = (8 - ni) & 7;
2880 const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
2884 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
2893 if (out - outb != no) {
2901static void countFrequencies(std::vector<long long> &freq,
2902 const unsigned short data[],
int n) {
2903 for (
int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
2905 for (
int i = 0; i < n; ++i) ++freq[data[i]];
2908static void writeUInt(
char buf[4],
unsigned int i) {
2909 unsigned char *b = (
unsigned char *)
buf;
2917static unsigned int readUInt(
const char buf[4]) {
2918 const unsigned char *b = (
const unsigned char *)
buf;
2920 return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) |
2921 ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000);
2928static int hufCompress(
const unsigned short raw[],
int nRaw,
2929 char compressed[]) {
2930 if (nRaw == 0)
return 0;
2932 std::vector<long long> freq(HUF_ENCSIZE);
2934 countFrequencies(freq, raw, nRaw);
2938 hufBuildEncTable(freq.data(), &im, &iM);
2940 char *tableStart = compressed + 20;
2941 char *tableEnd = tableStart;
2942 hufPackEncTable(freq.data(), im, iM, &tableEnd);
2943 int tableLength = tableEnd - tableStart;
2945 char *dataStart = tableEnd;
2946 int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
2947 int data_length = (nBits + 7) / 8;
2949 writeUInt(compressed, im);
2950 writeUInt(compressed + 4, iM);
2951 writeUInt(compressed + 8, tableLength);
2952 writeUInt(compressed + 12, nBits);
2953 writeUInt(compressed + 16, 0);
2955 return dataStart + data_length - compressed;
2958static bool hufUncompress(
const char compressed[],
int nCompressed,
2959 std::vector<unsigned short> *raw) {
2960 if (nCompressed == 0) {
2961 if (raw->size() != 0)
return false;
2966 int im = readUInt(compressed);
2967 int iM = readUInt(compressed + 4);
2969 int nBits = readUInt(compressed + 12);
2971 if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE)
return false;
2973 const char *ptr = compressed + 20;
2988 std::vector<long long> freq(HUF_ENCSIZE);
2989 std::vector<HufDec> hdec(HUF_DECSIZE);
2991 hufClearDecTable(&hdec.at(0));
2993 hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM,
2997 if (nBits > 8 * (nCompressed - (ptr - compressed))) {
3001 hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
3002 hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
3011 hufFreeDecTable(&hdec.at(0));
3021const int USHORT_RANGE = (1 << 16);
3022const int BITMAP_SIZE = (USHORT_RANGE >> 3);
3024static void bitmapFromData(
const unsigned short data[],
int nData,
3025 unsigned char bitmap[BITMAP_SIZE],
3026 unsigned short &minNonZero,
3027 unsigned short &maxNonZero) {
3028 for (
int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0;
3030 for (
int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
3035 minNonZero = BITMAP_SIZE - 1;
3038 for (
int i = 0; i < BITMAP_SIZE; ++i) {
3040 if (minNonZero > i) minNonZero = i;
3041 if (maxNonZero < i) maxNonZero = i;
3046static unsigned short forwardLutFromBitmap(
3047 const unsigned char bitmap[BITMAP_SIZE],
unsigned short lut[USHORT_RANGE]) {
3050 for (
int i = 0; i < USHORT_RANGE; ++i) {
3051 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
3060static unsigned short reverseLutFromBitmap(
3061 const unsigned char bitmap[BITMAP_SIZE],
unsigned short lut[USHORT_RANGE]) {
3064 for (
int i = 0; i < USHORT_RANGE; ++i) {
3065 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i;
3070 while (k < USHORT_RANGE) lut[k++] = 0;
3075static void applyLut(
const unsigned short lut[USHORT_RANGE],
3076 unsigned short data[],
int nData) {
3077 for (
int i = 0; i < nData; ++i) data[i] = lut[data[i]];
3081#pragma clang diagnostic pop
3088static bool CompressPiz(
unsigned char *outPtr,
unsigned int *outSize,
3089 const unsigned char *inPtr,
size_t inSize,
3090 const std::vector<ChannelInfo> &channelInfo,
3091 int data_width,
int num_lines) {
3092 std::vector<unsigned char> bitmap(BITMAP_SIZE);
3093 unsigned short minNonZero;
3094 unsigned short maxNonZero;
3096#if !TINYEXR_LITTLE_ENDIAN
3102 std::vector<unsigned short> tmpBuffer(inSize /
sizeof(
unsigned short));
3104 std::vector<PIZChannelData> channelData(channelInfo.size());
3105 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
3107 for (
size_t c = 0; c < channelData.size(); c++) {
3108 PIZChannelData &cd = channelData[c];
3110 cd.start = tmpBufferEnd;
3117 size_t pixelSize =
sizeof(
int);
3119 pixelSize =
sizeof(short);
3122 cd.size =
static_cast<int>(pixelSize /
sizeof(short));
3124 tmpBufferEnd += cd.nx * cd.ny * cd.size;
3127 const unsigned char *ptr = inPtr;
3128 for (
int y = 0;
y < num_lines; ++
y) {
3129 for (
size_t i = 0; i < channelData.size(); ++i) {
3130 PIZChannelData &cd = channelData[i];
3135 size_t n =
static_cast<size_t>(cd.nx * cd.size);
3136 memcpy(cd.end, ptr, n *
sizeof(
unsigned short));
3137 ptr += n *
sizeof(
unsigned short);
3142 bitmapFromData(&tmpBuffer.at(0),
static_cast<int>(tmpBuffer.size()),
3143 bitmap.data(), minNonZero, maxNonZero);
3145 std::vector<unsigned short> lut(USHORT_RANGE);
3146 unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
3147 applyLut(lut.data(), &tmpBuffer.at(0),
static_cast<int>(tmpBuffer.size()));
3153 char *
buf =
reinterpret_cast<char *
>(outPtr);
3155 memcpy(
buf, &minNonZero,
sizeof(
unsigned short));
3156 buf +=
sizeof(
unsigned short);
3157 memcpy(
buf, &maxNonZero,
sizeof(
unsigned short));
3158 buf +=
sizeof(
unsigned short);
3160 if (minNonZero <= maxNonZero) {
3161 memcpy(
buf,
reinterpret_cast<char *
>(&bitmap[0] + minNonZero),
3162 maxNonZero - minNonZero + 1);
3163 buf += maxNonZero - minNonZero + 1;
3170 for (
size_t i = 0; i < channelData.size(); ++i) {
3171 PIZChannelData &cd = channelData[i];
3173 for (
int j = 0; j < cd.size; ++j) {
3174 wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
3185 char *lengthPtr =
buf;
3187 memcpy(
buf, &zero,
sizeof(
int));
3191 hufCompress(&tmpBuffer.at(0),
static_cast<int>(tmpBuffer.size()),
buf);
3192 memcpy(lengthPtr, &length,
sizeof(
int));
3194 (*outSize) =
static_cast<unsigned int>(
3195 (
reinterpret_cast<unsigned char *
>(
buf) - outPtr) +
3196 static_cast<unsigned int>(length));
3200 if ((*outSize) >= inSize) {
3201 (*outSize) =
static_cast<unsigned int>(inSize);
3202 memcpy(outPtr, inPtr, inSize);
3207static bool DecompressPiz(
unsigned char *outPtr,
const unsigned char *inPtr,
3208 size_t tmpBufSizeInBytes,
size_t inLen,
int num_channels,
3211 if (inLen == tmpBufSizeInBytes) {
3213 memcpy(outPtr, inPtr, inLen);
3217 std::vector<unsigned char> bitmap(BITMAP_SIZE);
3218 unsigned short minNonZero;
3219 unsigned short maxNonZero;
3221#if !TINYEXR_LITTLE_ENDIAN
3226 memset(bitmap.data(), 0, BITMAP_SIZE);
3234 const unsigned char *ptr = inPtr;
3236 tinyexr::cpy2(&minNonZero,
reinterpret_cast<const unsigned short *
>(ptr));
3238 tinyexr::cpy2(&maxNonZero,
reinterpret_cast<const unsigned short *
>(ptr + 2));
3242 if (maxNonZero >= BITMAP_SIZE) {
3251 if (minNonZero <= maxNonZero) {
3252 if (((maxNonZero - minNonZero + 1) + readLen) > inLen) {
3257 memcpy(
reinterpret_cast<char *
>(&bitmap[0] + minNonZero), ptr,
3258 maxNonZero - minNonZero + 1);
3259 ptr += maxNonZero - minNonZero + 1;
3260 readLen += maxNonZero - minNonZero + 1;
3263 if ((minNonZero == (BITMAP_SIZE - 1)) && (maxNonZero == 0)) {
3271 std::vector<unsigned short> lut(USHORT_RANGE);
3272 memset(lut.data(), 0,
sizeof(
unsigned short) * USHORT_RANGE);
3273 unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
3279 if ((readLen + 4) > inLen) {
3286 tinyexr::cpy4(&length,
reinterpret_cast<const int *
>(ptr));
3289 if (
size_t((ptr - inPtr) + length) > inLen) {
3293 std::vector<unsigned short> tmpBuffer(tmpBufSizeInBytes /
sizeof(
unsigned short));
3294 hufUncompress(
reinterpret_cast<const char *
>(ptr), length, &tmpBuffer);
3300 std::vector<PIZChannelData> channelData(
static_cast<size_t>(num_channels));
3302 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
3304 for (
size_t i = 0; i < static_cast<size_t>(num_channels); ++i) {
3307 size_t pixelSize =
sizeof(
int);
3309 pixelSize =
sizeof(short);
3312 channelData[i].start = tmpBufferEnd;
3313 channelData[i].end = channelData[i].start;
3314 channelData[i].nx = data_width;
3315 channelData[i].ny = num_lines;
3317 channelData[i].size =
static_cast<int>(pixelSize /
sizeof(short));
3319 tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size;
3322 for (
size_t i = 0; i < channelData.size(); ++i) {
3323 PIZChannelData &cd = channelData[i];
3325 for (
int j = 0; j < cd.size; ++j) {
3326 wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
3335 applyLut(lut.data(), &tmpBuffer.at(0),
static_cast<int>(tmpBufSizeInBytes /
sizeof(
unsigned short)));
3337 for (
int y = 0;
y < num_lines;
y++) {
3338 for (
size_t i = 0; i < channelData.size(); ++i) {
3339 PIZChannelData &cd = channelData[i];
3344 size_t n =
static_cast<size_t>(cd.nx * cd.size);
3345 memcpy(outPtr, cd.end,
static_cast<size_t>(n *
sizeof(
unsigned short)));
3346 outPtr += n *
sizeof(
unsigned short);
3357struct ZFPCompressionParam {
3359 unsigned int precision;
3360 unsigned int __pad0;
3363 unsigned int __pad1;
3365 ZFPCompressionParam() {
3373static bool FindZFPCompressionParam(ZFPCompressionParam *param,
3375 int num_attributes, std::string *err) {
3376 bool foundType =
false;
3378 for (
int i = 0; i < num_attributes; i++) {
3379 if ((strcmp(attributes[i].name,
"zfpCompressionType") == 0)) {
3380 if (attributes[i].
size == 1) {
3381 param->type =
static_cast<int>(attributes[i].
value[0]);
3387 "zfpCompressionType attribute must be uchar(1 byte) type.\n";
3396 (*err) +=
"`zfpCompressionType` attribute not found.\n";
3402 for (
int i = 0; i < num_attributes; i++) {
3403 if ((strcmp(attributes[i].name,
"zfpCompressionRate") == 0) &&
3404 (attributes[i].
size == 8)) {
3405 param->rate = *(
reinterpret_cast<double *
>(attributes[i].
value));
3411 (*err) +=
"`zfpCompressionRate` attribute not found.\n";
3415 for (
int i = 0; i < num_attributes; i++) {
3416 if ((strcmp(attributes[i].name,
"zfpCompressionPrecision") == 0) &&
3417 (attributes[i].
size == 4)) {
3418 param->rate = *(
reinterpret_cast<int *
>(attributes[i].
value));
3424 (*err) +=
"`zfpCompressionPrecision` attribute not found.\n";
3428 for (
int i = 0; i < num_attributes; i++) {
3429 if ((strcmp(attributes[i].name,
"zfpCompressionTolerance") == 0) &&
3430 (attributes[i].
size == 8)) {
3431 param->tolerance = *(
reinterpret_cast<double *
>(attributes[i].
value));
3437 (*err) +=
"`zfpCompressionTolerance` attribute not found.\n";
3441 (*err) +=
"Unknown value specified for `zfpCompressionType`.\n";
3449static bool DecompressZfp(
float *dst,
int dst_width,
int dst_num_lines,
3450 size_t num_channels,
const unsigned char *src,
3451 unsigned long src_size,
3452 const ZFPCompressionParam ¶m) {
3453 size_t uncompressed_size =
3454 size_t(dst_width) * size_t(dst_num_lines) * num_channels;
3456 if (uncompressed_size == src_size) {
3458 memcpy(dst, src, src_size);
3461 zfp_stream *zfp = NULL;
3462 zfp_field *field = NULL;
3464 TINYEXR_CHECK_AND_RETURN_C((dst_width % 4) == 0,
false);
3465 TINYEXR_CHECK_AND_RETURN_C((dst_num_lines % 4) == 0,
false);
3467 if ((
size_t(dst_width) & 3U) || (
size_t(dst_num_lines) & 3U)) {
3472 zfp_field_2d(
reinterpret_cast<void *
>(
const_cast<unsigned char *
>(src)),
3473 zfp_type_float,
static_cast<unsigned int>(dst_width),
3474 static_cast<unsigned int>(dst_num_lines) *
3475 static_cast<unsigned int>(num_channels));
3476 zfp = zfp_stream_open(NULL);
3479 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2,
3482 zfp_stream_set_precision(zfp, param.precision);
3484 zfp_stream_set_accuracy(zfp, param.tolerance);
3489 size_t buf_size = zfp_stream_maximum_size(zfp, field);
3490 std::vector<unsigned char>
buf(buf_size);
3491 memcpy(&
buf.at(0), src, src_size);
3493 bitstream *
stream = stream_open(&
buf.at(0), buf_size);
3494 zfp_stream_set_bit_stream(zfp,
stream);
3495 zfp_stream_rewind(zfp);
3497 size_t image_size = size_t(dst_width) * size_t(dst_num_lines);
3499 for (
size_t c = 0; c < size_t(num_channels); c++) {
3501 for (
size_t y = 0;
y < size_t(dst_num_lines);
y += 4) {
3502 for (
size_t x = 0;
x < size_t(dst_width);
x += 4) {
3504 zfp_decode_block_float_2(zfp, fblock);
3505 for (
size_t j = 0; j < 4; j++) {
3506 for (
size_t i = 0; i < 4; i++) {
3507 dst[c * image_size + ((
y + j) * size_t(dst_width) + (
x + i))] =
3515 zfp_field_free(field);
3516 zfp_stream_close(zfp);
3523static bool CompressZfp(std::vector<unsigned char> *outBuf,
3524 unsigned int *outSize,
const float *inPtr,
int width,
3525 int num_lines,
int num_channels,
3526 const ZFPCompressionParam ¶m) {
3527 zfp_stream *zfp = NULL;
3528 zfp_field *field = NULL;
3530 TINYEXR_CHECK_AND_RETURN_C((width % 4) == 0,
false);
3531 TINYEXR_CHECK_AND_RETURN_C((num_lines % 4) == 0,
false);
3533 if ((
size_t(width) & 3U) || (
size_t(num_lines) & 3U)) {
3538 field = zfp_field_2d(
reinterpret_cast<void *
>(
const_cast<float *
>(inPtr)),
3539 zfp_type_float,
static_cast<unsigned int>(width),
3540 static_cast<unsigned int>(num_lines * num_channels));
3542 zfp = zfp_stream_open(NULL);
3545 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0);
3547 zfp_stream_set_precision(zfp, param.precision);
3549 zfp_stream_set_accuracy(zfp, param.tolerance);
3554 size_t buf_size = zfp_stream_maximum_size(zfp, field);
3556 outBuf->resize(buf_size);
3558 bitstream *
stream = stream_open(&outBuf->at(0), buf_size);
3559 zfp_stream_set_bit_stream(zfp,
stream);
3560 zfp_field_free(field);
3562 size_t image_size = size_t(width) * size_t(num_lines);
3564 for (
size_t c = 0; c < size_t(num_channels); c++) {
3566 for (
size_t y = 0;
y < size_t(num_lines);
y += 4) {
3567 for (
size_t x = 0;
x < size_t(width);
x += 4) {
3569 for (
size_t j = 0; j < 4; j++) {
3570 for (
size_t i = 0; i < 4; i++) {
3572 inPtr[c * image_size + ((
y + j) * size_t(width) + (
x + i))];
3575 zfp_encode_block_float_2(zfp, fblock);
3580 zfp_stream_flush(zfp);
3581 (*outSize) =
static_cast<unsigned int>(zfp_stream_compressed_size(zfp));
3583 zfp_stream_close(zfp);
3595#define TINYEXR_DIMENSION_THRESHOLD (1024 * 8192)
3598static bool DecodePixelData(
unsigned char **out_images,
3599 const int *requested_pixel_types,
3600 const unsigned char *data_ptr,
size_t data_len,
3601 int compression_type,
int line_order,
int width,
3602 int height,
int x_stride,
int y,
int line_no,
3603 int num_lines,
size_t pixel_data_size,
3604 size_t num_attributes,
3607 const std::vector<size_t> &channel_offset_list) {
3610 if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
3616 std::vector<unsigned char> outBuf(
static_cast<size_t>(
3617 static_cast<size_t>(width * num_lines) * pixel_data_size));
3618 size_t tmpBufLen = outBuf.size();
3620 bool ret = tinyexr::DecompressPiz(
3621 reinterpret_cast<unsigned char *
>(&outBuf.at(0)), data_ptr, tmpBufLen,
3622 data_len,
static_cast<int>(num_channels), channels, width, num_lines);
3638 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
3640 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3641 const unsigned short *line_ptr =
reinterpret_cast<unsigned short *
>(
3642 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
3643 channel_offset_list[c] *
static_cast<size_t>(width)));
3644 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3650 tinyexr::cpy2(&(hf.u), line_ptr + u);
3652 tinyexr::swap2(
reinterpret_cast<unsigned short *
>(&hf.u));
3655 unsigned short *image =
3656 reinterpret_cast<unsigned short **
>(out_images)[c];
3657 if (line_order == 0) {
3658 image += (
static_cast<size_t>(line_no) + v) *
3659 static_cast<size_t>(x_stride) +
3662 image +=
static_cast<size_t>(
3663 (height - 1 - (line_no +
static_cast<int>(v)))) *
3664 static_cast<size_t>(x_stride) +
3669 FP32 f32 = half_to_float(hf);
3670 float *image =
reinterpret_cast<float **
>(out_images)[c];
3672 if (line_order == 0) {
3673 offset = (
static_cast<size_t>(line_no) + v) *
3674 static_cast<size_t>(x_stride) +
3677 offset =
static_cast<size_t>(
3678 (height - 1 - (line_no +
static_cast<int>(v)))) *
3679 static_cast<size_t>(x_stride) +
3690 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3691 const unsigned int *line_ptr =
reinterpret_cast<unsigned int *
>(
3692 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
3693 channel_offset_list[c] *
static_cast<size_t>(width)));
3694 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3697 tinyexr::cpy4(&val, line_ptr + u);
3699 tinyexr::swap4(&val);
3701 unsigned int *image =
3702 reinterpret_cast<unsigned int **
>(out_images)[c];
3703 if (line_order == 0) {
3704 image += (
static_cast<size_t>(line_no) + v) *
3705 static_cast<size_t>(x_stride) +
3708 image +=
static_cast<size_t>(
3709 (height - 1 - (line_no +
static_cast<int>(v)))) *
3710 static_cast<size_t>(x_stride) +
3718 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3719 const float *line_ptr =
reinterpret_cast<float *
>(&outBuf.at(
3720 v * pixel_data_size *
static_cast<size_t>(width) +
3721 channel_offset_list[c] *
static_cast<size_t>(width)));
3722 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3725 tinyexr::cpy4(&val, line_ptr + u);
3727 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&val));
3729 float *image =
reinterpret_cast<float **
>(out_images)[c];
3730 if (line_order == 0) {
3731 image += (
static_cast<size_t>(line_no) + v) *
3732 static_cast<size_t>(x_stride) +
3735 image +=
static_cast<size_t>(
3736 (height - 1 - (line_no +
static_cast<int>(v)))) *
3737 static_cast<size_t>(x_stride) +
3754 std::vector<unsigned char> outBuf(
static_cast<size_t>(width) *
3755 static_cast<size_t>(num_lines) *
3758 unsigned long dstLen =
static_cast<unsigned long>(outBuf.size());
3759 TINYEXR_CHECK_AND_RETURN_C(dstLen > 0,
false);
3760 if (!tinyexr::DecompressZip(
3761 reinterpret_cast<unsigned char *
>(&outBuf.at(0)), &dstLen, data_ptr,
3762 static_cast<unsigned long>(data_len))) {
3776 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
3778 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3779 const unsigned short *line_ptr =
reinterpret_cast<unsigned short *
>(
3780 &outBuf.at(v *
static_cast<size_t>(pixel_data_size) *
3781 static_cast<size_t>(width) +
3782 channel_offset_list[c] *
static_cast<size_t>(width)));
3783 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3787 tinyexr::cpy2(&(hf.u), line_ptr + u);
3789 tinyexr::swap2(
reinterpret_cast<unsigned short *
>(&hf.u));
3792 unsigned short *image =
3793 reinterpret_cast<unsigned short **
>(out_images)[c];
3794 if (line_order == 0) {
3795 image += (
static_cast<size_t>(line_no) + v) *
3796 static_cast<size_t>(x_stride) +
3799 image += (
static_cast<size_t>(height) - 1U -
3800 (
static_cast<size_t>(line_no) + v)) *
3801 static_cast<size_t>(x_stride) +
3806 tinyexr::FP32 f32 = half_to_float(hf);
3807 float *image =
reinterpret_cast<float **
>(out_images)[c];
3809 if (line_order == 0) {
3810 offset = (
static_cast<size_t>(line_no) + v) *
3811 static_cast<size_t>(x_stride) +
3814 offset = (
static_cast<size_t>(height) - 1U -
3815 (
static_cast<size_t>(line_no) + v)) *
3816 static_cast<size_t>(x_stride) +
3828 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3829 const unsigned int *line_ptr =
reinterpret_cast<unsigned int *
>(
3830 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
3831 channel_offset_list[c] *
static_cast<size_t>(width)));
3832 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3835 tinyexr::cpy4(&val, line_ptr + u);
3837 tinyexr::swap4(&val);
3839 unsigned int *image =
3840 reinterpret_cast<unsigned int **
>(out_images)[c];
3841 if (line_order == 0) {
3842 image += (
static_cast<size_t>(line_no) + v) *
3843 static_cast<size_t>(x_stride) +
3846 image += (
static_cast<size_t>(height) - 1U -
3847 (
static_cast<size_t>(line_no) + v)) *
3848 static_cast<size_t>(x_stride) +
3856 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3857 const float *line_ptr =
reinterpret_cast<float *
>(
3858 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
3859 channel_offset_list[c] *
static_cast<size_t>(width)));
3860 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3863 tinyexr::cpy4(&val, line_ptr + u);
3865 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&val));
3867 float *image =
reinterpret_cast<float **
>(out_images)[c];
3868 if (line_order == 0) {
3869 image += (
static_cast<size_t>(line_no) + v) *
3870 static_cast<size_t>(x_stride) +
3873 image += (
static_cast<size_t>(height) - 1U -
3874 (
static_cast<size_t>(line_no) + v)) *
3875 static_cast<size_t>(x_stride) +
3887 std::vector<unsigned char> outBuf(
static_cast<size_t>(width) *
3888 static_cast<size_t>(num_lines) *
3891 unsigned long dstLen =
static_cast<unsigned long>(outBuf.size());
3896 if (!tinyexr::DecompressRle(
3897 reinterpret_cast<unsigned char *
>(&outBuf.at(0)), dstLen, data_ptr,
3898 static_cast<unsigned long>(data_len))) {
3912 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
3914 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3915 const unsigned short *line_ptr =
reinterpret_cast<unsigned short *
>(
3916 &outBuf.at(v *
static_cast<size_t>(pixel_data_size) *
3917 static_cast<size_t>(width) +
3918 channel_offset_list[c] *
static_cast<size_t>(width)));
3919 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3923 tinyexr::cpy2(&(hf.u), line_ptr + u);
3925 tinyexr::swap2(
reinterpret_cast<unsigned short *
>(&hf.u));
3928 unsigned short *image =
3929 reinterpret_cast<unsigned short **
>(out_images)[c];
3930 if (line_order == 0) {
3931 image += (
static_cast<size_t>(line_no) + v) *
3932 static_cast<size_t>(x_stride) +
3935 image += (
static_cast<size_t>(height) - 1U -
3936 (
static_cast<size_t>(line_no) + v)) *
3937 static_cast<size_t>(x_stride) +
3942 tinyexr::FP32 f32 = half_to_float(hf);
3943 float *image =
reinterpret_cast<float **
>(out_images)[c];
3944 if (line_order == 0) {
3945 image += (
static_cast<size_t>(line_no) + v) *
3946 static_cast<size_t>(x_stride) +
3949 image += (
static_cast<size_t>(height) - 1U -
3950 (
static_cast<size_t>(line_no) + v)) *
3951 static_cast<size_t>(x_stride) +
3961 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3962 const unsigned int *line_ptr =
reinterpret_cast<unsigned int *
>(
3963 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
3964 channel_offset_list[c] *
static_cast<size_t>(width)));
3965 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3968 tinyexr::cpy4(&val, line_ptr + u);
3970 tinyexr::swap4(&val);
3972 unsigned int *image =
3973 reinterpret_cast<unsigned int **
>(out_images)[c];
3974 if (line_order == 0) {
3975 image += (
static_cast<size_t>(line_no) + v) *
3976 static_cast<size_t>(x_stride) +
3979 image += (
static_cast<size_t>(height) - 1U -
3980 (
static_cast<size_t>(line_no) + v)) *
3981 static_cast<size_t>(x_stride) +
3989 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
3990 const float *line_ptr =
reinterpret_cast<float *
>(
3991 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
3992 channel_offset_list[c] *
static_cast<size_t>(width)));
3993 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
3996 tinyexr::cpy4(&val, line_ptr + u);
3998 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&val));
4000 float *image =
reinterpret_cast<float **
>(out_images)[c];
4001 if (line_order == 0) {
4002 image += (
static_cast<size_t>(line_no) + v) *
4003 static_cast<size_t>(x_stride) +
4006 image += (
static_cast<size_t>(height) - 1U -
4007 (
static_cast<size_t>(line_no) + v)) *
4008 static_cast<size_t>(x_stride) +
4020 tinyexr::ZFPCompressionParam zfp_compression_param;
4022 if (!tinyexr::FindZFPCompressionParam(&zfp_compression_param, attributes,
4023 int(num_attributes), &e)) {
4029 std::vector<unsigned char> outBuf(
static_cast<size_t>(width) *
4030 static_cast<size_t>(num_lines) *
4033 unsigned long dstLen = outBuf.size();
4034 TINYEXR_CHECK_AND_RETURN_C(dstLen > 0,
false);
4035 tinyexr::DecompressZfp(
reinterpret_cast<float *
>(&outBuf.at(0)), width,
4036 num_lines, num_channels, data_ptr,
4037 static_cast<unsigned long>(data_len),
4038 zfp_compression_param);
4050 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
4054 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
4055 const float *line_ptr =
reinterpret_cast<float *
>(
4056 &outBuf.at(v * pixel_data_size *
static_cast<size_t>(width) +
4057 channel_offset_list[c] *
static_cast<size_t>(width)));
4058 for (
size_t u = 0; u < static_cast<size_t>(width); u++) {
4060 tinyexr::cpy4(&val, line_ptr + u);
4062 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&val));
4064 float *image =
reinterpret_cast<float **
>(out_images)[c];
4065 if (line_order == 0) {
4066 image += (
static_cast<size_t>(line_no) + v) *
4067 static_cast<size_t>(x_stride) +
4070 image += (
static_cast<size_t>(height) - 1U -
4071 (
static_cast<size_t>(line_no) + v)) *
4072 static_cast<size_t>(x_stride) +
4084 (void)num_attributes;
4089 for (
size_t c = 0; c < num_channels; c++) {
4090 for (
size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
4092 const unsigned short *line_ptr =
4093 reinterpret_cast<const unsigned short *
>(
4094 data_ptr + v * pixel_data_size * size_t(width) +
4095 channel_offset_list[c] *
static_cast<size_t>(width));
4098 unsigned short *outLine =
4099 reinterpret_cast<unsigned short *
>(out_images[c]);
4100 if (line_order == 0) {
4101 outLine += (size_t(
y) + v) *
size_t(x_stride);
4104 (size_t(height) - 1 - (size_t(
y) + v)) * size_t(x_stride);
4107 for (
int u = 0; u < width; u++) {
4111 tinyexr::cpy2(&(hf.u), line_ptr + u);
4113 tinyexr::swap2(
reinterpret_cast<unsigned short *
>(&hf.u));
4118 float *outLine =
reinterpret_cast<float *
>(out_images[c]);
4119 if (line_order == 0) {
4120 outLine += (size_t(
y) + v) *
size_t(x_stride);
4123 (size_t(height) - 1 - (size_t(
y) + v)) * size_t(x_stride);
4126 if (
reinterpret_cast<const unsigned char *
>(line_ptr + width) >
4127 (data_ptr + data_len)) {
4132 for (
int u = 0; u < width; u++) {
4137 tinyexr::cpy2(&(hf.u), line_ptr + u);
4139 tinyexr::swap2(
reinterpret_cast<unsigned short *
>(&hf.u));
4141 tinyexr::FP32 f32 = half_to_float(hf);
4149 const float *line_ptr =
reinterpret_cast<const float *
>(
4150 data_ptr + v * pixel_data_size * size_t(width) +
4151 channel_offset_list[c] *
static_cast<size_t>(width));
4153 float *outLine =
reinterpret_cast<float *
>(out_images[c]);
4154 if (line_order == 0) {
4155 outLine += (size_t(
y) + v) *
size_t(x_stride);
4158 (size_t(height) - 1 - (size_t(
y) + v)) * size_t(x_stride);
4161 if (
reinterpret_cast<const unsigned char *
>(line_ptr + width) >
4162 (data_ptr + data_len)) {
4167 for (
int u = 0; u < width; u++) {
4169 tinyexr::cpy4(&val, line_ptr + u);
4171 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&val));
4176 const unsigned int *line_ptr =
reinterpret_cast<const unsigned int *
>(
4177 data_ptr + v * pixel_data_size * size_t(width) +
4178 channel_offset_list[c] *
static_cast<size_t>(width));
4180 unsigned int *outLine =
4181 reinterpret_cast<unsigned int *
>(out_images[c]);
4182 if (line_order == 0) {
4183 outLine += (size_t(
y) + v) *
size_t(x_stride);
4186 (size_t(height) - 1 - (size_t(
y) + v)) * size_t(x_stride);
4189 if (
reinterpret_cast<const unsigned char *
>(line_ptr + width) >
4190 (data_ptr + data_len)) {
4195 for (
int u = 0; u < width; u++) {
4198 tinyexr::cpy4(&val, line_ptr + u);
4200 tinyexr::swap4(
reinterpret_cast<unsigned int *
>(&val));
4212static bool DecodeTiledPixelData(
4213 unsigned char **out_images,
int *width,
int *height,
4214 const int *requested_pixel_types,
const unsigned char *data_ptr,
4215 size_t data_len,
int compression_type,
int line_order,
int data_width,
4216 int data_height,
int tile_offset_x,
int tile_offset_y,
int tile_size_x,
4217 int tile_size_y,
size_t pixel_data_size,
size_t num_attributes,
4220 const std::vector<size_t> &channel_offset_list) {
4222 if (tile_size_x * tile_offset_x > data_width ||
4223 tile_size_y * tile_offset_y > data_height) {
4228 if ((tile_offset_x + 1) * tile_size_x >= data_width) {
4229 (*width) = data_width - (tile_offset_x * tile_size_x);
4231 (*width) = tile_size_x;
4234 if ((tile_offset_y + 1) * tile_size_y >= data_height) {
4235 (*height) = data_height - (tile_offset_y * tile_size_y);
4237 (*height) = tile_size_y;
4241 return DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len,
4242 compression_type, line_order, (*width), tile_size_y,
4244 (*height), pixel_data_size, num_attributes, attributes,
4245 num_channels, channels, channel_offset_list);
4248static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
4249 int *pixel_data_size,
size_t *channel_offset,
4252 channel_offset_list->resize(
static_cast<size_t>(num_channels));
4254 (*pixel_data_size) = 0;
4255 (*channel_offset) = 0;
4257 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
4258 (*channel_offset_list)[c] = (*channel_offset);
4260 (*pixel_data_size) +=
sizeof(
unsigned short);
4261 (*channel_offset) +=
sizeof(
unsigned short);
4263 (*pixel_data_size) +=
sizeof(float);
4264 (*channel_offset) +=
sizeof(float);
4266 (*pixel_data_size) +=
sizeof(
unsigned int);
4267 (*channel_offset) +=
sizeof(
unsigned int);
4277static unsigned char **AllocateImage(
int num_channels,
4279 const int *requested_pixel_types,
4280 int data_width,
int data_height,
bool *success) {
4281 unsigned char **images =
4282 reinterpret_cast<unsigned char **
>(
static_cast<float **
>(
4283 malloc(
sizeof(
float *) *
static_cast<size_t>(num_channels))));
4285 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
4291 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
4293 static_cast<size_t>(data_width) *
static_cast<size_t>(data_height);
4300 reinterpret_cast<unsigned char *
>(
static_cast<unsigned short *
>(
4301 malloc(
sizeof(
unsigned short) * data_len)));
4303 images[c] =
reinterpret_cast<unsigned char *
>(
4304 static_cast<float *
>(malloc(
sizeof(
float) * data_len)));
4313 images[c] =
reinterpret_cast<unsigned char *
>(
4314 static_cast<float *
>(malloc(
sizeof(
float) * data_len)));
4318 images[c] =
reinterpret_cast<unsigned char *
>(
4319 static_cast<unsigned int *
>(malloc(
sizeof(
unsigned int) * data_len)));
4328 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
4348static inline std::wstring UTF8ToWchar(
const std::string &str) {
4350 MultiByteToWideChar(CP_UTF8, 0, str.data(), (
int)str.size(), NULL, 0);
4351 std::wstring wstr(wstr_size, 0);
4352 MultiByteToWideChar(CP_UTF8, 0, str.data(), (
int)str.size(), &wstr[0],
4359static int ParseEXRHeader(HeaderInfo *info,
bool *empty_header,
4361 const unsigned char *
buf,
size_t size) {
4362 const char *marker =
reinterpret_cast<const char *
>(&
buf[0]);
4365 (*empty_header) =
false;
4369 if (
size > 0 && marker[0] ==
'\0') {
4372 (*empty_header) =
true;
4389 bool has_channels =
false;
4390 bool has_compression =
false;
4391 bool has_data_window =
false;
4392 bool has_display_window =
false;
4393 bool has_line_order =
false;
4394 bool has_pixel_aspect_ratio =
false;
4395 bool has_screen_window_center =
false;
4396 bool has_screen_window_width =
false;
4397 bool has_name =
false;
4398 bool has_type =
false;
4403 info->data_window.min_x = 0;
4404 info->data_window.min_y = 0;
4405 info->data_window.max_x = 0;
4406 info->data_window.max_y = 0;
4407 info->line_order = 0;
4408 info->display_window.min_x = 0;
4409 info->display_window.min_y = 0;
4410 info->display_window.max_x = 0;
4411 info->display_window.max_y = 0;
4412 info->screen_window_center[0] = 0.0f;
4413 info->screen_window_center[1] = 0.0f;
4414 info->screen_window_width = -1.0f;
4415 info->pixel_aspect_ratio = -1.0f;
4418 info->tile_size_x = -1;
4419 info->tile_size_y = -1;
4420 info->tile_level_mode = -1;
4421 info->tile_rounding_mode = -1;
4423 info->attributes.clear();
4426 size_t orig_size =
size;
4430 (*err) +=
"Insufficient data size for attributes.\n";
4433 }
else if (marker[0] ==
'\0') {
4438 std::string attr_name;
4439 std::string attr_type;
4440 std::vector<unsigned char> data;
4442 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
4445 (*err) +=
"Failed to read attribute.\n";
4449 marker += marker_size;
4450 size -= marker_size;
4454 unsigned int x_size, y_size;
4455 unsigned char tile_mode;
4456 if (data.size() != 9) {
4458 (*err) +=
"(ParseEXRHeader) Invalid attribute data size. Attribute data size must be 9.\n";
4463 memcpy(&x_size, &data.at(0),
sizeof(
int));
4464 memcpy(&y_size, &data.at(4),
sizeof(
int));
4465 tile_mode = data[8];
4466 tinyexr::swap4(&x_size);
4467 tinyexr::swap4(&y_size);
4469 if (x_size >
static_cast<unsigned int>(std::numeric_limits<int>::max()) ||
4470 y_size >
static_cast<unsigned int>(std::numeric_limits<int>::max())) {
4472 (*err) =
"Tile sizes were invalid.";
4477 info->tile_size_x =
static_cast<int>(x_size);
4478 info->tile_size_y =
static_cast<int>(y_size);
4481 info->tile_level_mode = tile_mode & 0x3;
4482 info->tile_rounding_mode = (tile_mode >> 4) & 0x1;
4484 }
else if (attr_name.compare(
"compression") == 0) {
4495 (*err) =
"PIZ compression is not supported.";
4506 (*err) =
"ZFP compression is not supported.";
4514 (*err) =
"Unknown compression type.";
4519 info->compression_type =
static_cast<int>(data[0]);
4520 has_compression =
true;
4522 }
else if (attr_name.compare(
"channels") == 0) {
4530 if (!ReadChannelInfo(info->channels, data)) {
4532 (*err) +=
"Failed to parse channel info.\n";
4537 if (info->channels.size() < 1) {
4539 (*err) +=
"# of channels is zero.\n";
4544 has_channels =
true;
4546 }
else if (attr_name.compare(
"dataWindow") == 0) {
4547 if (data.size() >= 16) {
4548 memcpy(&info->data_window.min_x, &data.at(0),
sizeof(
int));
4549 memcpy(&info->data_window.min_y, &data.at(4),
sizeof(
int));
4550 memcpy(&info->data_window.max_x, &data.at(8),
sizeof(
int));
4551 memcpy(&info->data_window.max_y, &data.at(12),
sizeof(
int));
4552 tinyexr::swap4(&info->data_window.min_x);
4553 tinyexr::swap4(&info->data_window.min_y);
4554 tinyexr::swap4(&info->data_window.max_x);
4555 tinyexr::swap4(&info->data_window.max_y);
4556 has_data_window =
true;
4558 }
else if (attr_name.compare(
"displayWindow") == 0) {
4559 if (data.size() >= 16) {
4560 memcpy(&info->display_window.min_x, &data.at(0),
sizeof(
int));
4561 memcpy(&info->display_window.min_y, &data.at(4),
sizeof(
int));
4562 memcpy(&info->display_window.max_x, &data.at(8),
sizeof(
int));
4563 memcpy(&info->display_window.max_y, &data.at(12),
sizeof(
int));
4564 tinyexr::swap4(&info->display_window.min_x);
4565 tinyexr::swap4(&info->display_window.min_y);
4566 tinyexr::swap4(&info->display_window.max_x);
4567 tinyexr::swap4(&info->display_window.max_y);
4569 has_display_window =
true;
4571 }
else if (attr_name.compare(
"lineOrder") == 0) {
4572 if (data.size() >= 1) {
4573 info->line_order =
static_cast<int>(data[0]);
4574 has_line_order =
true;
4576 }
else if (attr_name.compare(
"pixelAspectRatio") == 0) {
4577 if (data.size() >=
sizeof(
float)) {
4578 memcpy(&info->pixel_aspect_ratio, &data.at(0),
sizeof(
float));
4579 tinyexr::swap4(&info->pixel_aspect_ratio);
4580 has_pixel_aspect_ratio =
true;
4582 }
else if (attr_name.compare(
"screenWindowCenter") == 0) {
4583 if (data.size() >= 8) {
4584 memcpy(&info->screen_window_center[0], &data.at(0),
sizeof(
float));
4585 memcpy(&info->screen_window_center[1], &data.at(4),
sizeof(
float));
4586 tinyexr::swap4(&info->screen_window_center[0]);
4587 tinyexr::swap4(&info->screen_window_center[1]);
4588 has_screen_window_center =
true;
4590 }
else if (attr_name.compare(
"screenWindowWidth") == 0) {
4591 if (data.size() >=
sizeof(
float)) {
4592 memcpy(&info->screen_window_width, &data.at(0),
sizeof(
float));
4593 tinyexr::swap4(&info->screen_window_width);
4595 has_screen_window_width =
true;
4597 }
else if (attr_name.compare(
"chunkCount") == 0) {
4598 if (data.size() >=
sizeof(
int)) {
4599 memcpy(&info->chunk_count, &data.at(0),
sizeof(
int));
4600 tinyexr::swap4(&info->chunk_count);
4602 }
else if (attr_name.compare(
"name") == 0) {
4603 if (!data.empty() && data[0]) {
4605 size_t len = strlen(
reinterpret_cast<const char*
>(&data[0]));
4606 info->name.resize(len);
4607 info->name.assign(
reinterpret_cast<const char*
>(&data[0]), len);
4610 }
else if (attr_name.compare(
"type") == 0) {
4611 if (!data.empty() && data[0]) {
4613 size_t len = strlen(
reinterpret_cast<const char*
>(&data[0]));
4614 info->type.resize(len);
4615 info->type.assign(
reinterpret_cast<const char*
>(&data[0]), len);
4623 strncpy_s(attrib.
name, attr_name.c_str(), 255);
4624 strncpy_s(attrib.
type, attr_type.c_str(), 255);
4626 strncpy(attrib.
name, attr_name.c_str(), 255);
4627 strncpy(attrib.
type, attr_type.c_str(), 255);
4629 attrib.
name[255] =
'\0';
4630 attrib.
type[255] =
'\0';
4632 attrib.
size =
static_cast<int>(data.size());
4633 attrib.
value =
static_cast<unsigned char *
>(malloc(data.size()));
4634 memcpy(
reinterpret_cast<char *
>(attrib.
value), &data.at(0),
4636 info->attributes.push_back(attrib);
4643 std::stringstream ss_err;
4645 if (!has_compression) {
4646 ss_err <<
"\"compression\" attribute not found in the header."
4650 if (!has_channels) {
4651 ss_err <<
"\"channels\" attribute not found in the header." << std::endl;
4654 if (!has_line_order) {
4655 ss_err <<
"\"lineOrder\" attribute not found in the header." << std::endl;
4658 if (!has_display_window) {
4659 ss_err <<
"\"displayWindow\" attribute not found in the header."
4663 if (!has_data_window) {
4664 ss_err <<
"\"dataWindow\" attribute not found in the header or invalid."
4668 if (!has_pixel_aspect_ratio) {
4669 ss_err <<
"\"pixelAspectRatio\" attribute not found in the header."
4673 if (!has_screen_window_width) {
4674 ss_err <<
"\"screenWindowWidth\" attribute not found in the header."
4678 if (!has_screen_window_center) {
4679 ss_err <<
"\"screenWindowCenter\" attribute not found in the header."
4685 ss_err <<
"\"name\" attribute not found in the header."
4689 ss_err <<
"\"type\" attribute not found in the header."
4694 if (!(ss_err.str().empty())) {
4696 (*err) += ss_err.str();
4703 info->header_len =
static_cast<unsigned int>(orig_size -
size);
4709static bool ConvertHeader(
EXRHeader *exr_header,
const HeaderInfo &info, std::string *warn, std::string *err) {
4725 exr_header->
tiled = info.tiled;
4734 if (!info.type.empty()) {
4736 if (info.type ==
"scanlineimage") {
4737 if (exr_header->
tiled) {
4739 (*err) +=
"(ConvertHeader) tiled bit must be off for `scanlineimage` type.\n";
4743 }
else if (info.type ==
"tiledimage") {
4744 if (!exr_header->
tiled) {
4746 (*err) +=
"(ConvertHeader) tiled bit must be on for `tiledimage` type.\n";
4750 }
else if (info.type ==
"deeptile") {
4752 if (!exr_header->
tiled) {
4754 (*err) +=
"(ConvertHeader) tiled bit must be on for `deeptile` type.\n";
4758 }
else if (info.type ==
"deepscanline") {
4760 if (exr_header->
tiled) {
4762 (*err) +=
"(ConvertHeader) tiled bit must be off for `deepscanline` type.\n";
4768 std::stringstream ss;
4769 ss <<
"(ConvertHeader) Unsupported or unknown info.type: " << info.type <<
"\n";
4770 (*warn) += ss.str();
4779 exr_header->
num_channels =
static_cast<int>(info.channels.size());
4783 for (
size_t c = 0; c < static_cast<size_t>(exr_header->
num_channels); c++) {
4785 strncpy_s(exr_header->
channels[c].
name, info.channels[c].name.c_str(), 255);
4787 strncpy(exr_header->
channels[c].
name, info.channels[c].name.c_str(), 255);
4799 malloc(
sizeof(
int) *
static_cast<size_t>(exr_header->
num_channels)));
4800 for (
size_t c = 0; c < static_cast<size_t>(exr_header->
num_channels); c++) {
4801 exr_header->
pixel_types[c] = info.channels[c].pixel_type;
4806 malloc(
sizeof(
int) *
static_cast<size_t>(exr_header->
num_channels)));
4807 for (
size_t c = 0; c < static_cast<size_t>(exr_header->
num_channels); c++) {
4843 OffsetData() : num_x_levels(0), num_y_levels(0) {}
4844 std::vector<std::vector<std::vector <tinyexr::tinyexr_uint64> > > offsets;
4850static int LevelIndex(
int lx,
int ly,
int tile_level_mode,
int num_x_levels) {
4851 switch (tile_level_mode) {
4859 return lx + ly * num_x_levels;
4867static int LevelSize(
int toplevel_size,
int level,
int tile_rounding_mode) {
4872 int b =
static_cast<int>(1u <<
static_cast<unsigned int>(level));
4873 int level_size = toplevel_size / b;
4878 return std::max(level_size, 1);
4882 const OffsetData& offset_data,
4883 const std::vector<size_t>& channel_offset_list,
4884 int pixel_data_size,
4885 const unsigned char* head,
const size_t size,
4890 int num_y_tiles =
int(offset_data.offsets[
size_t(level_index)].size());
4891 if (num_y_tiles < 1) {
4894 int num_x_tiles =
int(offset_data.offsets[
size_t(level_index)][0].size());
4895 if (num_x_tiles < 1) {
4898 int num_tiles = num_x_tiles * num_y_tiles;
4904 EF_INVALID_DATA = 1,
4905 EF_INSUFFICIENT_DATA = 2,
4906 EF_FAILED_TO_DECODE = 4
4908#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
4909 std::atomic<unsigned> error_flag(EF_SUCCESS);
4911 unsigned error_flag(EF_SUCCESS);
4920 (*err) +=
"Failed to decode tile data.\n";
4926 calloc(
static_cast<size_t>(num_tiles),
sizeof(
EXRTile)));
4928#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
4929 std::vector<std::thread> workers;
4930 std::atomic<int> tile_count(0);
4932 int num_threads = std::max(1,
int(std::thread::hardware_concurrency()));
4933 if (num_threads >
int(num_tiles)) {
4934 num_threads =
int(num_tiles);
4937 for (
int t = 0; t < num_threads; t++) {
4938 workers.emplace_back(std::thread([&]()
4941 while ((tile_idx = tile_count++) < num_tiles) {
4944#if TINYEXR_USE_OPENMP
4945#pragma omp parallel for
4947 for (
int tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
4950 bool alloc_success =
false;
4951 exr_image->
tiles[tile_idx].
images = tinyexr::AllocateImage(
4952 num_channels, exr_header->
channels,
4956 if (!alloc_success) {
4957 error_flag |= EF_INVALID_DATA;
4961 int x_tile = tile_idx % num_x_tiles;
4962 int y_tile = tile_idx / num_x_tiles;
4966 tinyexr::tinyexr_uint64
offset = offset_data.offsets[size_t(level_index)][size_t(y_tile)][size_t(x_tile)];
4969 error_flag |= EF_INSUFFICIENT_DATA;
4975 const unsigned char* data_ptr =
4976 reinterpret_cast<const unsigned char*
>(head +
offset);
4978 int tile_coordinates[4];
4979 memcpy(tile_coordinates, data_ptr,
sizeof(
int) * 4);
4980 tinyexr::swap4(&tile_coordinates[0]);
4981 tinyexr::swap4(&tile_coordinates[1]);
4982 tinyexr::swap4(&tile_coordinates[2]);
4983 tinyexr::swap4(&tile_coordinates[3]);
4985 if (tile_coordinates[2] != exr_image->
level_x) {
4987 error_flag |= EF_INVALID_DATA;
4990 if (tile_coordinates[3] != exr_image->
level_y) {
4992 error_flag |= EF_INVALID_DATA;
4997 memcpy(&data_len, data_ptr + 16,
4999 tinyexr::swap4(&data_len);
5001 if (data_len < 2 ||
size_t(data_len) > data_size) {
5003 error_flag |= EF_INSUFFICIENT_DATA;
5009 bool ret = tinyexr::DecodeTiledPixelData(
5017 tile_coordinates[0], tile_coordinates[1], exr_header->
tile_size_x,
5018 exr_header->
tile_size_y,
static_cast<size_t>(pixel_data_size),
5022 exr_header->
channels, channel_offset_list);
5026 error_flag |= EF_FAILED_TO_DECODE;
5031 exr_image->
tiles[tile_idx].
level_x = tile_coordinates[2];
5032 exr_image->
tiles[tile_idx].
level_y = tile_coordinates[3];
5034#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
5039 for (
auto& t : workers) {
5049 exr_image->
num_tiles =
static_cast<int>(num_tiles);
5053 if (error_flag & EF_INSUFFICIENT_DATA) {
5054 (*err) +=
"Insufficient data length.\n";
5056 if (error_flag & EF_FAILED_TO_DECODE) {
5057 (*err) +=
"Failed to decode tile data.\n";
5064 const OffsetData& offset_data,
5065 const unsigned char *head,
const size_t size,
5069 int num_scanline_blocks = 1;
5071 num_scanline_blocks = 16;
5073 num_scanline_blocks = 32;
5075 num_scanline_blocks = 16;
5078 tinyexr::ZFPCompressionParam zfp_compression_param;
5079 if (!FindZFPCompressionParam(&zfp_compression_param,
5090 (*err) +=
"Invalid data window.\n";
5095 tinyexr_int64 data_width =
5097 tinyexr_int64 data_height =
5100 if (data_width <= 0) {
5102 (*err) +=
"Invalid data window width.\n";
5107 if (data_height <= 0) {
5109 (*err) +=
"Invalid data window height.\n";
5116 if ((data_width > TINYEXR_DIMENSION_THRESHOLD) || (data_height > TINYEXR_DIMENSION_THRESHOLD)) {
5118 std::stringstream ss;
5119 ss <<
"data_with or data_height too large. data_width: " << data_width
5121 <<
"data_height = " << data_height << std::endl;
5126 if (exr_header->
tiled) {
5127 if ((exr_header->
tile_size_x > TINYEXR_DIMENSION_THRESHOLD) || (exr_header->
tile_size_y > TINYEXR_DIMENSION_THRESHOLD)) {
5129 std::stringstream ss;
5130 ss <<
"tile with or tile height too large. tile width: " << exr_header->
tile_size_x
5132 <<
"tile height = " << exr_header->
tile_size_y << std::endl;
5140 const std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
5141 size_t num_blocks = offsets.size();
5143 std::vector<size_t> channel_offset_list;
5144 int pixel_data_size = 0;
5145 size_t channel_offset = 0;
5146 if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
5147 &channel_offset, num_channels,
5150 (*err) +=
"Failed to compute channel layout.\n";
5155#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
5156 std::atomic<bool> invalid_data(
false);
5158 bool invalid_data(
false);
5161 if (exr_header->
tiled) {
5165 std::stringstream ss;
5166 ss <<
"Invalid tile size x : " << exr_header->
tile_size_x <<
"\n";
5174 std::stringstream ss;
5175 ss <<
"Invalid tile size y : " << exr_header->
tile_size_y <<
"\n";
5182 for (
int level = 0; level < offset_data.num_x_levels; ++level) {
5184 level_image = exr_image;
5190 level_image->
width =
5192 if (level_image->
width < 1) {
5199 if (level_image->
height < 1) {
5206 int ret = DecodeTiledLevel(level_image, exr_header,
5208 channel_offset_list,
5216 for (
int level_y = 0; level_y < offset_data.num_y_levels; ++level_y)
5217 for (
int level_x = 0; level_x < offset_data.num_x_levels; ++level_x) {
5219 level_image = exr_image;
5226 level_image->
width =
5228 if (level_image->
width < 1) {
5234 if (level_image->
height < 1) {
5238 level_image->
level_x = level_x;
5239 level_image->
level_y = level_y;
5241 int ret = DecodeTiledLevel(level_image, exr_header,
5243 channel_offset_list,
5253 size_t total_data_len =
5254 size_t(data_width) * size_t(data_height) * size_t(num_channels);
5255 const bool total_data_len_overflown =
5256 sizeof(
void *) == 8 ? (total_data_len >= 0x4000000000) :
false;
5257 if ((total_data_len == 0) || total_data_len_overflown) {
5259 std::stringstream ss;
5260 ss <<
"Image data size is zero or too large: width = " << data_width
5261 <<
", height = " << data_height <<
", channels = " << num_channels
5268 bool alloc_success =
false;
5269 exr_image->
images = tinyexr::AllocateImage(
5271 int(data_width),
int(data_height), &alloc_success);
5273 if (!alloc_success) {
5275 std::stringstream ss;
5276 ss <<
"Failed to allocate memory for Images. Maybe EXR header is corrupted or Image data size is too large: width = " << data_width
5277 <<
", height = " << data_height <<
", channels = " << num_channels
5284#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
5285 std::vector<std::thread> workers;
5286 std::atomic<int> y_count(0);
5288 int num_threads = std::max(1,
int(std::thread::hardware_concurrency()));
5289 if (num_threads >
int(num_blocks)) {
5290 num_threads =
int(num_blocks);
5293 for (
int t = 0; t < num_threads; t++) {
5294 workers.emplace_back(std::thread([&]() {
5296 while ((
y = y_count++) <
int(num_blocks)) {
5300#if TINYEXR_USE_OPENMP
5301#pragma omp parallel for
5306 size_t y_idx =
static_cast<size_t>(
y);
5308 if (offsets[y_idx] +
sizeof(
int) * 2 >
size) {
5309 invalid_data =
true;
5315 size_t(
size - (offsets[y_idx] +
sizeof(
int) * 2));
5316 const unsigned char *data_ptr =
5317 reinterpret_cast<const unsigned char *
>(head + offsets[y_idx]);
5320 memcpy(&line_no, data_ptr,
sizeof(
int));
5322 memcpy(&data_len, data_ptr + 4,
sizeof(
int));
5323 tinyexr::swap4(&line_no);
5324 tinyexr::swap4(&data_len);
5326 if (
size_t(data_len) > data_size) {
5327 invalid_data =
true;
5329 }
else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) {
5332 invalid_data =
true;
5333 }
else if (data_len == 0) {
5336 invalid_data =
true;
5339 int end_line_no = (std::min)(line_no + num_scanline_blocks,
5342 int num_lines = end_line_no - line_no;
5344 if (num_lines <= 0) {
5345 invalid_data =
true;
5354 static_cast<tinyexr_int64
>(line_no) -
5356 if (lno > std::numeric_limits<int>::max()) {
5358 }
else if (lno < -std::numeric_limits<int>::max()) {
5365 invalid_data =
true;
5367 if (!tinyexr::DecodePixelData(
5369 data_ptr,
static_cast<size_t>(data_len),
5371 int(data_width),
int(data_height),
int(data_width),
y, line_no,
5372 num_lines,
static_cast<size_t>(pixel_data_size),
5373 static_cast<size_t>(
5377 exr_header->
channels, channel_offset_list)) {
5378 invalid_data =
true;
5385#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
5390 for (
auto &t : workers) {
5400 (*err) +=
"Invalid/Corrupted data found when decoding pixels.\n";
5404 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
5405 if (exr_image->
images[c]) {
5406 free(exr_image->
images[c]);
5407 exr_image->
images[c] = NULL;
5423 exr_image->
width =
int(data_width);
5430static bool ReconstructLineOffsets(
5431 std::vector<tinyexr::tinyexr_uint64> *offsets,
size_t n,
5432 const unsigned char *head,
const unsigned char *marker,
const size_t size) {
5433 if (head >= marker) {
5436 if (offsets->size() != n) {
5440 for (
size_t i = 0; i < n; i++) {
5441 size_t offset =
static_cast<size_t>(marker - head);
5443 if ((
offset +
sizeof(tinyexr::tinyexr_uint64)) >=
size) {
5448 unsigned int data_len;
5450 memcpy(&
y, marker,
sizeof(
int));
5451 memcpy(&data_len, marker + 4,
sizeof(
unsigned int));
5453 if (data_len >=
size) {
5458 tinyexr::swap4(&data_len);
5462 marker += data_len + 8;
5469static int FloorLog2(
unsigned x) {
5482static int CeilLog2(
unsigned x) {
5498static int RoundLog2(
int x,
int tile_rounding_mode) {
5499 return (tile_rounding_mode ==
TINYEXR_TILE_ROUND_DOWN) ? FloorLog2(
static_cast<unsigned>(
x)) : CeilLog2(static_cast<unsigned>(
x));
5502static int CalculateNumXLevels(
const EXRHeader* exr_header) {
5518 int w = max_x - min_x + 1;
5519 int h = max_y - min_y + 1;
5527 int w = max_x - min_x + 1;
5540static int CalculateNumYLevels(
const EXRHeader* exr_header) {
5556 int w = max_x - min_x + 1;
5557 int h = max_y - min_y + 1;
5565 int h = max_y - min_y + 1;
5578static bool CalculateNumTiles(std::vector<int>& numTiles,
5581 int tile_rounding_mode) {
5582 for (
unsigned i = 0; i < numTiles.size(); i++) {
5583 int l = LevelSize(toplevel_size,
int(i), tile_rounding_mode);
5587 TINYEXR_CHECK_AND_RETURN_C(l <= std::numeric_limits<int>::max() -
size + 1,
false);
5589 numTiles[i] = (l +
size - 1) /
size;
5594static bool PrecalculateTileInfo(std::vector<int>& num_x_tiles,
5595 std::vector<int>& num_y_tiles,
5602 int num_x_levels = CalculateNumXLevels(exr_header);
5604 if (num_x_levels < 0) {
5608 int num_y_levels = CalculateNumYLevels(exr_header);
5610 if (num_y_levels < 0) {
5614 num_x_tiles.resize(
size_t(num_x_levels));
5615 num_y_tiles.resize(
size_t(num_y_levels));
5617 if (!CalculateNumTiles(num_x_tiles,
5624 if (!CalculateNumTiles(num_y_tiles,
5634static void InitSingleResolutionOffsets(OffsetData& offset_data,
size_t num_blocks) {
5635 offset_data.offsets.resize(1);
5636 offset_data.offsets[0].resize(1);
5637 offset_data.offsets[0][0].resize(num_blocks);
5638 offset_data.num_x_levels = 1;
5639 offset_data.num_y_levels = 1;
5644static int InitTileOffsets(OffsetData& offset_data,
5646 const std::vector<int>& num_x_tiles,
5647 const std::vector<int>& num_y_tiles) {
5648 int num_tile_blocks = 0;
5649 offset_data.num_x_levels =
static_cast<int>(num_x_tiles.size());
5650 offset_data.num_y_levels =
static_cast<int>(num_y_tiles.size());
5654 TINYEXR_CHECK_AND_RETURN_C(offset_data.num_x_levels == offset_data.num_y_levels, 0);
5655 offset_data.offsets.resize(
size_t(offset_data.num_x_levels));
5657 for (
unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
5658 offset_data.offsets[l].resize(
size_t(num_y_tiles[l]));
5660 for (
unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
5661 offset_data.offsets[l][dy].resize(
size_t(num_x_tiles[l]));
5662 num_tile_blocks += num_x_tiles[l];
5669 offset_data.offsets.resize(
static_cast<size_t>(offset_data.num_x_levels) *
static_cast<size_t>(offset_data.num_y_levels));
5671 for (
int ly = 0; ly < offset_data.num_y_levels; ++ly) {
5672 for (
int lx = 0; lx < offset_data.num_x_levels; ++lx) {
5673 int l = ly * offset_data.num_x_levels + lx;
5674 offset_data.offsets[size_t(l)].resize(
size_t(num_y_tiles[
size_t(ly)]));
5676 for (
size_t dy = 0; dy < offset_data.offsets[size_t(l)].size(); ++dy) {
5677 offset_data.offsets[size_t(l)][dy].resize(
size_t(num_x_tiles[
size_t(lx)]));
5678 num_tile_blocks += num_x_tiles[size_t(lx)];
5687 return num_tile_blocks;
5690static bool IsAnyOffsetsAreInvalid(
const OffsetData& offset_data) {
5691 for (
unsigned int l = 0; l < offset_data.offsets.size(); ++l)
5692 for (
unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy)
5693 for (
unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx)
5694 if (
reinterpret_cast<const tinyexr::tinyexr_int64&
>(offset_data.offsets[l][dy][dx]) <= 0)
5700static bool isValidTile(
const EXRHeader* exr_header,
5701 const OffsetData& offset_data,
5702 int dx,
int dy,
int lx,
int ly) {
5703 if (lx < 0 || ly < 0 || dx < 0 || dy < 0)
return false;
5704 int num_x_levels = offset_data.num_x_levels;
5705 int num_y_levels = offset_data.num_y_levels;
5711 offset_data.offsets.size() > 0 &&
5712 offset_data.offsets[0].size() >
static_cast<size_t>(dy) &&
5713 offset_data.offsets[0][
size_t(dy)].size() >
static_cast<size_t>(dx)) {
5721 if (lx < num_x_levels &&
5722 ly < num_y_levels &&
5723 offset_data.offsets.size() >
static_cast<size_t>(lx) &&
5724 offset_data.offsets[
size_t(lx)].size() >
static_cast<size_t>(dy) &&
5725 offset_data.offsets[
size_t(lx)][
size_t(dy)].size() >
static_cast<size_t>(dx)) {
5733 size_t idx =
static_cast<size_t>(lx) +
static_cast<size_t>(ly)*
static_cast<size_t>(num_x_levels);
5734 if (lx < num_x_levels &&
5735 ly < num_y_levels &&
5736 (offset_data.offsets.size() > idx) &&
5737 offset_data.offsets[idx].size() >
static_cast<size_t>(dy) &&
5738 offset_data.offsets[idx][
size_t(dy)].size() >
static_cast<size_t>(dx)) {
5753static bool ReconstructTileOffsets(OffsetData& offset_data,
5755 const unsigned char* head,
const unsigned char* marker,
const size_t size,
5756 bool isMultiPartFile,
5758 int numXLevels = offset_data.num_x_levels;
5759 for (
unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
5760 for (
unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
5761 for (
unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
5762 tinyexr::tinyexr_uint64 tileOffset = tinyexr::tinyexr_uint64(marker - head);
5765 if (isMultiPartFile) {
5766 if ((marker +
sizeof(
int)) >= (head +
size)) {
5771 marker +=
sizeof(
int);
5774 if ((marker + 4 *
sizeof(
int)) >= (head +
size)) {
5779 memcpy(&tileX, marker,
sizeof(
int));
5780 tinyexr::swap4(&tileX);
5781 marker +=
sizeof(
int);
5784 memcpy(&tileY, marker,
sizeof(
int));
5785 tinyexr::swap4(&tileY);
5786 marker +=
sizeof(
int);
5789 memcpy(&levelX, marker,
sizeof(
int));
5790 tinyexr::swap4(&levelX);
5791 marker +=
sizeof(
int);
5794 memcpy(&levelY, marker,
sizeof(
int));
5795 tinyexr::swap4(&levelY);
5796 marker +=
sizeof(
int);
5799 if ((marker + 2 *
sizeof(tinyexr::tinyexr_int64)) >= (head +
size)) {
5802 tinyexr::tinyexr_int64 packed_offset_table_size;
5803 memcpy(&packed_offset_table_size, marker,
sizeof(tinyexr::tinyexr_int64));
5804 tinyexr::swap8(
reinterpret_cast<tinyexr::tinyexr_uint64*
>(&packed_offset_table_size));
5805 marker +=
sizeof(tinyexr::tinyexr_int64);
5807 tinyexr::tinyexr_int64 packed_sample_size;
5808 memcpy(&packed_sample_size, marker,
sizeof(tinyexr::tinyexr_int64));
5809 tinyexr::swap8(
reinterpret_cast<tinyexr::tinyexr_uint64*
>(&packed_sample_size));
5810 marker +=
sizeof(tinyexr::tinyexr_int64);
5813 marker += packed_offset_table_size + packed_sample_size + 8;
5815 if (marker >= (head +
size)) {
5821 if ((marker +
sizeof(uint32_t)) >= (head +
size)) {
5826 memcpy(&dataSize, marker,
sizeof(uint32_t));
5827 tinyexr::swap4(&dataSize);
5828 marker +=
sizeof(uint32_t);
5832 if (marker >= (head +
size)) {
5837 if (!isValidTile(exr_header, offset_data,
5838 tileX, tileY, levelX, levelY)) {
5842 int level_idx = LevelIndex(levelX, levelY, exr_header->
tile_level_mode, numXLevels);
5843 if (level_idx < 0) {
5847 if (
size_t(level_idx) >= offset_data.offsets.size()) {
5851 if (
size_t(tileY) >= offset_data.offsets[
size_t(level_idx)].size()) {
5855 if (
size_t(tileX) >= offset_data.offsets[
size_t(level_idx)][
size_t(tileY)].size()) {
5859 offset_data.offsets[size_t(level_idx)][size_t(tileY)][size_t(tileX)] = tileOffset;
5867static int ReadOffsets(OffsetData& offset_data,
5868 const unsigned char* head,
5869 const unsigned char*& marker,
5872 for (
unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
5873 for (
unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
5874 for (
unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
5875 tinyexr::tinyexr_uint64
offset;
5876 if ((marker +
sizeof(tinyexr_uint64)) >= (head +
size)) {
5877 tinyexr::SetErrorMessage(
"Insufficient data size in offset table.", err);
5881 memcpy(&
offset, marker,
sizeof(tinyexr::tinyexr_uint64));
5884 tinyexr::SetErrorMessage(
"Invalid offset value in DecodeEXRImage.", err);
5887 marker +=
sizeof(tinyexr::tinyexr_uint64);
5888 offset_data.offsets[l][dy][dx] =
offset;
5896 const unsigned char *head,
5897 const unsigned char *marker,
const size_t size,
5899 if (exr_image == NULL || exr_header == NULL || head == NULL ||
5900 marker == NULL || (
size <= tinyexr::kEXRVersionSize)) {
5901 tinyexr::SetErrorMessage(
"Invalid argument for DecodeEXRImage().", err);
5905 int num_scanline_blocks = 1;
5907 num_scanline_blocks = 16;
5909 num_scanline_blocks = 32;
5911 num_scanline_blocks = 16;
5916 std::numeric_limits<int>::max()) {
5918 tinyexr::SetErrorMessage(
"Invalid data width value", err);
5921 tinyexr_int64 data_width =
5923 if (data_width <= 0) {
5924 tinyexr::SetErrorMessage(
"Invalid data window width value", err);
5930 std::numeric_limits<int>::max()) {
5931 tinyexr::SetErrorMessage(
"Invalid data height value", err);
5934 tinyexr_int64 data_height =
5937 if (data_height <= 0) {
5938 tinyexr::SetErrorMessage(
"Invalid data window height value", err);
5944 if (data_width > TINYEXR_DIMENSION_THRESHOLD) {
5945 tinyexr::SetErrorMessage(
"data width too large.", err);
5948 if (data_height > TINYEXR_DIMENSION_THRESHOLD) {
5949 tinyexr::SetErrorMessage(
"data height too large.", err);
5954 if (exr_header->
tiled) {
5955 if (exr_header->
tile_size_x > TINYEXR_DIMENSION_THRESHOLD) {
5956 tinyexr::SetErrorMessage(
"tile width too large.", err);
5959 if (exr_header->
tile_size_y > TINYEXR_DIMENSION_THRESHOLD) {
5960 tinyexr::SetErrorMessage(
"tile height too large.", err);
5966 OffsetData offset_data;
5967 size_t num_blocks = 0;
5970 if (exr_header->
tiled) {
5972 std::vector<int> num_x_tiles, num_y_tiles;
5973 if (!PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_header)) {
5974 tinyexr::SetErrorMessage(
"Failed to precalculate tile info.", err);
5977 num_blocks = size_t(InitTileOffsets(offset_data, exr_header, num_x_tiles, num_y_tiles));
5979 if (exr_header->
chunk_count !=
static_cast<int>(num_blocks)) {
5980 tinyexr::SetErrorMessage(
"Invalid offset table size.", err);
5986 int ret = ReadOffsets(offset_data, head, marker,
size, err);
5988 if (IsAnyOffsetsAreInvalid(offset_data)) {
5989 if (!ReconstructTileOffsets(offset_data, exr_header,
5993 tinyexr::SetErrorMessage(
"Invalid Tile Offsets data.", err);
5999 num_blocks =
static_cast<size_t>(exr_header->
chunk_count);
6000 InitSingleResolutionOffsets(offset_data, num_blocks);
6002 num_blocks =
static_cast<size_t>(data_height) /
6003 static_cast<size_t>(num_scanline_blocks);
6004 if (num_blocks *
static_cast<size_t>(num_scanline_blocks) <
6005 static_cast<size_t>(data_height)) {
6009 InitSingleResolutionOffsets(offset_data, num_blocks);
6012 if (!exr_header->
tiled) {
6013 std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
6014 for (
size_t y = 0;
y < num_blocks;
y++) {
6015 tinyexr::tinyexr_uint64
offset;
6017 if ((marker +
sizeof(tinyexr_uint64)) >= (head +
size)) {
6018 tinyexr::SetErrorMessage(
"Insufficient data size in offset table.", err);
6022 memcpy(&
offset, marker,
sizeof(tinyexr::tinyexr_uint64));
6025 tinyexr::SetErrorMessage(
"Invalid offset value in DecodeEXRImage.", err);
6028 marker +=
sizeof(tinyexr::tinyexr_uint64);
6034 for (
size_t y = 0;
y < num_blocks;
y++) {
6035 if (offsets[
y] <= 0) {
6043 ReconstructLineOffsets(&offsets, num_blocks, head, marker,
size);
6048 tinyexr::SetErrorMessage(
6049 "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
6058 int ret = DecodeChunk(exr_image, exr_header, offset_data, head,
size, &e);
6062 tinyexr::SetErrorMessage(e, err);
6070 for (
size_t c = 0; c < size_t(exr_header->
num_channels); c++) {
6071 if (exr_image->
images[c]) {
6072 free(exr_image->
images[c]);
6073 exr_image->
images[c] = NULL;
6077 exr_image->
images = NULL;
6086static void GetLayers(
const EXRHeader &exr_header,
6087 std::vector<std::string> &layer_names) {
6092 layer_names.clear();
6095 const size_t pos = full_name.find_last_of(
'.');
6096 if (pos != std::string::npos && pos != 0 && pos + 1 < full_name.size()) {
6097 full_name.erase(pos);
6098 if (std::find(layer_names.begin(), layer_names.end(), full_name) ==
6100 layer_names.push_back(full_name);
6105struct LayerChannel {
6106 explicit LayerChannel(
size_t i, std::string n) : index(i), name(n) {}
6111static void ChannelsInLayer(
const EXRHeader &exr_header,
6112 const std::string &layer_name,
6113 std::vector<LayerChannel> &channels) {
6119 if (layer_name.empty()) {
6120 const size_t pos = ch_name.find_last_of(
'.');
6121 if (pos != std::string::npos && pos < ch_name.size()) {
6122 if (pos != 0)
continue;
6123 ch_name = ch_name.substr(pos + 1);
6126 const size_t pos = ch_name.find(layer_name +
'.');
6127 if (pos == std::string::npos)
continue;
6129 ch_name = ch_name.substr(layer_name.size() + 1);
6132 LayerChannel ch(
size_t(c), ch_name);
6133 channels.push_back(ch);
6148 tinyexr::SetErrorMessage(
"Invalid EXR header.", err);
6153 tinyexr::SetErrorMessage(
6154 "Loading multipart or DeepImage is not supported in LoadEXR() API",
6166 std::vector<std::string> layer_vec;
6167 tinyexr::GetLayers(exr_header, layer_vec);
6169 (*num_layers) =
int(layer_vec.size());
6170 (*layer_names) =
static_cast<const char **
>(
6171 malloc(
sizeof(
const char *) *
static_cast<size_t>(layer_vec.size())));
6172 for (
size_t c = 0; c < static_cast<size_t>(layer_vec.size()); c++) {
6174 (*layer_names)[c] = _strdup(layer_vec[c].c_str());
6176 (*layer_names)[c] = strdup(layer_vec[c].c_str());
6184int LoadEXR(
float **out_rgba,
int *width,
int *height,
const char *
filename,
6191 const char *
filename,
const char *layername,
6193 if (out_rgba == NULL) {
6194 tinyexr::SetErrorMessage(
"Invalid argument for LoadEXR()", err);
6207 std::stringstream ss;
6208 ss <<
"Failed to open EXR file or read version info from EXR file. code("
6210 tinyexr::SetErrorMessage(ss.str(), err);
6215 tinyexr::SetErrorMessage(
6216 "Loading multipart or DeepImage is not supported in LoadEXR() API",
6252 std::vector<std::string> layer_names;
6253 tinyexr::GetLayers(exr_header, layer_names);
6255 std::vector<tinyexr::LayerChannel> channels;
6256 tinyexr::ChannelsInLayer(
6257 exr_header, layername == NULL ?
"" : std::string(layername), channels);
6260 if (channels.size() < 1) {
6261 if (layername == NULL) {
6262 tinyexr::SetErrorMessage(
"Layer Not Found. Seems EXR contains channels with layer(e.g. `diffuse.R`). if you are using LoadEXR(), please try LoadEXRWithLayer(). LoadEXR() cannot load EXR having channels with layer.", err);
6265 tinyexr::SetErrorMessage(
"Layer Not Found", err);
6272 size_t ch_count = channels.size() < 4 ? channels.size() : 4;
6273 for (
size_t c = 0; c < ch_count; c++) {
6274 const tinyexr::LayerChannel &ch = channels[c];
6276 if (ch.name ==
"R") {
6277 idxR =
int(ch.index);
6278 }
else if (ch.name ==
"G") {
6279 idxG =
int(ch.index);
6280 }
else if (ch.name ==
"B") {
6281 idxB =
int(ch.index);
6282 }
else if (ch.name ==
"A") {
6283 idxA =
int(ch.index);
6287 if (channels.size() == 1) {
6288 int chIdx =
int(channels.front().index);
6291 (*out_rgba) =
reinterpret_cast<float *
>(
6292 malloc(4 *
sizeof(
float) *
static_cast<size_t>(exr_image.
width) *
6293 static_cast<size_t>(exr_image.
height)));
6295 if (exr_header.
tiled) {
6296 const size_t tile_size_x =
static_cast<size_t>(exr_header.
tile_size_x);
6297 const size_t tile_size_y =
static_cast<size_t>(exr_header.
tile_size_y);
6298 for (
int it = 0; it < exr_image.
num_tiles; it++) {
6299 for (
size_t j = 0; j < tile_size_y; j++) {
6300 for (
size_t i = 0; i < tile_size_x; i++) {
6302 static_cast<size_t>(exr_image.
tiles[it].
offset_x) * tile_size_x +
6305 static_cast<size_t>(exr_image.
tiles[it].
offset_y) * tile_size_y +
6307 const size_t idx = ii + jj *
static_cast<size_t>(exr_image.
width);
6310 if (ii >=
static_cast<size_t>(exr_image.
width)) {
6313 if (jj >=
static_cast<size_t>(exr_image.
height)) {
6316 const size_t srcIdx = i + j * tile_size_x;
6318 (*out_rgba)[4 * idx + 0] =
6319 reinterpret_cast<float **
>(src)[chIdx][srcIdx];
6320 (*out_rgba)[4 * idx + 1] =
6321 reinterpret_cast<float **
>(src)[chIdx][srcIdx];
6322 (*out_rgba)[4 * idx + 2] =
6323 reinterpret_cast<float **
>(src)[chIdx][srcIdx];
6324 (*out_rgba)[4 * idx + 3] =
6325 reinterpret_cast<float **
>(src)[chIdx][srcIdx];
6330 const size_t pixel_size =
static_cast<size_t>(exr_image.
width) *
6331 static_cast<size_t>(exr_image.
height);
6332 for (
size_t i = 0; i < pixel_size; i++) {
6334 reinterpret_cast<float **
>(exr_image.
images)[chIdx][i];
6335 (*out_rgba)[4 * i + 0] = val;
6336 (*out_rgba)[4 * i + 1] = val;
6337 (*out_rgba)[4 * i + 2] = val;
6338 (*out_rgba)[4 * i + 3] = val;
6345 tinyexr::SetErrorMessage(
"R channel not found", err);
6353 tinyexr::SetErrorMessage(
"G channel not found", err);
6360 tinyexr::SetErrorMessage(
"B channel not found", err);
6366 (*out_rgba) =
reinterpret_cast<float *
>(
6367 malloc(4 *
sizeof(
float) *
static_cast<size_t>(exr_image.
width) *
6368 static_cast<size_t>(exr_image.
height)));
6369 if (exr_header.
tiled) {
6370 const size_t tile_size_x =
static_cast<size_t>(exr_header.
tile_size_x);
6371 const size_t tile_size_y =
static_cast<size_t>(exr_header.
tile_size_y);
6372 for (
int it = 0; it < exr_image.
num_tiles; it++) {
6373 for (
size_t j = 0; j < tile_size_y; j++) {
6374 for (
size_t i = 0; i < tile_size_x; i++) {
6383 const size_t idx = ii + jj *
static_cast<size_t>(exr_image.
width);
6386 if (ii >=
static_cast<size_t>(exr_image.
width)) {
6389 if (jj >=
static_cast<size_t>(exr_image.
height)) {
6392 const size_t srcIdx = i + j * tile_size_x;
6394 (*out_rgba)[4 * idx + 0] =
6395 reinterpret_cast<float **
>(src)[idxR][srcIdx];
6396 (*out_rgba)[4 * idx + 1] =
6397 reinterpret_cast<float **
>(src)[idxG][srcIdx];
6398 (*out_rgba)[4 * idx + 2] =
6399 reinterpret_cast<float **
>(src)[idxB][srcIdx];
6401 (*out_rgba)[4 * idx + 3] =
6402 reinterpret_cast<float **
>(src)[idxA][srcIdx];
6404 (*out_rgba)[4 * idx + 3] = 1.0;
6410 const size_t pixel_size =
static_cast<size_t>(exr_image.
width) *
6411 static_cast<size_t>(exr_image.
height);
6412 for (
size_t i = 0; i < pixel_size; i++) {
6413 (*out_rgba)[4 * i + 0] =
6414 reinterpret_cast<float **
>(exr_image.
images)[idxR][i];
6415 (*out_rgba)[4 * i + 1] =
6416 reinterpret_cast<float **
>(exr_image.
images)[idxG][i];
6417 (*out_rgba)[4 * i + 2] =
6418 reinterpret_cast<float **
>(exr_image.
images)[idxB][i];
6420 (*out_rgba)[4 * i + 3] =
6421 reinterpret_cast<float **
>(exr_image.
images)[idxA][i];
6423 (*out_rgba)[4 * i + 3] = 1.0;
6429 (*width) = exr_image.
width;
6430 (*height) = exr_image.
height;
6461 const unsigned char *memory,
size_t size,
6463 if (memory == NULL || exr_header == NULL) {
6464 tinyexr::SetErrorMessage(
6465 "Invalid argument. `memory` or `exr_header` argument is null in "
6466 "ParseEXRHeaderFromMemory()",
6473 if (
size < tinyexr::kEXRVersionSize) {
6474 tinyexr::SetErrorMessage(
"Insufficient header/data size.\n", err);
6478 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
6479 size_t marker_size =
size - tinyexr::kEXRVersionSize;
6481 tinyexr::HeaderInfo info;
6486 std::string err_str;
6487 ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size);
6490 if (err && !err_str.empty()) {
6491 tinyexr::SetErrorMessage(err_str, err);
6498 std::string err_str;
6500 if (!ConvertHeader(exr_header, info, &warn, &err_str)) {
6502 for (
size_t i = 0; i < info.attributes.size(); i++) {
6503 if (info.attributes[i].value) {
6504 free(info.attributes[i].value);
6507 if (err && !err_str.empty()) {
6508 tinyexr::SetErrorMessage(err_str, err);
6521 const unsigned char *memory,
size_t size,
6523 if (out_rgba == NULL || memory == NULL) {
6524 tinyexr::SetErrorMessage(
"Invalid argument for LoadEXRFromMemory", err);
6536 std::stringstream ss;
6537 ss <<
"Failed to parse EXR version. code(" << ret <<
")";
6538 tinyexr::SetErrorMessage(ss.str(), err);
6568 }
else if (strcmp(exr_header.
channels[c].
name,
"G") == 0) {
6570 }
else if (strcmp(exr_header.
channels[c].
name,
"B") == 0) {
6572 }
else if (strcmp(exr_header.
channels[c].
name,
"A") == 0) {
6581 (*out_rgba) =
reinterpret_cast<float *
>(
6582 malloc(4 *
sizeof(
float) *
static_cast<size_t>(exr_image.
width) *
6583 static_cast<size_t>(exr_image.
height)));
6585 if (exr_header.
tiled) {
6586 const size_t tile_size_x =
static_cast<size_t>(exr_header.
tile_size_x);
6587 const size_t tile_size_y =
static_cast<size_t>(exr_header.
tile_size_y);
6588 for (
int it = 0; it < exr_image.
num_tiles; it++) {
6589 for (
size_t j = 0; j < tile_size_y; j++) {
6590 for (
size_t i = 0; i < tile_size_x; i++) {
6599 const size_t idx = ii + jj *
static_cast<size_t>(exr_image.
width);
6602 if (ii >=
static_cast<size_t>(exr_image.
width)) {
6605 if (jj >=
static_cast<size_t>(exr_image.
height)) {
6608 const size_t srcIdx = i + j * tile_size_x;
6610 (*out_rgba)[4 * idx + 0] =
6611 reinterpret_cast<float **
>(src)[0][srcIdx];
6612 (*out_rgba)[4 * idx + 1] =
6613 reinterpret_cast<float **
>(src)[0][srcIdx];
6614 (*out_rgba)[4 * idx + 2] =
6615 reinterpret_cast<float **
>(src)[0][srcIdx];
6616 (*out_rgba)[4 * idx + 3] =
6617 reinterpret_cast<float **
>(src)[0][srcIdx];
6622 const size_t pixel_size =
static_cast<size_t>(exr_image.
width) *
6623 static_cast<size_t>(exr_image.
height);
6624 for (
size_t i = 0; i < pixel_size; i++) {
6625 const float val =
reinterpret_cast<float **
>(exr_image.
images)[0][i];
6626 (*out_rgba)[4 * i + 0] = val;
6627 (*out_rgba)[4 * i + 1] = val;
6628 (*out_rgba)[4 * i + 2] = val;
6629 (*out_rgba)[4 * i + 3] = val;
6637 tinyexr::SetErrorMessage(
"R channel not found", err);
6644 tinyexr::SetErrorMessage(
"G channel not found", err);
6650 tinyexr::SetErrorMessage(
"B channel not found", err);
6655 (*out_rgba) =
reinterpret_cast<float *
>(
6656 malloc(4 *
sizeof(
float) *
static_cast<size_t>(exr_image.
width) *
6657 static_cast<size_t>(exr_image.
height)));
6659 if (exr_header.
tiled) {
6660 const size_t tile_size_x =
static_cast<size_t>(exr_header.
tile_size_x);
6661 const size_t tile_size_y =
static_cast<size_t>(exr_header.
tile_size_y);
6662 for (
int it = 0; it < exr_image.
num_tiles; it++) {
6663 for (
size_t j = 0; j < tile_size_y; j++)
6664 for (
size_t i = 0; i < tile_size_x; i++) {
6673 const size_t idx = ii + jj *
static_cast<size_t>(exr_image.
width);
6676 if (ii >=
static_cast<size_t>(exr_image.
width)) {
6679 if (jj >=
static_cast<size_t>(exr_image.
height)) {
6682 const size_t srcIdx = i + j * tile_size_x;
6684 (*out_rgba)[4 * idx + 0] =
6685 reinterpret_cast<float **
>(src)[idxR][srcIdx];
6686 (*out_rgba)[4 * idx + 1] =
6687 reinterpret_cast<float **
>(src)[idxG][srcIdx];
6688 (*out_rgba)[4 * idx + 2] =
6689 reinterpret_cast<float **
>(src)[idxB][srcIdx];
6691 (*out_rgba)[4 * idx + 3] =
6692 reinterpret_cast<float **
>(src)[idxA][srcIdx];
6694 (*out_rgba)[4 * idx + 3] = 1.0;
6699 const size_t pixel_size =
static_cast<size_t>(exr_image.
width) *
6700 static_cast<size_t>(exr_image.
height);
6701 for (
size_t i = 0; i < pixel_size; i++) {
6702 (*out_rgba)[4 * i + 0] =
6703 reinterpret_cast<float **
>(exr_image.
images)[idxR][i];
6704 (*out_rgba)[4 * i + 1] =
6705 reinterpret_cast<float **
>(exr_image.
images)[idxG][i];
6706 (*out_rgba)[4 * i + 2] =
6707 reinterpret_cast<float **
>(exr_image.
images)[idxB][i];
6709 (*out_rgba)[4 * i + 3] =
6710 reinterpret_cast<float **
>(exr_image.
images)[idxA][i];
6712 (*out_rgba)[4 * i + 3] = 1.0;
6718 (*width) = exr_image.
width;
6719 (*height) = exr_image.
height;
6730struct MemoryMappedFile {
6731 unsigned char *data;
6733#ifdef TINYEXR_USE_WIN32_MMAP
6734 HANDLE windows_file;
6735 HANDLE windows_file_mapping;
6736#elif defined(TINYEXR_USE_POSIX_MMAP)
6737 int posix_descriptor;
6743 MemoryMappedFile(
const char *
filename) {
6746#ifdef TINYEXR_USE_WIN32_MMAP
6747 windows_file_mapping = NULL;
6749 CreateFileW(tinyexr::UTF8ToWchar(
filename).c_str(),
6754 FILE_ATTRIBUTE_READONLY,
6756 if (windows_file == INVALID_HANDLE_VALUE) {
6760 windows_file_mapping = CreateFileMapping(windows_file,
6766 if (windows_file_mapping == NULL) {
6770 data =
reinterpret_cast<unsigned char *
>(
6771 MapViewOfFile(windows_file_mapping,
6780 LARGE_INTEGER windows_file_size = {};
6781 if (!GetFileSizeEx(windows_file, &windows_file_size) ||
6782 static_cast<ULONGLONG
>(windows_file_size.QuadPart) >
6783 std::numeric_limits<size_t>::max()) {
6784 UnmapViewOfFile(data);
6788 size =
static_cast<size_t>(windows_file_size.QuadPart);
6789#elif defined(TINYEXR_USE_POSIX_MMAP)
6790 posix_descriptor = open(
filename, O_RDONLY);
6791 if (posix_descriptor == -1) {
6796 if (fstat(posix_descriptor, &info) < 0) {
6806#pragma clang diagnostic push
6807#pragma clang diagnostic ignored "-Wtautological-type-limit-compare"
6809 if (info.st_size < 0 ||
6810 info.st_size > std::numeric_limits<ssize_t>::max()) {
6814#pragma clang diagnostic pop
6816 size =
static_cast<size_t>(info.st_size);
6818 data =
reinterpret_cast<unsigned char *
>(
6819 mmap(0,
size, PROT_READ, MAP_SHARED, posix_descriptor, 0));
6820 if (data == MAP_FAILED) {
6833 if (fseek(fp, 0, SEEK_END) != 0) {
6837 const long ftell_result = ftell(fp);
6838 if (ftell_result < 0) {
6843 size =
static_cast<size_t>(ftell_result);
6844 if (fseek(fp, 0, SEEK_SET) != 0) {
6850 data =
reinterpret_cast<unsigned char *
>(malloc(
size));
6856 size_t read_bytes = fread(data, 1,
size, fp);
6857 if (read_bytes !=
size) {
6869 ~MemoryMappedFile() {
6870#ifdef TINYEXR_USE_WIN32_MMAP
6872 (void)UnmapViewOfFile(data);
6876 if (windows_file_mapping != NULL) {
6877 (void)CloseHandle(windows_file_mapping);
6880 if (windows_file != INVALID_HANDLE_VALUE) {
6881 (void)CloseHandle(windows_file);
6883#elif defined(TINYEXR_USE_POSIX_MMAP)
6885 (void)munmap(data,
size);
6889 if (posix_descriptor != -1) {
6890 (void)close(posix_descriptor);
6903#if TINYEXR_HAS_CXX11
6905#pragma clang diagnostic push
6906#pragma clang diagnostic ignored "-Wc++98-compat"
6908 MemoryMappedFile(
const MemoryMappedFile &) =
delete;
6909 MemoryMappedFile &operator=(
const MemoryMappedFile &) =
delete;
6910 MemoryMappedFile(MemoryMappedFile &&other)
noexcept =
delete;
6911 MemoryMappedFile &operator=(MemoryMappedFile &&other)
noexcept =
delete;
6913#pragma clang diagnostic pop
6918 bool valid()
const {
return data; }
6922 const char *
filename,
const char **err) {
6923 if (exr_image == NULL) {
6924 tinyexr::SetErrorMessage(
"Invalid argument for LoadEXRImageFromFile", err);
6929 if (!file.valid()) {
6930 tinyexr::SetErrorMessage(
"Cannot read file " + std::string(
filename), err);
6934 if (file.size < 16) {
6935 tinyexr::SetErrorMessage(
"File size too short : " + std::string(
filename),
6945 const unsigned char *memory,
const size_t size,
6947 if (exr_image == NULL || memory == NULL ||
6948 (
size < tinyexr::kEXRVersionSize)) {
6949 tinyexr::SetErrorMessage(
"Invalid argument for LoadEXRImageFromMemory",
6955 tinyexr::SetErrorMessage(
"EXRHeader variable is not initialized.", err);
6959 const unsigned char *head = memory;
6960 const unsigned char *marker =
reinterpret_cast<const unsigned char *
>(
6963 return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker,
size,
6971#pragma clang diagnostic push
6972#pragma clang diagnostic ignored "-Wsign-conversion"
6977static bool EncodePixelData( std::vector<unsigned char>& out_data,
6978 const unsigned char*
const* images,
6979 int compression_type,
6986 size_t pixel_data_size,
6987 const std::vector<ChannelInfo>& channels,
6988 const std::vector<size_t>& channel_offset_list,
6990 const void* compression_param = 0)
6992 size_t buf_size =
static_cast<size_t>(width) *
6993 static_cast<size_t>(num_lines) *
6994 static_cast<size_t>(pixel_data_size);
6998 std::vector<unsigned char>
buf(buf_size);
7000 size_t start_y =
static_cast<size_t>(line_no);
7001 for (
size_t c = 0; c < channels.size(); c++) {
7004 for (
int y = 0;
y < num_lines;
y++) {
7006 float *line_ptr =
reinterpret_cast<float *
>(&
buf.at(
7007 static_cast<size_t>(pixel_data_size *
size_t(
y) *
size_t(width)) +
7008 channel_offset_list[c] *
7009 static_cast<size_t>(width)));
7010 for (
int x = 0;
x < width;
x++) {
7012 h16.u =
reinterpret_cast<const unsigned short *
const *
>(
7013 images)[c][(
y + start_y) * size_t(x_stride) + size_t(
x)];
7015 tinyexr::FP32 f32 = half_to_float(h16);
7017 tinyexr::swap4(&f32.f);
7020 tinyexr::cpy4(line_ptr +
x, &(f32.f));
7024 for (
int y = 0;
y < num_lines;
y++) {
7026 unsigned short *line_ptr =
reinterpret_cast<unsigned short *
>(
7027 &
buf.at(
static_cast<size_t>(pixel_data_size *
y *
7029 channel_offset_list[c] *
7030 static_cast<size_t>(width)));
7031 for (
int x = 0;
x < width;
x++) {
7032 unsigned short val =
reinterpret_cast<const unsigned short *
const *
>(
7033 images)[c][(
y + start_y) * x_stride +
x];
7035 tinyexr::swap2(&val);
7038 tinyexr::cpy2(line_ptr +
x, &val);
7043 (*err) +=
"Invalid requested_pixel_type.\n";
7050 for (
int y = 0;
y < num_lines;
y++) {
7052 unsigned short *line_ptr =
reinterpret_cast<unsigned short *
>(
7053 &
buf.at(
static_cast<size_t>(pixel_data_size *
y *
7055 channel_offset_list[c] *
7056 static_cast<size_t>(width)));
7057 for (
int x = 0;
x < width;
x++) {
7059 f32.f =
reinterpret_cast<const float *
const *
>(
7060 images)[c][(
y + start_y) * x_stride +
x];
7063 h16 = float_to_half_full(f32);
7065 tinyexr::swap2(
reinterpret_cast<unsigned short *
>(&h16.u));
7068 tinyexr::cpy2(line_ptr +
x, &(h16.u));
7072 for (
int y = 0;
y < num_lines;
y++) {
7074 float *line_ptr =
reinterpret_cast<float *
>(&
buf.at(
7075 static_cast<size_t>(pixel_data_size *
y * width) +
7076 channel_offset_list[c] *
7077 static_cast<size_t>(width)));
7078 for (
int x = 0;
x < width;
x++) {
7079 float val =
reinterpret_cast<const float *
const *
>(
7080 images)[c][(
y + start_y) * x_stride +
x];
7082 tinyexr::swap4(&val);
7085 tinyexr::cpy4(line_ptr +
x, &val);
7090 (*err) +=
"Invalid requested_pixel_type.\n";
7095 for (
int y = 0;
y < num_lines;
y++) {
7097 unsigned int *line_ptr =
reinterpret_cast<unsigned int *
>(&
buf.at(
7098 static_cast<size_t>(pixel_data_size *
y * width) +
7099 channel_offset_list[c] *
static_cast<size_t>(width)));
7100 for (
int x = 0;
x < width;
x++) {
7101 unsigned int val =
reinterpret_cast<const unsigned int *
const *
>(
7102 images)[c][(
y + start_y) * x_stride +
x];
7104 tinyexr::swap4(&val);
7107 tinyexr::cpy4(line_ptr +
x, &val);
7117 out_data.insert(out_data.end(),
buf.begin(),
buf.end());
7121#if defined(TINYEXR_USE_MINIZ) && (TINYEXR_USE_MINIZ==1)
7123 static_cast<unsigned long>(
buf.size())));
7124#elif TINYEXR_USE_STB_ZLIB
7127 std::vector<unsigned char> block(256 + 2 *
buf.size());
7128#elif defined(TINYEXR_USE_NANOZLIB) && (TINYEXR_USE_NANOZLIB == 1)
7129 std::vector<unsigned char> block(nanoz_compressBound(
7130 static_cast<unsigned long>(
buf.size())));
7132 std::vector<unsigned char> block(
7135 tinyexr::tinyexr_uint64 outSize = block.size();
7137 if (!tinyexr::CompressZip(&block.at(0), outSize,
7138 reinterpret_cast<const unsigned char *
>(&
buf.at(0)),
7139 static_cast<unsigned long>(
buf.size()))) {
7141 (*err) +=
"Zip compresssion failed.\n";
7149 unsigned int data_len =
static_cast<unsigned int>(outSize);
7151 out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
7155 std::vector<unsigned char> block((
buf.size() * 3) / 2);
7157 tinyexr::tinyexr_uint64 outSize = block.size();
7159 if (!tinyexr::CompressRle(&block.at(0), outSize,
7160 reinterpret_cast<const unsigned char *
>(&
buf.at(0)),
7161 static_cast<unsigned long>(
buf.size()))) {
7163 (*err) +=
"RLE compresssion failed.\n";
7171 unsigned int data_len =
static_cast<unsigned int>(outSize);
7172 out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
7176 unsigned int bufLen =
7177 8192 +
static_cast<unsigned int>(
7178 2 *
static_cast<unsigned int>(
7180 std::vector<unsigned char> block(bufLen);
7181 unsigned int outSize =
static_cast<unsigned int>(block.size());
7183 if (!CompressPiz(&block.at(0), &outSize,
7184 reinterpret_cast<const unsigned char *
>(&
buf.at(0)),
7185 buf.size(), channels, width, num_lines)) {
7187 (*err) +=
"PIZ compresssion failed.\n";
7195 unsigned int data_len = outSize;
7196 out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
7200 (*err) +=
"PIZ compression is disabled in this build.\n";
7206 const ZFPCompressionParam* zfp_compression_param =
reinterpret_cast<const ZFPCompressionParam*
>(compression_param);
7207 std::vector<unsigned char> block;
7208 unsigned int outSize;
7210 tinyexr::CompressZfp(
7211 &block, &outSize,
reinterpret_cast<const float *
>(&
buf.at(0)),
7212 width, num_lines,
static_cast<int>(channels.size()), *zfp_compression_param);
7217 unsigned int data_len = outSize;
7218 out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
7222 (*err) +=
"ZFP compression is disabled in this build.\n";
7224 (void)compression_param;
7234static int EncodeTiledLevel(
const EXRImage* level_image,
const EXRHeader* exr_header,
7235 const std::vector<tinyexr::ChannelInfo>& channels,
7236 std::vector<std::vector<unsigned char> >& data_list,
7238 int num_x_tiles,
int num_y_tiles,
7239 const std::vector<size_t>& channel_offset_list,
7240 int pixel_data_size,
7241 const void* compression_param,
7243 int num_tiles = num_x_tiles * num_y_tiles;
7244 if (num_tiles != level_image->
num_tiles) {
7246 (*err) +=
"Invalid number of tiles in argument.\n";
7254 (*err) +=
"Failed to encode tile data.\n";
7260#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
7261 std::atomic<bool> invalid_data(
false);
7263 bool invalid_data(
false);
7266#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
7267 std::vector<std::thread> workers;
7268 std::atomic<int> tile_count(0);
7270 int num_threads = std::max(1,
int(std::thread::hardware_concurrency()));
7271 if (num_threads >
int(num_tiles)) {
7272 num_threads =
int(num_tiles);
7275 for (
int t = 0; t < num_threads; t++) {
7276 workers.emplace_back(std::thread([&]() {
7278 while ((i = tile_count++) < num_tiles) {
7283#if TINYEXR_USE_OPENMP
7284#pragma omp parallel for
7286 for (
int i = 0; i < num_tiles; i++) {
7289 size_t tile_idx =
static_cast<size_t>(i);
7290 size_t data_idx = tile_idx + start_index;
7292 int x_tile = i % num_x_tiles;
7293 int y_tile = i / num_x_tiles;
7297 const unsigned char*
const* images =
7298 static_cast<const unsigned char* const*
>(tile.
images);
7300 data_list[data_idx].resize(5*
sizeof(
int));
7301 size_t data_header_size = data_list[data_idx].size();
7302 bool ret = EncodePixelData(data_list[data_idx],
7313 channel_offset_list,
7314 err, compression_param);
7316 invalid_data =
true;
7319 if (data_list[data_idx].
size() <= data_header_size) {
7320 invalid_data =
true;
7324 int data_len =
static_cast<int>(data_list[data_idx].size() - data_header_size);
7326 memcpy(&data_list[data_idx][0], &x_tile,
sizeof(
int));
7327 memcpy(&data_list[data_idx][4], &y_tile,
sizeof(
int));
7328 memcpy(&data_list[data_idx][8], &level_image->
level_x,
sizeof(
int));
7329 memcpy(&data_list[data_idx][12], &level_image->
level_y,
sizeof(
int));
7330 memcpy(&data_list[data_idx][16], &data_len,
sizeof(
int));
7332 swap4(
reinterpret_cast<int*
>(&data_list[data_idx][0]));
7333 swap4(
reinterpret_cast<int*
>(&data_list[data_idx][4]));
7334 swap4(
reinterpret_cast<int*
>(&data_list[data_idx][8]));
7335 swap4(
reinterpret_cast<int*
>(&data_list[data_idx][12]));
7336 swap4(
reinterpret_cast<int*
>(&data_list[data_idx][16]));
7338#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
7343 for (
auto &t : workers) {
7352 (*err) +=
"Failed to encode tile data.\n";
7359static int NumScanlines(
int compression_type) {
7360 int num_scanlines = 1;
7368 return num_scanlines;
7372 const std::vector<ChannelInfo>& channels,
7374 tinyexr_uint64 chunk_offset,
7376 OffsetData& offset_data,
7377 std::vector<std::vector<unsigned char> >& data_list,
7378 tinyexr_uint64& total_size,
7382 data_list.resize(num_blocks);
7384 std::vector<size_t> channel_offset_list(
7387 int pixel_data_size = 0;
7389 size_t channel_offset = 0;
7390 for (
size_t c = 0; c < static_cast<size_t>(exr_header->
num_channels); c++) {
7391 channel_offset_list[c] = channel_offset;
7393 pixel_data_size +=
sizeof(
unsigned short);
7394 channel_offset +=
sizeof(
unsigned short);
7395 }
else if (channels[c].requested_pixel_type ==
7397 pixel_data_size +=
sizeof(float);
7398 channel_offset +=
sizeof(float);
7400 pixel_data_size +=
sizeof(
unsigned int);
7401 channel_offset +=
sizeof(
unsigned int);
7404 (*err) +=
"Invalid requested_pixel_type.\n";
7411 const void* compression_param = 0;
7413 tinyexr::ZFPCompressionParam zfp_compression_param;
7419 bool ret = tinyexr::FindZFPCompressionParam(
7425 zfp_compression_param.type = 0;
7426 zfp_compression_param.rate = 2;
7428 compression_param = &zfp_compression_param;
7432 tinyexr_uint64
offset = chunk_offset;
7433 tinyexr_uint64 doffset = is_multipart ? 4u : 0u;
7435 if (exr_image->
tiles) {
7436 const EXRImage* level_image = exr_image;
7437 size_t block_idx = 0;
7440 offset_data.num_x_levels : (offset_data.num_x_levels * offset_data.num_y_levels);
7441 for (
int level_index = 0; level_index < num_levels; ++level_index) {
7444 (*err) +=
"Invalid number of tiled levels for EncodeChunk\n";
7449 int level_index_from_image = LevelIndex(level_image->
level_x, level_image->
level_y,
7451 if (level_index_from_image < 0) {
7453 (*err) +=
"Invalid tile level mode\n";
7458 if (level_index_from_image != level_index) {
7460 (*err) +=
"Incorrect level ordering in tiled image\n";
7464 int num_y_tiles =
int(offset_data.offsets[level_index].size());
7465 if (num_y_tiles <= 0) {
7467 (*err) +=
"Invalid Y tile size\n";
7472 int num_x_tiles =
int(offset_data.offsets[level_index][0].size());
7473 if (num_x_tiles <= 0) {
7475 (*err) +=
"Invalid X tile size\n";
7481 int ret = EncodeTiledLevel(level_image,
7488 channel_offset_list,
7493 if (!e.empty() && err) {
7499 for (
size_t j = 0; j < static_cast<size_t>(num_y_tiles); ++j)
7500 for (
size_t i = 0; i < static_cast<size_t>(num_x_tiles); ++i) {
7501 offset_data.offsets[level_index][j][i] =
offset;
7502 swap8(
reinterpret_cast<tinyexr_uint64*
>(&offset_data.offsets[level_index][j][i]));
7503 offset += data_list[block_idx].size() + doffset;
7512 std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
7514#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
7515 std::atomic<bool> invalid_data(
false);
7516 std::vector<std::thread> workers;
7517 std::atomic<int> block_count(0);
7519 int num_threads = std::min(std::max(1,
int(std::thread::hardware_concurrency())), num_blocks);
7521 for (
int t = 0; t < num_threads; t++) {
7522 workers.emplace_back(std::thread([&]() {
7524 while ((i = block_count++) < num_blocks) {
7527 bool invalid_data(
false);
7528#if TINYEXR_USE_OPENMP
7529#pragma omp parallel for
7531 for (
int i = 0; i < num_blocks; i++) {
7534 int start_y = num_scanlines * i;
7535 int end_Y = (std::min)(num_scanlines * (i + 1), exr_image->
height);
7536 int num_lines = end_Y - start_y;
7538 const unsigned char*
const* images =
7539 static_cast<const unsigned char* const*
>(exr_image->
images);
7541 data_list[i].resize(2*
sizeof(
int));
7542 size_t data_header_size = data_list[i].size();
7544 bool ret = EncodePixelData(data_list[i],
7555 channel_offset_list,
7559 invalid_data =
true;
7562 if (data_list[i].
size() <= data_header_size) {
7563 invalid_data =
true;
7566 int data_len =
static_cast<int>(data_list[i].size() - data_header_size);
7567 memcpy(&data_list[i][0], &start_y,
sizeof(
int));
7568 memcpy(&data_list[i][4], &data_len,
sizeof(
int));
7570 swap4(
reinterpret_cast<int*
>(&data_list[i][0]));
7571 swap4(
reinterpret_cast<int*
>(&data_list[i][4]));
7572#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
7577 for (
auto &t : workers) {
7586 (*err) +=
"Failed to encode scanline data.\n";
7591 for (
size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
7593 tinyexr::swap8(
reinterpret_cast<tinyexr::tinyexr_uint64 *
>(&offsets[i]));
7594 offset += data_list[i].size() + doffset;
7597 total_size =
static_cast<size_t>(
offset);
7603static size_t SaveEXRNPartImageToMemory(
const EXRImage* exr_images,
7605 unsigned int num_parts,
7606 unsigned char** memory_out,
const char** err) {
7607 if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
7608 memory_out == NULL) {
7609 SetErrorMessage(
"Invalid argument for SaveEXRNPartImageToMemory",
7614 for (
unsigned int i = 0; i < num_parts; ++i) {
7615 if (exr_headers[i]->compression_type < 0) {
7616 SetErrorMessage(
"Invalid argument for SaveEXRNPartImageToMemory",
7622 SetErrorMessage(
"PIZ compression is not supported in this build",
7629 SetErrorMessage(
"ZFP compression is not supported in this build",
7636 for (
int c = 0; c < exr_headers[i]->
num_channels; ++c) {
7638 SetErrorMessage(
"Pixel type must be FLOAT for ZFP compression",
7648 std::vector<unsigned char> memory;
7652 const char header[] = { 0x76, 0x2f, 0x31, 0x01 };
7653 memory.insert(memory.end(), header, header + 4);
7658 int long_name = exr_headers[0]->
long_name;
7660 char marker[] = { 2, 0, 0, 0 };
7667 if (num_parts == 1 && exr_images[0].tiles) {
7675 if (num_parts > 1) {
7678 memory.insert(memory.end(), marker, marker + 4);
7681 int total_chunk_count = 0;
7682 std::vector<int> chunk_count(num_parts);
7683 std::vector<OffsetData> offset_data(num_parts);
7684 for (
unsigned int i = 0; i < num_parts; ++i) {
7685 if (!exr_images[i].tiles) {
7686 int num_scanlines = NumScanlines(exr_headers[i]->compression_type);
7688 (exr_images[i].
height + num_scanlines - 1) / num_scanlines;
7689 InitSingleResolutionOffsets(offset_data[i], chunk_count[i]);
7690 total_chunk_count += chunk_count[i];
7693 std::vector<int> num_x_tiles, num_y_tiles;
7694 if (!PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i])) {
7695 SetErrorMessage(
"Failed to precalculate Tile info",
7699 int ntiles = InitTileOffsets(offset_data[i], exr_headers[i], num_x_tiles, num_y_tiles);
7701 chunk_count[i] = ntiles;
7703 SetErrorMessage(
"Failed to compute Tile offsets",
7708 total_chunk_count += chunk_count[i];
7713 std::vector< std::vector<tinyexr::ChannelInfo> > channels(num_parts);
7715 std::set<std::string> partnames;
7716 for (
unsigned int i = 0; i < num_parts; ++i) {
7719 std::vector<unsigned char> data;
7721 for (
int c = 0; c < exr_headers[i]->
num_channels; c++) {
7722 tinyexr::ChannelInfo info;
7726 info.x_sampling = 1;
7727 info.y_sampling = 1;
7728 info.name = std::string(exr_headers[i]->channels[c].name);
7729 channels[i].push_back(info);
7732 tinyexr::WriteChannelInfo(data, channels[i]);
7734 tinyexr::WriteAttributeToMemory(&memory,
"channels",
"chlist", &data.at(0),
7735 static_cast<int>(data.size()));
7741 WriteAttributeToMemory(
7742 &memory,
"compression",
"compression",
7743 reinterpret_cast<const unsigned char*
>(&comp), 1);
7747 int data[4] = { 0, 0, exr_images[i].
width - 1, exr_images[i].
height - 1 };
7752 WriteAttributeToMemory(
7753 &memory,
"dataWindow",
"box2i",
7754 reinterpret_cast<const unsigned char*
>(data),
sizeof(
int) * 4);
7756 int data0[4] = { 0, 0, exr_images[0].
width - 1, exr_images[0].
height - 1 };
7762 WriteAttributeToMemory(
7763 &memory,
"displayWindow",
"box2i",
7764 reinterpret_cast<const unsigned char*
>(data0),
sizeof(
int) * 4);
7768 unsigned char line_order = 0;
7769 WriteAttributeToMemory(&memory,
"lineOrder",
"lineOrder",
7775 float aspectRatio = 1.0f;
7776 swap4(&aspectRatio);
7777 WriteAttributeToMemory(
7778 &memory,
"pixelAspectRatio",
"float",
7779 reinterpret_cast<const unsigned char*
>(&aspectRatio),
sizeof(
float));
7783 float center[2] = { 0.0f, 0.0f };
7786 WriteAttributeToMemory(
7787 &memory,
"screenWindowCenter",
"v2f",
7788 reinterpret_cast<const unsigned char*
>(center), 2 *
sizeof(
float));
7794 WriteAttributeToMemory(&memory,
"screenWindowWidth",
"float",
7795 reinterpret_cast<const unsigned char*
>(&w),
7799 if (exr_images[i].tiles) {
7800 unsigned char tile_mode =
static_cast<unsigned char>(exr_headers[i]->
tile_level_mode & 0x3);
7801 if (exr_headers[i]->tile_rounding_mode) tile_mode |= (1u << 4u);
7803 unsigned int datai[3] = { 0, 0, 0 };
7804 unsigned char* data =
reinterpret_cast<unsigned char*
>(&datai[0]);
7805 datai[0] =
static_cast<unsigned int>(exr_headers[i]->
tile_size_x);
7806 datai[1] =
static_cast<unsigned int>(exr_headers[i]->
tile_size_y);
7807 data[8] = tile_mode;
7808 swap4(
reinterpret_cast<unsigned int*
>(&data[0]));
7809 swap4(
reinterpret_cast<unsigned int*
>(&data[4]));
7810 WriteAttributeToMemory(
7811 &memory,
"tiles",
"tiledesc",
7812 reinterpret_cast<const unsigned char*
>(data), 9);
7816 if (num_parts > 1) {
7820 if ((len = strlen(exr_headers[i]->name)) > 0) {
7821#if TINYEXR_HAS_CXX11
7822 partnames.emplace(exr_headers[i]->name);
7824 partnames.insert(std::string(exr_headers[i]->name));
7826 if (partnames.size() != i + 1) {
7827 SetErrorMessage(
"'name' attributes must be unique for a multi-part file", err);
7830 WriteAttributeToMemory(
7831 &memory,
"name",
"string",
7832 reinterpret_cast<const unsigned char*
>(exr_headers[i]->name),
7833 static_cast<int>(len));
7835 SetErrorMessage(
"Invalid 'name' attribute for a multi-part file", err);
7841 const char* type =
"scanlineimage";
7842 if (exr_images[i].tiles) type =
"tiledimage";
7843 WriteAttributeToMemory(
7844 &memory,
"type",
"string",
7845 reinterpret_cast<const unsigned char*
>(type),
7846 static_cast<int>(strlen(type)));
7850 WriteAttributeToMemory(
7851 &memory,
"chunkCount",
"int",
7852 reinterpret_cast<const unsigned char*
>(&chunk_count[i]),
7858 if (exr_headers[i]->num_custom_attributes > 0) {
7860 tinyexr::WriteAttributeToMemory(
7861 &memory, exr_headers[i]->custom_attributes[j].name,
7862 exr_headers[i]->custom_attributes[j].type,
7863 reinterpret_cast<const unsigned char*
>(
7864 exr_headers[i]->custom_attributes[j].value),
7865 exr_headers[i]->custom_attributes[j].
size);
7870 memory.push_back(0);
7874 if (num_parts > 1) {
7876 memory.push_back(0);
7879 tinyexr_uint64 chunk_offset = memory.size() + size_t(total_chunk_count) *
sizeof(tinyexr_uint64);
7881 tinyexr_uint64 total_size = 0;
7882 std::vector< std::vector< std::vector<unsigned char> > > data_lists(num_parts);
7883 for (
unsigned int i = 0; i < num_parts; ++i) {
7885 int ret = EncodeChunk(&exr_images[i], exr_headers[i],
7897 tinyexr::SetErrorMessage(e, err);
7901 chunk_offset = total_size;
7905 if (total_size == 0) {
7906 tinyexr::SetErrorMessage(
"Output memory size is zero", err);
7909 (*memory_out) =
static_cast<unsigned char*
>(malloc(
size_t(total_size)));
7912 memcpy((*memory_out), &memory[0], memory.size());
7913 unsigned char* memory_ptr = *memory_out + memory.size();
7914 size_t sum = memory.size();
7917 for (
unsigned int i = 0; i < num_parts; ++i) {
7918 if (exr_images[i].tiles) {
7919 const EXRImage* level_image = &exr_images[i];
7921 offset_data[i].num_x_levels : (offset_data[i].num_x_levels * offset_data[i].num_y_levels);
7922 for (
int level_index = 0; level_index < num_levels; ++level_index) {
7923 for (
size_t j = 0; j < offset_data[i].offsets[level_index].size(); ++j) {
7924 size_t num_bytes =
sizeof(tinyexr_uint64) * offset_data[i].offsets[level_index][j].
size();
7926 if (sum > total_size) {
7927 tinyexr::SetErrorMessage(
"Invalid offset bytes in Tiled Part image.", err);
7932 reinterpret_cast<unsigned char*
>(&offset_data[i].offsets[level_index][j][0]),
7934 memory_ptr += num_bytes;
7939 size_t num_bytes =
sizeof(tinyexr::tinyexr_uint64) *
static_cast<size_t>(chunk_count[i]);
7941 if (sum > total_size) {
7942 tinyexr::SetErrorMessage(
"Invalid offset bytes in Part image.", err);
7945 std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data[i].offsets[0][0];
7946 memcpy(memory_ptr,
reinterpret_cast<unsigned char*
>(&offsets[0]), num_bytes);
7947 memory_ptr += num_bytes;
7952 for (
unsigned int i = 0; i < num_parts; ++i) {
7953 for (
size_t j = 0; j < static_cast<size_t>(chunk_count[i]); ++j) {
7954 if (num_parts > 1) {
7956 if (sum > total_size) {
7957 tinyexr::SetErrorMessage(
"Buffer overrun in reading Part image chunk data.", err);
7960 unsigned int part_number = i;
7961 swap4(&part_number);
7962 memcpy(memory_ptr, &part_number, 4);
7965 sum += data_lists[i][j].size();
7966 if (sum > total_size) {
7967 tinyexr::SetErrorMessage(
"Buffer overrun in reading Part image chunk data.", err);
7970 memcpy(memory_ptr, &data_lists[i][j][0], data_lists[i][j].
size());
7971 memory_ptr += data_lists[i][j].size();
7975 if (sum != total_size) {
7976 tinyexr::SetErrorMessage(
"Corrupted Part image chunk data.", err);
7980 return size_t(total_size);
7984#pragma clang diagnostic pop
7991 unsigned char** memory_out,
const char** err) {
7992 return tinyexr::SaveEXRNPartImageToMemory(exr_image, &exr_header, 1, memory_out, err);
7996 const char *
filename,
const char **err) {
7997 if (exr_image == NULL ||
filename == NULL ||
7999 tinyexr::SetErrorMessage(
"Invalid argument for SaveEXRImageToFile", err);
8005 tinyexr::SetErrorMessage(
"PIZ compression is not supported in this build",
8013 tinyexr::SetErrorMessage(
"ZFP compression is not supported in this build",
8021#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API)
8023 _wfopen_s(&fp, tinyexr::UTF8ToWchar(
filename).c_str(), L
"wb");
8025 tinyexr::SetErrorMessage(
"Cannot write a file: " + std::string(
filename),
8037 tinyexr::SetErrorMessage(
"Cannot write a file: " + std::string(
filename),
8042 unsigned char *mem = NULL;
8044 if (mem_size == 0) {
8049 size_t written_size = 0;
8050 if ((mem_size > 0) && mem) {
8051 written_size = fwrite(mem, 1, mem_size, fp);
8057 if (written_size != mem_size) {
8058 tinyexr::SetErrorMessage(
"Cannot write a file", err);
8067 unsigned int num_parts,
8068 unsigned char** memory_out,
const char** err) {
8069 if (exr_images == NULL || exr_headers == NULL || num_parts < 2 ||
8070 memory_out == NULL) {
8071 tinyexr::SetErrorMessage(
"Invalid argument for SaveEXRNPartImageToMemory",
8075 return tinyexr::SaveEXRNPartImageToMemory(exr_images, exr_headers, num_parts, memory_out, err);
8080 unsigned int num_parts,
8083 if (exr_images == NULL || exr_headers == NULL || num_parts < 2) {
8084 tinyexr::SetErrorMessage(
"Invalid argument for SaveEXRMultipartImageToFile",
8091#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API)
8093 _wfopen_s(&fp, tinyexr::UTF8ToWchar(
filename).c_str(), L
"wb");
8095 tinyexr::SetErrorMessage(
"Cannot write a file: " + std::string(
filename),
8107 tinyexr::SetErrorMessage(
"Cannot write a file: " + std::string(
filename),
8112 unsigned char *mem = NULL;
8114 if (mem_size == 0) {
8119 size_t written_size = 0;
8120 if ((mem_size > 0) && mem) {
8121 written_size = fwrite(mem, 1, mem_size, fp);
8127 if (written_size != mem_size) {
8128 tinyexr::SetErrorMessage(
"Cannot write a file", err);
8136 if (deep_image == NULL) {
8137 tinyexr::SetErrorMessage(
"Invalid argument for LoadDeepEXR", err);
8142 if (!file.valid()) {
8143 tinyexr::SetErrorMessage(
"Cannot read file " + std::string(
filename), err);
8147 if (file.size == 0) {
8148 tinyexr::SetErrorMessage(
"File size is zero : " + std::string(
filename),
8153 const char *head =
reinterpret_cast<const char *
>(file.data);
8154 const char *marker =
reinterpret_cast<const char *
>(file.data);
8158 const char header[] = {0x76, 0x2f, 0x31, 0x01};
8160 if (memcmp(marker, header, 4) != 0) {
8161 tinyexr::SetErrorMessage(
"Invalid magic number", err);
8171 if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) {
8172 tinyexr::SetErrorMessage(
"Unsupported version or scanline", err);
8183 int num_scanline_blocks = 1;
8184 int compression_type = -1;
8185 int num_channels = -1;
8186 std::vector<tinyexr::ChannelInfo> channels;
8189 size_t size = file.size - tinyexr::kEXRVersionSize;
8193 }
else if (marker[0] ==
'\0') {
8199 std::string attr_name;
8200 std::string attr_type;
8201 std::vector<unsigned char> data;
8203 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
8205 std::stringstream ss;
8206 ss <<
"Failed to parse attribute\n";
8207 tinyexr::SetErrorMessage(ss.str(), err);
8210 marker += marker_size;
8211 size -= marker_size;
8213 if (attr_name.compare(
"compression") == 0) {
8214 compression_type = data[0];
8216 std::stringstream ss;
8217 ss <<
"Unsupported compression type : " << compression_type;
8218 tinyexr::SetErrorMessage(ss.str(), err);
8223 num_scanline_blocks = 16;
8226 }
else if (attr_name.compare(
"channels") == 0) {
8234 if (!tinyexr::ReadChannelInfo(channels, data)) {
8235 tinyexr::SetErrorMessage(
"Failed to parse channel info", err);
8239 num_channels =
static_cast<int>(channels.size());
8241 if (num_channels < 1) {
8242 tinyexr::SetErrorMessage(
"Invalid channels format", err);
8246 }
else if (attr_name.compare(
"dataWindow") == 0) {
8247 memcpy(&dx, &data.at(0),
sizeof(
int));
8248 memcpy(&dy, &data.at(4),
sizeof(
int));
8249 memcpy(&dw, &data.at(8),
sizeof(
int));
8250 memcpy(&dh, &data.at(12),
sizeof(
int));
8251 tinyexr::swap4(&dx);
8252 tinyexr::swap4(&dy);
8253 tinyexr::swap4(&dw);
8254 tinyexr::swap4(&dh);
8256 }
else if (attr_name.compare(
"displayWindow") == 0) {
8261 memcpy(&
x, &data.at(0),
sizeof(
int));
8262 memcpy(&
y, &data.at(4),
sizeof(
int));
8263 memcpy(&w, &data.at(8),
sizeof(
int));
8264 memcpy(&h, &data.at(12),
sizeof(
int));
8278 int data_width = dw - dx + 1;
8279 int data_height = dh - dy + 1;
8282 int num_blocks = data_height / num_scanline_blocks;
8283 if (num_blocks * num_scanline_blocks < data_height) {
8287 std::vector<tinyexr::tinyexr_int64> offsets(
static_cast<size_t>(num_blocks));
8290 tinyexr::tinyexr_int64
offset;
8291 memcpy(&
offset, marker,
sizeof(tinyexr::tinyexr_int64));
8292 tinyexr::swap8(
reinterpret_cast<tinyexr::tinyexr_uint64 *
>(&
offset));
8293 marker +=
sizeof(tinyexr::tinyexr_int64);
8311 tinyexr::SetErrorMessage(
"Unsupported compression format", err);
8315 deep_image->
image =
static_cast<float ***
>(
8316 malloc(
sizeof(
float **) *
static_cast<size_t>(num_channels)));
8317 for (
int c = 0; c < num_channels; c++) {
8318 deep_image->
image[c] =
static_cast<float **
>(
8319 malloc(
sizeof(
float *) *
static_cast<size_t>(data_height)));
8320 for (
int y = 0;
y < data_height;
y++) {
8325 malloc(
sizeof(
int *) *
static_cast<size_t>(data_height)));
8326 for (
int y = 0;
y < data_height;
y++) {
8328 malloc(
sizeof(
int) *
static_cast<size_t>(data_width)));
8332 const unsigned char *data_ptr =
8333 reinterpret_cast<const unsigned char *
>(head + offsets[
y]);
8342 tinyexr::tinyexr_int64 packedOffsetTableSize;
8343 tinyexr::tinyexr_int64 packedSampleDataSize;
8344 tinyexr::tinyexr_int64 unpackedSampleDataSize;
8345 memcpy(&line_no, data_ptr,
sizeof(
int));
8346 memcpy(&packedOffsetTableSize, data_ptr + 4,
8347 sizeof(tinyexr::tinyexr_int64));
8348 memcpy(&packedSampleDataSize, data_ptr + 12,
8349 sizeof(tinyexr::tinyexr_int64));
8350 memcpy(&unpackedSampleDataSize, data_ptr + 20,
8351 sizeof(tinyexr::tinyexr_int64));
8353 tinyexr::swap4(&line_no);
8355 reinterpret_cast<tinyexr::tinyexr_uint64 *
>(&packedOffsetTableSize));
8357 reinterpret_cast<tinyexr::tinyexr_uint64 *
>(&packedSampleDataSize));
8359 reinterpret_cast<tinyexr::tinyexr_uint64 *
>(&unpackedSampleDataSize));
8361 std::vector<int> pixelOffsetTable(
static_cast<size_t>(data_width));
8365 unsigned long dstLen =
8366 static_cast<unsigned long>(pixelOffsetTable.size() *
sizeof(
int));
8367 if (!tinyexr::DecompressZip(
8368 reinterpret_cast<unsigned char *
>(&pixelOffsetTable.at(0)),
8369 &dstLen, data_ptr + 28,
8370 static_cast<unsigned long>(packedOffsetTableSize))) {
8375 for (
size_t i = 0; i < static_cast<size_t>(data_width); i++) {
8380 std::vector<unsigned char> sample_data(
8381 static_cast<size_t>(unpackedSampleDataSize));
8385 unsigned long dstLen =
static_cast<unsigned long>(unpackedSampleDataSize);
8387 if (!tinyexr::DecompressZip(
8388 reinterpret_cast<unsigned char *
>(&sample_data.at(0)), &dstLen,
8389 data_ptr + 28 + packedOffsetTableSize,
8390 static_cast<unsigned long>(packedSampleDataSize))) {
8398 int sampleSize = -1;
8399 std::vector<int> channel_offset_list(
static_cast<size_t>(num_channels));
8401 int channel_offset = 0;
8402 for (
size_t i = 0; i < static_cast<size_t>(num_channels); i++) {
8403 channel_offset_list[i] = channel_offset;
8405 channel_offset += 4;
8407 channel_offset += 2;
8408 }
else if (channels[i].pixel_type ==
8410 channel_offset += 4;
8412 tinyexr::SetErrorMessage(
"Invalid pixel_type in chnnels.", err);
8416 sampleSize = channel_offset;
8420 TINYEXR_CHECK_AND_RETURN_C(
static_cast<size_t>(
8421 pixelOffsetTable[
static_cast<size_t>(data_width - 1)] *
8423 int samples_per_line =
static_cast<int>(sample_data.size()) / sampleSize;
8433 tinyexr::tinyexr_uint64 data_offset = 0;
8434 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
8435 deep_image->
image[c][
y] =
static_cast<float *
>(
8436 malloc(
sizeof(
float) *
static_cast<size_t>(samples_per_line)));
8438 if (channels[c].pixel_type == 0) {
8441 unsigned int *src_ptr =
reinterpret_cast<unsigned int *
>(
8442 &sample_data.at(
size_t(data_offset) +
x *
sizeof(
int)));
8443 tinyexr::cpy4(&ui, src_ptr);
8444 deep_image->
image[c][
y][
x] =
static_cast<float>(ui);
8447 sizeof(
unsigned int) *
static_cast<size_t>(samples_per_line);
8448 }
else if (channels[c].pixel_type == 1) {
8451 const unsigned short *src_ptr =
reinterpret_cast<unsigned short *
>(
8452 &sample_data.at(
size_t(data_offset) +
x *
sizeof(
short)));
8453 tinyexr::cpy2(&(f16.u), src_ptr);
8454 tinyexr::FP32 f32 = half_to_float(f16);
8455 deep_image->
image[c][
y][
x] = f32.f;
8457 data_offset +=
sizeof(short) *
static_cast<size_t>(samples_per_line);
8461 const float *src_ptr =
reinterpret_cast<float *
>(
8462 &sample_data.at(
size_t(data_offset) +
x *
sizeof(
float)));
8463 tinyexr::cpy4(&f, src_ptr);
8464 deep_image->
image[c][
y][
x] = f;
8466 data_offset +=
sizeof(float) *
static_cast<size_t>(samples_per_line);
8472 deep_image->
width = data_width;
8473 deep_image->
height = data_height;
8476 malloc(
sizeof(
const char *) *
static_cast<size_t>(num_channels)));
8477 for (
size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
8479 deep_image->
channel_names[c] = _strdup(channels[c].name.c_str());
8481 deep_image->
channel_names[c] = strdup(channels[c].name.c_str());
8490 if (exr_image == NULL) {
8494 exr_image->
width = 0;
8498 exr_image->
images = NULL;
8499 exr_image->
tiles = NULL;
8509 free(
reinterpret_cast<void *
>(
const_cast<char *
>(msg)));
8515 if (exr_header == NULL) {
8519 memset(exr_header, 0,
sizeof(
EXRHeader));
8523 if (exr_header == NULL) {
8555 if (exr_header == NULL) {
8558 memset(exr_header->
name, 0, 256);
8560 size_t len = std::min(strlen(name),
size_t(255));
8562 memcpy(exr_header->
name, name, len);
8568 if (exr_image == NULL)
return 0;
8569 if(exr_image->
images)
return 1;
8571 const EXRImage* level_image = exr_image;
8572 while((level_image = level_image->
next_level)) ++levels;
8577 if (exr_image == NULL) {
8588 free(exr_image->
images[i]);
8596 if (exr_image->
tiles) {
8597 for (
int tid = 0; tid < exr_image->
num_tiles; tid++) {
8607 free(exr_image->
tiles);
8614 const char *
filename,
const char **err) {
8615 if (exr_header == NULL || exr_version == NULL ||
filename == NULL) {
8616 tinyexr::SetErrorMessage(
"Invalid argument for ParseEXRHeaderFromFile",
8622 if (!file.valid()) {
8623 tinyexr::SetErrorMessage(
"Cannot read file " + std::string(
filename), err);
8634 const unsigned char *memory,
size_t size,
8636 if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
8637 exr_version == NULL) {
8639 tinyexr::SetErrorMessage(
8640 "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
8644 if (
size < tinyexr::kEXRVersionSize) {
8645 tinyexr::SetErrorMessage(
"Data size too short", err);
8649 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
8650 size_t marker_size =
size - tinyexr::kEXRVersionSize;
8652 std::vector<tinyexr::HeaderInfo> infos;
8655 tinyexr::HeaderInfo info;
8658 std::string err_str;
8659 bool empty_header =
false;
8660 int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str,
8661 marker, marker_size);
8666 for (
size_t i = 0; i < info.attributes.size(); i++) {
8667 if (info.attributes[i].value) {
8668 free(info.attributes[i].value);
8672 tinyexr::SetErrorMessage(err_str, err);
8682 if (info.chunk_count == 0) {
8685 for (
size_t i = 0; i < info.attributes.size(); i++) {
8686 if (info.attributes[i].value) {
8687 free(info.attributes[i].value);
8691 tinyexr::SetErrorMessage(
8692 "`chunkCount' attribute is not found in the header.", err);
8696 infos.push_back(info);
8699 marker += info.header_len;
8700 size -= info.header_len;
8710 for (
size_t i = 0; i < infos.size(); i++) {
8712 memset(exr_header, 0,
sizeof(
EXRHeader));
8716 if (!ConvertHeader(exr_header, infos[i], &warn, &_err)) {
8719 for (
size_t k = 0; k < infos[i].attributes.size(); k++) {
8720 if (infos[i].attributes[k].value) {
8721 free(infos[i].attributes[k].value);
8725 if (!_err.empty()) {
8726 tinyexr::SetErrorMessage(
8735 (*exr_headers)[i] = exr_header;
8738 (*num_headers) =
static_cast<int>(infos.size());
8745 const char *
filename,
const char **err) {
8746 if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
8748 tinyexr::SetErrorMessage(
8749 "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
8754 if (!file.valid()) {
8755 tinyexr::SetErrorMessage(
"Cannot read file " + std::string(
filename), err);
8760 exr_headers, num_headers, exr_version, file.data, file.size, err);
8765 if (version == NULL || memory == NULL) {
8769 if (
size < tinyexr::kEXRVersionSize) {
8773 const unsigned char *marker = memory;
8777 const char header[] = {0x76, 0x2f, 0x31, 0x01};
8779 if (memcmp(marker, header, 4) != 0) {
8785 version->
tiled =
false;
8793 if (marker[0] != 2) {
8797 if (version == NULL) {
8803 if (marker[1] & 0x2) {
8804 version->
tiled =
true;
8806 if (marker[1] & 0x4) {
8809 if (marker[1] & 0x8) {
8812 if (marker[1] & 0x10) {
8827#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API)
8828 errno_t err = _wfopen_s(&fp, tinyexr::UTF8ToWchar(
filename).c_str(), L
"rb");
8848 unsigned char buf[tinyexr::kEXRVersionSize];
8849 size_t ret = fread(&
buf[0], 1, tinyexr::kEXRVersionSize, fp);
8852 if (ret != tinyexr::kEXRVersionSize) {
8861 unsigned int num_parts,
8862 const unsigned char *memory,
8863 const size_t size,
const char **err) {
8864 if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
8865 memory == NULL || (
size <= tinyexr::kEXRVersionSize)) {
8866 tinyexr::SetErrorMessage(
8867 "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
8872 size_t total_header_size = 0;
8873 for (
unsigned int i = 0; i < num_parts; i++) {
8874 if (exr_headers[i]->header_len == 0) {
8875 tinyexr::SetErrorMessage(
"EXRHeader variable is not initialized.", err);
8879 total_header_size += exr_headers[i]->
header_len;
8882 const char *marker =
reinterpret_cast<const char *
>(
8883 memory + total_header_size + 4 +
8899 std::vector<tinyexr::OffsetData> chunk_offset_table_list;
8900 chunk_offset_table_list.reserve(num_parts);
8901 for (
size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
8902 chunk_offset_table_list.resize(chunk_offset_table_list.size() + 1);
8903 tinyexr::OffsetData& offset_data = chunk_offset_table_list.back();
8905 tinyexr::InitSingleResolutionOffsets(offset_data,
size_t(exr_headers[i]->chunk_count));
8906 std::vector<tinyexr::tinyexr_uint64>& offset_table = offset_data.offsets[0][0];
8908 for (
size_t c = 0; c < offset_table.size(); c++) {
8909 tinyexr::tinyexr_uint64
offset;
8910 memcpy(&
offset, marker, 8);
8914 tinyexr::SetErrorMessage(
"Invalid offset size in EXR header chunks.",
8919 offset_table[c] =
offset + 4;
8924 std::vector<int> num_x_tiles, num_y_tiles;
8925 if (!tinyexr::PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i])) {
8926 tinyexr::SetErrorMessage(
"Invalid tile info.", err);
8929 int num_blocks = InitTileOffsets(offset_data, exr_headers[i], num_x_tiles, num_y_tiles);
8930 if (num_blocks != exr_headers[i]->chunk_count) {
8931 tinyexr::SetErrorMessage(
"Invalid offset table size.", err);
8935 for (
unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
8936 for (
unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
8937 for (
unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
8938 tinyexr::tinyexr_uint64
offset;
8939 memcpy(&
offset, marker,
sizeof(tinyexr::tinyexr_uint64));
8942 tinyexr::SetErrorMessage(
"Invalid offset size in EXR header chunks.",
8946 offset_data.offsets[l][dy][dx] =
offset + 4;
8947 marker +=
sizeof(tinyexr::tinyexr_uint64);
8955 for (
size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
8956 tinyexr::OffsetData &offset_data = chunk_offset_table_list[i];
8959 for (
unsigned int l = 0; l < offset_data.offsets.size(); ++l)
8960 for (
unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy)
8961 for (
unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
8963 const unsigned char *part_number_addr =
8964 memory + offset_data.offsets[l][dy][dx] - 4;
8965 unsigned int part_no;
8966 memcpy(&part_no, part_number_addr,
sizeof(
unsigned int));
8967 tinyexr::swap4(&part_no);
8970 tinyexr::SetErrorMessage(
"Invalid `part number' in EXR header chunks.",
8977 int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_data,
8981 tinyexr::SetErrorMessage(e, err);
8992 unsigned int num_parts,
const char *
filename,
8994 if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
8995 tinyexr::SetErrorMessage(
8996 "Invalid argument for LoadEXRMultipartImageFromFile", err);
9001 if (!file.valid()) {
9002 tinyexr::SetErrorMessage(
"Cannot read file " + std::string(
filename), err);
9007 file.data, file.size, err);
9010int SaveEXRToMemory(
const float *data,
int width,
int height,
int components,
9011 const int save_as_fp16,
unsigned char **outbuf,
const char **err) {
9013 if ((components == 1) || components == 3 || components == 4) {
9016 std::stringstream ss;
9017 ss <<
"Unsupported component value : " << components << std::endl;
9019 tinyexr::SetErrorMessage(ss.str(), err);
9026 if ((width < 16) && (height < 16)) {
9038 std::vector<float> images[4];
9040 if (components == 1) {
9041 images[0].resize(
static_cast<size_t>(width * height));
9042 memcpy(images[0].data(), data,
sizeof(
float) *
size_t(width * height));
9044 images[0].resize(
static_cast<size_t>(width * height));
9045 images[1].resize(
static_cast<size_t>(width * height));
9046 images[2].resize(
static_cast<size_t>(width * height));
9047 images[3].resize(
static_cast<size_t>(width * height));
9050 for (
size_t i = 0; i < static_cast<size_t>(width * height); i++) {
9051 images[0][i] = data[
static_cast<size_t>(components) * i + 0];
9052 images[1][i] = data[
static_cast<size_t>(components) * i + 1];
9053 images[2][i] = data[
static_cast<size_t>(components) * i + 2];
9054 if (components == 4) {
9055 images[3][i] = data[
static_cast<size_t>(components) * i + 3];
9060 float *image_ptr[4] = {0, 0, 0, 0};
9061 if (components == 4) {
9062 image_ptr[0] = &(images[3].at(0));
9063 image_ptr[1] = &(images[2].at(0));
9064 image_ptr[2] = &(images[1].at(0));
9065 image_ptr[3] = &(images[0].at(0));
9066 }
else if (components == 3) {
9067 image_ptr[0] = &(images[2].at(0));
9068 image_ptr[1] = &(images[1].at(0));
9069 image_ptr[2] = &(images[0].at(0));
9070 }
else if (components == 1) {
9071 image_ptr[0] = &(images[0].at(0));
9074 image.
images =
reinterpret_cast<unsigned char **
>(image_ptr);
9075 image.
width = width;
9082 if (components == 4) {
9098 }
else if (components == 3) {
9121 malloc(
sizeof(
int) *
static_cast<size_t>(header.
num_channels)));
9123 malloc(
sizeof(
int) *
static_cast<size_t>(header.
num_channels)));
9128 if (save_as_fp16 > 0) {
9139 unsigned char *mem_buf;
9142 if (mem_size == 0) {
9150 if (mem_size >
size_t(std::numeric_limits<int>::max())) {
9155 (*outbuf) = mem_buf;
9157 return int(mem_size);
9160int SaveEXR(
const float *data,
int width,
int height,
int components,
9161 const int save_as_fp16,
const char *outfilename,
const char **err) {
9162 if ((components == 1) || components == 3 || components == 4) {
9165 std::stringstream ss;
9166 ss <<
"Unsupported component value : " << components << std::endl;
9168 tinyexr::SetErrorMessage(ss.str(), err);
9175 if ((width < 16) && (height < 16)) {
9187 std::vector<float> images[4];
9188 const size_t pixel_count =
9189 static_cast<size_t>(width) *
static_cast<size_t>(height);
9191 if (components == 1) {
9192 images[0].resize(pixel_count);
9193 memcpy(images[0].data(), data,
sizeof(
float) * pixel_count);
9195 images[0].resize(pixel_count);
9196 images[1].resize(pixel_count);
9197 images[2].resize(pixel_count);
9198 images[3].resize(pixel_count);
9201 for (
size_t i = 0; i < pixel_count; i++) {
9202 images[0][i] = data[
static_cast<size_t>(components) * i + 0];
9203 images[1][i] = data[
static_cast<size_t>(components) * i + 1];
9204 images[2][i] = data[
static_cast<size_t>(components) * i + 2];
9205 if (components == 4) {
9206 images[3][i] = data[
static_cast<size_t>(components) * i + 3];
9211 float *image_ptr[4] = {0, 0, 0, 0};
9212 if (components == 4) {
9213 image_ptr[0] = &(images[3].at(0));
9214 image_ptr[1] = &(images[2].at(0));
9215 image_ptr[2] = &(images[1].at(0));
9216 image_ptr[3] = &(images[0].at(0));
9217 }
else if (components == 3) {
9218 image_ptr[0] = &(images[2].at(0));
9219 image_ptr[1] = &(images[1].at(0));
9220 image_ptr[2] = &(images[0].at(0));
9221 }
else if (components == 1) {
9222 image_ptr[0] = &(images[0].at(0));
9225 image.
images =
reinterpret_cast<unsigned char **
>(image_ptr);
9226 image.
width = width;
9233 if (components == 4) {
9249 }
else if (components == 3) {
9272 malloc(
sizeof(
int) *
static_cast<size_t>(header.
num_channels)));
9274 malloc(
sizeof(
int) *
static_cast<size_t>(header.
num_channels)));
9279 if (save_as_fp16 > 0) {
9300#pragma clang diagnostic pop
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
mz_ulong mz_compressBound(mz_ulong source_len)
int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
const char ** channel_names
struct TEXRImage * next_level
int LoadEXRFromMemory(float **out_rgba, int *width, int *height, const unsigned char *memory, size_t size, const char **err)
int ParseEXRHeaderFromMemory(EXRHeader *header, const EXRVersion *version, const unsigned char *memory, size_t size, const char **err)
struct TEXRBox2i EXRBox2i
int FreeEXRHeader(EXRHeader *exr_header)
#define TINYEXR_ERROR_UNSUPPORTED_FEATURE
#define TINYEXR_COMPRESSIONTYPE_ZFP
int FreeEXRImage(EXRImage *exr_image)
int IsEXRFromMemory(const unsigned char *memory, size_t size)
int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, int *num_headers, const EXRVersion *version, const char *filename, const char **err)
#define TINYEXR_ERROR_INVALID_ARGUMENT
struct TEXRVersion EXRVersion
#define TINYEXR_COMPRESSIONTYPE_PIZ
int LoadDeepEXR(DeepImage *out_image, const char *filename, const char **err)
int SaveEXRToMemory(const float *data, const int width, const int height, const int components, const int save_as_fp16, unsigned char **buffer, const char **err)
#define TINYEXR_ERROR_DATA_TOO_LARGE
#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION
#define TINYEXR_COMPRESSIONTYPE_ZIPS
#define TINYEXR_TILE_MIPMAP_LEVELS
#define TINYEXR_TILE_RIPMAP_LEVELS
#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER
#define TINYEXR_COMPRESSIONTYPE_RLE
int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory, size_t size)
#define TINYEXR_PIXELTYPE_UINT
int SaveEXR(const float *data, const int width, const int height, const int components, const int save_as_fp16, const char *filename, const char **err)
int ParseEXRVersionFromFile(EXRVersion *version, const char *filename)
void FreeEXRErrorMessage(const char *msg)
#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE
int LoadEXRMultipartImageFromMemory(EXRImage *images, const EXRHeader **headers, unsigned int num_parts, const unsigned char *memory, const size_t size, const char **err)
int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, const char **err)
#define TINYEXR_ERROR_SERIALIZATION_FAILED
int LoadEXRWithLayer(float **out_rgba, int *width, int *height, const char *filename, const char *layer_name, const char **err)
struct TEXRImage EXRImage
int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, const unsigned char *memory, const size_t size, const char **err)
#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY
#define TINYEXR_ERROR_INVALID_EXR_VERSION
#define TINYEXR_COMPRESSIONTYPE_NONE
#define TINYEXR_PIXELTYPE_HALF
#define TINYEXR_MAX_CUSTOM_ATTRIBUTES
int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version, const char *filename, const char **err)
int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, const char **err)
int IsEXR(const char *filename)
#define TINYEXR_ERROR_LAYER_NOT_FOUND
size_t SaveEXRImageToMemory(const EXRImage *image, const EXRHeader *exr_header, unsigned char **memory, const char **err)
#define TINYEXR_TILE_ROUND_UP
#define TINYEXR_COMPRESSIONTYPE_ZIP
int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, int *num_headers, const EXRVersion *version, const unsigned char *memory, size_t size, const char **err)
#define TINYEXR_ERROR_CANT_OPEN_FILE
int EXRNumLevels(const EXRImage *exr_image)
struct TEXRAttribute EXRAttribute
#define TINYEXR_ERROR_INVALID_FILE
#define TINYEXR_ERROR_INVALID_DATA
struct TEXRHeader EXRHeader
struct TEXRMultiPartImage EXRMultiPartImage
int LoadEXRMultipartImageFromFile(EXRImage *images, const EXRHeader **headers, unsigned int num_parts, const char *filename, const char **err)
#define TINYEXR_MAX_HEADER_ATTRIBUTES
void InitEXRHeader(EXRHeader *exr_header)
struct TEXRMultiPartHeader EXRMultiPartHeader
size_t SaveEXRMultipartImageToMemory(const EXRImage *images, const EXRHeader **exr_headers, unsigned int num_parts, unsigned char **memory, const char **err)
#define TINYEXR_PIXELTYPE_FLOAT
struct TEXRChannelInfo EXRChannelInfo
#define TINYEXR_TILE_ROUND_DOWN
#define TINYEXR_ERROR_UNSUPPORTED_FORMAT
void InitEXRImage(EXRImage *exr_image)
#define TINYEXR_ERROR_INVALID_HEADER
int SaveEXRImageToFile(const EXRImage *image, const EXRHeader *exr_header, const char *filename, const char **err)
#define TINYEXR_ERROR_CANT_WRITE_FILE
#define TINYEXR_TILE_ONE_LEVEL
struct TDeepImage DeepImage
int SaveEXRMultipartImageToFile(const EXRImage *images, const EXRHeader **exr_headers, unsigned int num_parts, const char *filename, const char **err)
int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, const char *filename, const char **err)
void EXRSetNameAttr(EXRHeader *exr_header, const char *name)