mirror of
https://github.com/bkaradzic/bimg.git
synced 2026-02-17 20:52:38 +01:00
tinyexr: Fixes warning C5208 (VS2019 16.6.0)
This commit is contained in:
426
3rdparty/tinyexr/README.md
vendored
426
3rdparty/tinyexr/README.md
vendored
@@ -1,5 +1,7 @@
|
||||
# Tiny OpenEXR image library.
|
||||
|
||||
[](https://lgtm.com/projects/g/syoyo/tinyexr/alerts/)
|
||||
|
||||

|
||||
|
||||
[](https://ci.appveyor.com/project/syoyo/tinyexr/branch/master)
|
||||
@@ -12,32 +14,80 @@
|
||||
`tinyexr` is written in portable C++ (no library dependency except for STL), thus `tinyexr` is good to embed into your application.
|
||||
To use `tinyexr`, simply copy `tinyexr.h` into your project.
|
||||
|
||||
`tinyexr` currently supports:
|
||||
# Features
|
||||
|
||||
* OpenEXR version 1.x.
|
||||
* Normal image
|
||||
* Scanline format.
|
||||
* Uncompress("compress" = 0), ZIPS("compress" = 2), ZIP compression("compress" = 3) and PIZ compression("compress" = 4).
|
||||
* Half/Uint/Float pixel type.
|
||||
* Custom attributes(up to 128)
|
||||
* Deep image
|
||||
* Scanline format.
|
||||
* ZIPS compression("compress" = 2).
|
||||
* Half, float pixel type.
|
||||
* Litte endian machine.
|
||||
* Limited support for big endian machine.
|
||||
* read/write normal image.
|
||||
Current status of `tinyexr` is:
|
||||
|
||||
- OpenEXR v1 image
|
||||
- [x] Scanline format
|
||||
- [ ] Tiled format
|
||||
- [x] Tile format with no LoD (load).
|
||||
- [ ] Tile format with LoD (load).
|
||||
- [ ] Tile format with no LoD (save).
|
||||
- [ ] Tile format with LoD (save).
|
||||
- [x] Custom attributes
|
||||
- OpenEXR v2 image
|
||||
- [ ] Multipart format
|
||||
- [x] Load multi-part image
|
||||
- [ ] Save multi-part image
|
||||
- [ ] Load multi-part deep image
|
||||
- [ ] Save multi-part deep image
|
||||
- OpenEXR v2 deep image
|
||||
- [x] Loading scanline + ZIPS + HALF or FLOAT pixel type.
|
||||
- Compression
|
||||
- [x] NONE
|
||||
- [x] RLE
|
||||
- [x] ZIP
|
||||
- [x] ZIPS
|
||||
- [x] PIZ
|
||||
- [x] ZFP (tinyexr extension)
|
||||
- [ ] B44?
|
||||
- [ ] B44A?
|
||||
- [ ] PIX24?
|
||||
- Line order.
|
||||
- [x] Increasing, decreasing (load)
|
||||
- [ ] Random?
|
||||
- [ ] Increasing, decreasing (save)
|
||||
- Pixel format (UINT, FLOAT).
|
||||
- [x] UINT, FLOAT (load)
|
||||
- [x] UINT, FLOAT (deep load)
|
||||
- [x] UINT, FLOAT (save)
|
||||
- [ ] UINT, FLOAT (deep save)
|
||||
- Support for big endian machine.
|
||||
- [x] Loading scanline image
|
||||
- [x] Saving scanline image
|
||||
- [ ] Loading multi-part channel EXR
|
||||
- [ ] Saving multi-part channel EXR
|
||||
- [ ] Loading deep image
|
||||
- [ ] Saving deep image
|
||||
- Optimization
|
||||
- [x] C++11 thread loading
|
||||
- [ ] C++11 thread saving
|
||||
- [ ] ISPC?
|
||||
- [x] OpenMP multi-threading in EXR loading.
|
||||
- [x] OpenMP multi-threading in EXR saving.
|
||||
- [ ] OpenMP multi-threading in deep image loading.
|
||||
- [ ] OpenMP multi-threading in deep image saving.
|
||||
* C interface.
|
||||
* You can easily write language bindings (e.g. golang)
|
||||
* EXR saving
|
||||
* with ZIP compression.
|
||||
* JavaScript library
|
||||
* Through emscripten.
|
||||
|
||||
# Requirements
|
||||
|
||||
* C++ compiler(C++11 recommended. C++03 may work)
|
||||
|
||||
# Use case
|
||||
|
||||
## New TinyEXR (v0.9.5+)
|
||||
|
||||
* Godot. Multi-platform 2D and 3D game engine https://godotengine.org/
|
||||
* Filament. PBR engine. https://github.com/google/filament
|
||||
* PyEXR. Loading OpenEXR (.exr) images using Python. https://github.com/ialhashim/PyEXR
|
||||
* The-Forge. The Forge Cross-Platform Rendering Framework PC, Linux, Ray Tracing, macOS / iOS, Android, XBOX, PS4 https://github.com/ConfettiFX/The-Forge
|
||||
* Your project here!
|
||||
|
||||
## Older TinyEXR (v0.9.0)
|
||||
|
||||
* mallie https://github.com/lighttransport/mallie
|
||||
* PBRT v3 https://github.com/mmp/pbrt-v3
|
||||
* Cinder 0.9.0 https://libcinder.org/notes/v0.9.0
|
||||
* Piccante (develop branch) http://piccantelib.net/
|
||||
* Your project here!
|
||||
@@ -47,6 +97,15 @@ To use `tinyexr`, simply copy `tinyexr.h` into your project.
|
||||
* [examples/deepview/](examples/deepview) Deep image view
|
||||
* [examples/rgbe2exr/](examples/rgbe2exr) .hdr to EXR converter
|
||||
* [examples/exr2rgbe/](examples/exr2rgbe) EXR to .hdr converter
|
||||
* [examples/ldr2exr/](examples/exr2rgbe) LDR to EXR converter
|
||||
* [examples/exr2ldr/](examples/exr2ldr) EXR to LDR converter
|
||||
* [examples/exr2fptiff/](examples/exr2fptiff) EXR to 32bit floating point TIFF converter
|
||||
* for 32bit floating point TIFF to EXR convert, see https://github.com/syoyo/tinydngloader/tree/master/examples/fptiff2exr
|
||||
* [examples/cube2longlat/](examples/cube2longlat) Cubemap to longlat (equirectangler) converter
|
||||
|
||||
## Experimental
|
||||
|
||||
* [experimental/js/](experimental/js) JavaScript port using Emscripten
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -54,72 +113,224 @@ NOTE: **API is still subject to change**. See the source code for details.
|
||||
|
||||
Include `tinyexr.h` with `TINYEXR_IMPLEMENTATION` flag (do this only for **one** .cc file).
|
||||
|
||||
```
|
||||
```cpp
|
||||
//Please include your own zlib-compatible API header before
|
||||
//including `tinyexr.h` when you disable `TINYEXR_USE_MINIZ`
|
||||
//#define TINYEXR_USE_MINIZ 0
|
||||
//#include "zlib.h"
|
||||
#define TINYEXR_IMPLEMENTATION
|
||||
#include "tinyexr.h"
|
||||
```
|
||||
|
||||
Quickly reading RGB(A) EXR file.
|
||||
### Compile flags
|
||||
|
||||
```
|
||||
* `TINYEXR_USE_MINIZ` Use embedded miniz (default = 1). Please include `zlib.h` header (before `tinyexr.h`) if you disable miniz support.
|
||||
* `TINYEXR_USE_PIZ` Enable PIZ compression support (default = 1)
|
||||
* `TINYEXR_USE_ZFP` Enable ZFP compression supoort (TinyEXR extension, default = 0)
|
||||
* `TINYEXR_USE_THREAD` Enable threaded loading using C++11 thread (Requires C++11 compiler, default = 0)
|
||||
* `TINYEXR_USE_OPENMP` Enable OpenMP threading support (default = 1 if `_OPENMP` is defined)
|
||||
* Use `TINYEXR_USE_OPENMP=0` to force disable OpenMP code path even if OpenMP is available/enabled in the compiler.
|
||||
|
||||
### Quickly reading RGB(A) EXR file.
|
||||
|
||||
```cpp
|
||||
const char* input = "asakusa.exr";
|
||||
float* out; // width * height * RGBA
|
||||
int width;
|
||||
int height;
|
||||
const char* err;
|
||||
const char* err = NULL; // or nullptr in C++11
|
||||
|
||||
int ret = LoadEXR(&out, &width, &height, input, &err);
|
||||
```
|
||||
|
||||
Loading EXR from a file.
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
if (err) {
|
||||
fprintf(stderr, "ERR : %s\n", err);
|
||||
FreeEXRErrorMessage(err); // release memory of error message.
|
||||
}
|
||||
} else {
|
||||
...
|
||||
free(out); // release memory of image data
|
||||
}
|
||||
|
||||
```
|
||||
const char* input = "asakusa.exr";
|
||||
const char* err;
|
||||
|
||||
EXRImage exrImage;
|
||||
InitEXRImage(&exrImage);
|
||||
### Reading layered RGB(A) EXR file.
|
||||
|
||||
int ret = ParseMultiChannelEXRHeaderFromFile(&exrImage, input, &err);
|
||||
If you want to read EXR image with layer info (channel has a name with delimiter `.`), please use `LoadEXRWithLayer` API.
|
||||
|
||||
You need to know layer name in advance (e.g. through `EXRLayers` API).
|
||||
|
||||
```cpp
|
||||
const char* input = ...;
|
||||
const char* layer_name = "diffuse"; // or use EXRLayers to get list of layer names in .exr
|
||||
float* out; // width * height * RGBA
|
||||
int width;
|
||||
int height;
|
||||
const char* err = NULL; // or nullptr in C++11
|
||||
|
||||
// will read `diffuse.R`, `diffuse.G`, `diffuse.B`, (`diffuse.A`) channels
|
||||
int ret = LoadEXRWithLayer(&out, &width, &height, input, layer_name, &err);
|
||||
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
if (err) {
|
||||
fprintf(stderr, "ERR : %s\n", err);
|
||||
FreeEXRErrorMessage(err); // release memory of error message.
|
||||
}
|
||||
} else {
|
||||
...
|
||||
free(out); // release memory of image data
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Loading Singlepart EXR from a file.
|
||||
|
||||
Scanline and tiled format are supported.
|
||||
|
||||
```cpp
|
||||
// 1. Read EXR version.
|
||||
EXRVersion exr_version;
|
||||
|
||||
int ret = ParseEXRVersionFromFile(&exr_version, argv[1]);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Invalid EXR file: %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (exr_version.multipart) {
|
||||
// must be multipart flag is false.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2. Read EXR header
|
||||
EXRHeader exr_header;
|
||||
InitEXRHeader(&exr_header);
|
||||
|
||||
const char* err = NULL; // or `nullptr` in C++11 or later.
|
||||
ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, argv[1], &err);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Parse EXR err: %s\n", err);
|
||||
return;
|
||||
FreeEXRErrorMessage(err); // free's buffer for an error message
|
||||
return ret;
|
||||
}
|
||||
|
||||
//// Uncomment if you want reading HALF image as FLOAT.
|
||||
//for (int i = 0; i < exrImage.num_channels; i++) {
|
||||
// if (exrImage.pixel_types[i] = TINYEXR_PIXELTYPE_HALF) {
|
||||
// exrImage.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
|
||||
// // Read HALF channel as FLOAT.
|
||||
// for (int i = 0; i < exr_header.num_channels; i++) {
|
||||
// if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
|
||||
// exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
|
||||
// }
|
||||
// }
|
||||
|
||||
ret = LoadMultiChannelEXRFromFile(&exrImage, input, &err);
|
||||
EXRImage exr_image;
|
||||
InitEXRImage(&exr_image);
|
||||
|
||||
ret = LoadEXRImageFromFile(&exr_image, &exr_header, argv[1], &err);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Load EXR err: %s\n", err);
|
||||
return;
|
||||
FreeEXRHeader(&exr_header);
|
||||
FreeEXRErrorMessage(err); // free's buffer for an error message
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 3. Access image data
|
||||
// `exr_image.images` will be filled when EXR is scanline format.
|
||||
// `exr_image.tiled` will be filled when EXR is tiled format.
|
||||
|
||||
// 4. Free image data
|
||||
FreeEXRImage(&exr_image);
|
||||
FreeEXRHeader(&exr_header);
|
||||
```
|
||||
|
||||
Saving EXR file.
|
||||
### Loading Multipart EXR from a file.
|
||||
|
||||
Scanline and tiled format are supported.
|
||||
|
||||
```cpp
|
||||
// 1. Read EXR version.
|
||||
EXRVersion exr_version;
|
||||
|
||||
int ret = ParseEXRVersionFromFile(&exr_version, argv[1]);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Invalid EXR file: %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!exr_version.multipart) {
|
||||
// must be multipart flag is true.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2. Read EXR headers in the EXR.
|
||||
EXRHeader **exr_headers; // list of EXRHeader pointers.
|
||||
int num_exr_headers;
|
||||
const char *err = NULL; // or nullptr in C++11 or later
|
||||
|
||||
// Memory for EXRHeader is allocated inside of ParseEXRMultipartHeaderFromFile,
|
||||
ret = ParseEXRMultipartHeaderFromFile(&exr_headers, &num_exr_headers, &exr_version, argv[1], &err);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Parse EXR err: %s\n", err);
|
||||
FreeEXRErrorMessage(err); // free's buffer for an error message
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("num parts = %d\n", num_exr_headers);
|
||||
|
||||
|
||||
// 3. Load images.
|
||||
|
||||
// Prepare array of EXRImage.
|
||||
std::vector<EXRImage> images(num_exr_headers);
|
||||
for (int i =0; i < num_exr_headers; i++) {
|
||||
InitEXRImage(&images[i]);
|
||||
}
|
||||
|
||||
ret = LoadEXRMultipartImageFromFile(&images.at(0), const_cast<const EXRHeader**>(exr_headers), num_exr_headers, argv[1], &err);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Parse EXR err: %s\n", err);
|
||||
FreeEXRErrorMessage(err); // free's buffer for an error message
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("Loaded %d part images\n", num_exr_headers);
|
||||
|
||||
// 4. Access image data
|
||||
// `exr_image.images` will be filled when EXR is scanline format.
|
||||
// `exr_image.tiled` will be filled when EXR is tiled format.
|
||||
|
||||
// 5. Free images
|
||||
for (int i =0; i < num_exr_headers; i++) {
|
||||
FreeEXRImage(&images.at(i));
|
||||
}
|
||||
|
||||
// 6. Free headers.
|
||||
for (int i =0; i < num_exr_headers; i++) {
|
||||
FreeEXRHeader(exr_headers[i]);
|
||||
free(exr_headers[i]);
|
||||
}
|
||||
free(exr_headers);
|
||||
```
|
||||
|
||||
|
||||
Saving Scanline EXR file.
|
||||
|
||||
```cpp
|
||||
// See `examples/rgbe2exr/` for more details.
|
||||
bool SaveEXR(const float* rgb, int width, int height, const char* outfilename) {
|
||||
|
||||
float* channels[3];
|
||||
EXRHeader header;
|
||||
InitEXRHeader(&header);
|
||||
|
||||
EXRImage image;
|
||||
InitEXRImage(&image);
|
||||
|
||||
image.num_channels = 3;
|
||||
|
||||
// Must be BGR(A) order, since most of EXR viewers expect this channel order.
|
||||
const char* channel_names[] = {"B", "G", "R"}; // "B", "G", "R", "A" for RGBA image
|
||||
|
||||
std::vector<float> images[3];
|
||||
images[0].resize(width * height);
|
||||
images[1].resize(width * height);
|
||||
images[2].resize(width * height);
|
||||
|
||||
// Split RGBRGBRGB... into R, G and B layer
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
images[0][i] = rgb[3*i+0];
|
||||
images[1][i] = rgb[3*i+1];
|
||||
@@ -131,31 +342,38 @@ Saving EXR file.
|
||||
image_ptr[1] = &(images[1].at(0)); // G
|
||||
image_ptr[2] = &(images[0].at(0)); // R
|
||||
|
||||
image.channel_names = channel_names;
|
||||
image.images = (unsigned char**)image_ptr;
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
image.compression = TINYEXR_COMPRESSIONTYPE_ZIP;
|
||||
|
||||
image.pixel_types = (int *)malloc(sizeof(int) * image.num_channels);
|
||||
image.requested_pixel_types = (int *)malloc(sizeof(int) * image.num_channels);
|
||||
for (int i = 0; i < image.num_channels; i++) {
|
||||
image.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
|
||||
image.requested_pixel_types[i] = TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in .EXR
|
||||
header.num_channels = 3;
|
||||
header.channels = (EXRChannelInfo *)malloc(sizeof(EXRChannelInfo) * header.num_channels);
|
||||
// Must be (A)BGR order, since most of EXR viewers expect this channel order.
|
||||
strncpy(header.channels[0].name, "B", 255); header.channels[0].name[strlen("B")] = '\0';
|
||||
strncpy(header.channels[1].name, "G", 255); header.channels[1].name[strlen("G")] = '\0';
|
||||
strncpy(header.channels[2].name, "R", 255); header.channels[2].name[strlen("R")] = '\0';
|
||||
|
||||
header.pixel_types = (int *)malloc(sizeof(int) * header.num_channels);
|
||||
header.requested_pixel_types = (int *)malloc(sizeof(int) * header.num_channels);
|
||||
for (int i = 0; i < header.num_channels; i++) {
|
||||
header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
|
||||
header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in .EXR
|
||||
}
|
||||
|
||||
const char* err;
|
||||
int ret = SaveMultiChannelEXRToFile(&image, outfilename, &err);
|
||||
if (ret != 0) {
|
||||
const char* err = NULL; // or nullptr in C++11 or later.
|
||||
int ret = SaveEXRImageToFile(&image, &header, outfilename, &err);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
fprintf(stderr, "Save EXR err: %s\n", err);
|
||||
FreeEXRErrorMessage(err); // free's buffer for an error message
|
||||
return ret;
|
||||
}
|
||||
printf("Saved exr file. [ %s ] \n", outfilename);
|
||||
|
||||
free(image.pixel_types);
|
||||
free(image.requested_pixel_types);
|
||||
free(rgb);
|
||||
|
||||
return ret;
|
||||
free(header.channels);
|
||||
free(header.pixel_types);
|
||||
free(header.requested_pixel_types);
|
||||
|
||||
}
|
||||
```
|
||||
@@ -164,14 +382,14 @@ Saving EXR file.
|
||||
Reading deep image EXR file.
|
||||
See `example/deepview` for actual usage.
|
||||
|
||||
```
|
||||
```cpp
|
||||
const char* input = "deepimage.exr";
|
||||
const char* err;
|
||||
const char* err = NULL; // or nullptr
|
||||
DeepImage deepImage;
|
||||
|
||||
int ret = LoadDeepEXR(&deepImage, input, &err);
|
||||
|
||||
// acccess to each sample in the deep pixel.
|
||||
// access to each sample in the deep pixel.
|
||||
for (int y = 0; y < deepImage.height; y++) {
|
||||
int sampleNum = deepImage.offset_table[y][deepImage.width-1];
|
||||
for (int x = 0; x < deepImage.width-1; x++) {
|
||||
@@ -196,37 +414,89 @@ See `example/deepview` for actual usage.
|
||||
|
||||

|
||||
|
||||
## TinyEXR extension
|
||||
|
||||
### ZFP
|
||||
|
||||
#### NOTE
|
||||
|
||||
TinyEXR adds ZFP compression as an experimemtal support (Linux and MacOSX only).
|
||||
|
||||
ZFP only supports FLOAT format pixel, and its image width and height must be the multiple of 4, since ZFP compresses pixels with 4x4 pixel block.
|
||||
|
||||
#### Setup
|
||||
|
||||
Checkout zfp repo as an submodule.
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
#### Build
|
||||
|
||||
Then build ZFP
|
||||
|
||||
$ cd deps/ZFP
|
||||
$ mkdir -p lib # Create `lib` directory if not exist
|
||||
$ make
|
||||
|
||||
Set `1` to `TINYEXT_USE_ZFP` define in `tinyexr.h`
|
||||
|
||||
Build your app with linking `deps/ZFP/lib/libzfp.a`
|
||||
|
||||
#### ZFP attribute
|
||||
|
||||
For ZFP EXR image, the following attribute must exist in its EXR image.
|
||||
|
||||
* `zfpCompressionType` (uchar).
|
||||
* 0 = fixed rate compression
|
||||
* 1 = precision based variable rate compression
|
||||
* 2 = accuracy based variable rate compression
|
||||
|
||||
And the one of following attributes must exist in EXR, depending on the `zfpCompressionType` value.
|
||||
|
||||
* `zfpCompressionRate` (double)
|
||||
* Specifies compression rate for fixed rate compression.
|
||||
* `zfpCompressionPrecision` (int32)
|
||||
* Specifies the number of bits for precision based variable rate compression.
|
||||
* `zfpCompressionTolerance` (double)
|
||||
* Specifies the tolerance value for accuracy based variable rate compression.
|
||||
|
||||
#### Note on ZFP compression.
|
||||
|
||||
At least ZFP code itself works well on big endian machine.
|
||||
|
||||
## Unit tests
|
||||
|
||||
See `test/unit` directory.
|
||||
|
||||
## TODO
|
||||
|
||||
Contribution is welcome!
|
||||
|
||||
- [ ] Compression
|
||||
- [ ] NONE("compress" = 0, load)
|
||||
- [ ] RLE("compress" = 1, load)
|
||||
- [x] ZIPS("compress" = 2, load)
|
||||
- [x] ZIP("compress" = 3, load)
|
||||
- [x] PIZ("compress" = 4, load)
|
||||
- [x] NONE("compress" = 0, save)
|
||||
- [ ] RLE("compress" = 1, save)
|
||||
- [x] ZIPS("compress" = 2, save)
|
||||
- [x] ZIP("compress" = 3, save)
|
||||
- [ ] PIZ("compress" = 4, save)
|
||||
- [ ] B44?
|
||||
- [ ] B44A?
|
||||
- [ ] PIX24?
|
||||
- [ ] Custom attributes
|
||||
- [x] Normal image (EXR 1.x)
|
||||
- [ ] Deep image (EXR 2.x)
|
||||
- [ ] JavaScript library
|
||||
- [ ] JavaScript library (experimental, using Emscripten)
|
||||
- [x] LoadEXRFromMemory
|
||||
- [ ] SaveMultiChannelEXR
|
||||
- [ ] Deep image save/load
|
||||
- [ ] Write from/to memory buffer.
|
||||
- [x] SaveMultiChannelEXR
|
||||
- [x] LoadMultiChannelEXR
|
||||
- [ ] Deep image save/load
|
||||
- [ ] Tile format.
|
||||
- [ ] Support for various compression type.
|
||||
- [x] zstd compression(Not in OpenEXR spec, though)
|
||||
- [x] Tile format with no LoD (load).
|
||||
- [ ] Tile format with LoD (load).
|
||||
- [ ] Tile format with no LoD (save).
|
||||
- [ ] Tile format with LoD (save).
|
||||
- [ ] Support for custom compression type.
|
||||
- [x] zfp compression (Not in OpenEXR spec, though)
|
||||
- [ ] zstd?
|
||||
- [x] Multi-channel.
|
||||
- [ ] Multi-part (EXR2.0)
|
||||
- [x] Load multi-part image
|
||||
- [ ] Load multi-part deep image
|
||||
- [ ] Line order.
|
||||
- [x] Increasing, decreasing (load)
|
||||
- [ ] Random?
|
||||
@@ -236,9 +506,9 @@ Contribution is welcome!
|
||||
- [x] UINT, FLOAT (deep load)
|
||||
- [x] UINT, FLOAT (save)
|
||||
- [ ] UINT, FLOAT (deep save)
|
||||
- [ ] Full support for big endian machine.
|
||||
- [x] Loading multi channel EXR
|
||||
- [x] Saving multi channel EXR
|
||||
- [ ] Support for big endian machine.
|
||||
- [ ] Loading multi-part channel EXR
|
||||
- [ ] Saving multi-part channel EXR
|
||||
- [ ] Loading deep image
|
||||
- [ ] Saving deep image
|
||||
- [ ] Optimization
|
||||
@@ -248,6 +518,10 @@ Contribution is welcome!
|
||||
- [ ] OpenMP multi-threading in deep image loading.
|
||||
- [ ] OpenMP multi-threading in deep image saving.
|
||||
|
||||
## Python bindings
|
||||
|
||||
`pytinyexr` is available: https://pypi.org/project/pytinyexr/ (loading only as of 0.9.1)
|
||||
|
||||
## Similar or related projects
|
||||
|
||||
* miniexr: https://github.com/aras-p/miniexr (Write OpenEXR)
|
||||
|
||||
311
3rdparty/tinyexr/tinyexr.h
vendored
311
3rdparty/tinyexr/tinyexr.h
vendored
@@ -1,3 +1,5 @@
|
||||
#ifndef TINYEXR_H_
|
||||
#define TINYEXR_H_
|
||||
/*
|
||||
Copyright (c) 2014 - 2019, Syoyo Fujita and many contributors.
|
||||
All rights reserved.
|
||||
@@ -63,8 +65,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// End of OpenEXR license -------------------------------------------------
|
||||
|
||||
#ifndef TINYEXR_H_
|
||||
#define TINYEXR_H_
|
||||
|
||||
//
|
||||
//
|
||||
@@ -287,7 +287,7 @@ typedef struct _DeepImage {
|
||||
extern int LoadEXR(float **out_rgba, int *width, int *height,
|
||||
const char *filename, const char **err);
|
||||
|
||||
// Loads single-frame OpenEXR image by specifing layer name. Assume EXR image contains A(single channel
|
||||
// Loads single-frame OpenEXR image by specifying layer name. Assume EXR image contains A(single channel
|
||||
// alpha) or RGB(A) channels.
|
||||
// Application must free image data as returned by `out_rgba`
|
||||
// Result image format is: float x RGBA x width x hight
|
||||
@@ -302,7 +302,7 @@ extern int LoadEXRWithLayer(float **out_rgba, int *width, int *height,
|
||||
//
|
||||
// @param[out] layer_names List of layer names. Application must free memory after using this.
|
||||
// @param[out] num_layers The number of layers
|
||||
// @param[out] err Error string(wll be filled when the function returns error code). Free it using FreeEXRErrorMessage after using this value.
|
||||
// @param[out] err Error string(will be filled when the function returns error code). Free it using FreeEXRErrorMessage after using this value.
|
||||
//
|
||||
// @return TINYEXR_SUCCEES upon success.
|
||||
//
|
||||
@@ -336,13 +336,13 @@ extern void InitEXRHeader(EXRHeader *exr_header);
|
||||
// Initialize EXRImage struct
|
||||
extern void InitEXRImage(EXRImage *exr_image);
|
||||
|
||||
// Free's internal data of EXRHeader struct
|
||||
// Frees internal data of EXRHeader struct
|
||||
extern int FreeEXRHeader(EXRHeader *exr_header);
|
||||
|
||||
// Free's internal data of EXRImage struct
|
||||
// Frees internal data of EXRImage struct
|
||||
extern int FreeEXRImage(EXRImage *exr_image);
|
||||
|
||||
// Free's error message
|
||||
// Frees error message
|
||||
extern void FreeEXRErrorMessage(const char *msg);
|
||||
|
||||
// Parse EXR version header of a file.
|
||||
@@ -497,8 +497,17 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
|
||||
#endif // TINYEXR_H_
|
||||
|
||||
#ifdef TINYEXR_IMPLEMENTATION
|
||||
#ifndef TINYEXR_IMPLEMENTATION_DEIFNED
|
||||
#define TINYEXR_IMPLEMENTATION_DEIFNED
|
||||
#ifndef TINYEXR_IMPLEMENTATION_DEFINED
|
||||
#define TINYEXR_IMPLEMENTATION_DEFINED
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h> // for UTF-8
|
||||
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@@ -536,7 +545,18 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
|
||||
#endif
|
||||
|
||||
#if TINYEXR_USE_ZFP
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#endif
|
||||
|
||||
#include "zfp.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace tinyexr {
|
||||
@@ -619,7 +639,7 @@ namespace miniz {
|
||||
- Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug
|
||||
(thanks kahmyong.moon@hp.com) which could cause locate files to not find
|
||||
files. This bug
|
||||
would only have occured in earlier versions if you explicitly used this
|
||||
would only have occurred in earlier versions if you explicitly used this
|
||||
flag, OR if you used mz_zip_extract_archive_file_to_heap() or
|
||||
mz_zip_add_mem_to_archive_file_in_place()
|
||||
(which used this flag). If you can't switch to v1.15 but want to fix
|
||||
@@ -7002,6 +7022,13 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
|
||||
|
||||
// Reuse MINIZ_LITTE_ENDIAN macro
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
|
||||
defined(__i386) || defined(__i486__) || defined(__i486) || \
|
||||
defined(i386) || defined(__ia64__) || defined(__x86_64__)
|
||||
// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
|
||||
#define MINIZ_X86_OR_X64_CPU 1
|
||||
#endif
|
||||
|
||||
#if defined(__sparcv9)
|
||||
// Big endian
|
||||
#else
|
||||
@@ -7378,7 +7405,7 @@ typedef struct {
|
||||
unsigned char pad[3];
|
||||
} ChannelInfo;
|
||||
|
||||
typedef struct {
|
||||
struct HeaderInfo {
|
||||
std::vector<tinyexr::ChannelInfo> channels;
|
||||
std::vector<EXRAttribute> attributes;
|
||||
|
||||
@@ -7430,7 +7457,7 @@ typedef struct {
|
||||
header_len = 0;
|
||||
compression_type = 0;
|
||||
}
|
||||
} HeaderInfo;
|
||||
};
|
||||
|
||||
static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
|
||||
const std::vector<unsigned char> &data) {
|
||||
@@ -7712,7 +7739,7 @@ static int rleCompress(int inLength, const char in[], signed char out[]) {
|
||||
|
||||
if (runEnd - runStart >= MIN_RUN_LENGTH) {
|
||||
//
|
||||
// Compressable run
|
||||
// Compressible run
|
||||
//
|
||||
|
||||
*outWrite++ = static_cast<char>(runEnd - runStart) - 1;
|
||||
@@ -8056,7 +8083,7 @@ static void wav2Encode(
|
||||
int p2 = 2; // == 1 << (level+1)
|
||||
|
||||
//
|
||||
// Hierachical loop on smaller dimension n
|
||||
// Hierarchical loop on smaller dimension n
|
||||
//
|
||||
|
||||
while (p2 <= n) {
|
||||
@@ -8287,9 +8314,9 @@ const int HUF_DECMASK = HUF_DECSIZE - 1;
|
||||
|
||||
struct HufDec { // short code long code
|
||||
//-------------------------------
|
||||
int len : 8; // code length 0
|
||||
int lit : 24; // lit p size
|
||||
int *p; // 0 lits
|
||||
unsigned int len : 8; // code length 0
|
||||
unsigned int lit : 24; // lit p size
|
||||
unsigned int *p; // 0 lits
|
||||
};
|
||||
|
||||
inline long long hufLength(long long code) { return code & 63; }
|
||||
@@ -8745,14 +8772,14 @@ static bool hufBuildDecTable(const long long *hcode, // i : encoding table
|
||||
pl->lit++;
|
||||
|
||||
if (pl->p) {
|
||||
int *p = pl->p;
|
||||
pl->p = new int[pl->lit];
|
||||
unsigned int *p = pl->p;
|
||||
pl->p = new unsigned int[pl->lit];
|
||||
|
||||
for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i];
|
||||
|
||||
delete[] p;
|
||||
} else {
|
||||
pl->p = new int[1];
|
||||
pl->p = new unsigned int[1];
|
||||
}
|
||||
|
||||
pl->p[pl->lit - 1] = im;
|
||||
@@ -9491,35 +9518,48 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
|
||||
#endif // TINYEXR_USE_PIZ
|
||||
|
||||
#if TINYEXR_USE_ZFP
|
||||
|
||||
struct ZFPCompressionParam {
|
||||
double rate;
|
||||
int precision;
|
||||
unsigned int precision;
|
||||
unsigned int __pad0;
|
||||
double tolerance;
|
||||
int type; // TINYEXR_ZFP_COMPRESSIONTYPE_*
|
||||
unsigned int __pad1;
|
||||
|
||||
ZFPCompressionParam() {
|
||||
type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE;
|
||||
rate = 2.0;
|
||||
precision = 0;
|
||||
tolerance = 0.0f;
|
||||
tolerance = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
bool FindZFPCompressionParam(ZFPCompressionParam *param,
|
||||
static bool FindZFPCompressionParam(ZFPCompressionParam *param,
|
||||
const EXRAttribute *attributes,
|
||||
int num_attributes) {
|
||||
int num_attributes,
|
||||
std::string *err) {
|
||||
bool foundType = false;
|
||||
|
||||
for (int i = 0; i < num_attributes; i++) {
|
||||
if ((strcmp(attributes[i].name, "zfpCompressionType") == 0) &&
|
||||
(attributes[i].size == 1)) {
|
||||
if ((strcmp(attributes[i].name, "zfpCompressionType") == 0)) {
|
||||
if (attributes[i].size == 1) {
|
||||
param->type = static_cast<int>(attributes[i].value[0]);
|
||||
|
||||
foundType = true;
|
||||
break;
|
||||
} else {
|
||||
if (err) {
|
||||
(*err) += "zfpCompressionType attribute must be uchar(1 byte) type.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundType) {
|
||||
if (err) {
|
||||
(*err) += "`zfpCompressionType` attribute not found.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9531,6 +9571,11 @@ bool FindZFPCompressionParam(ZFPCompressionParam *param,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
(*err) += "`zfpCompressionRate` attribute not found.\n";
|
||||
}
|
||||
|
||||
} else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
|
||||
for (int i = 0; i < num_attributes; i++) {
|
||||
if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) &&
|
||||
@@ -9539,6 +9584,11 @@ bool FindZFPCompressionParam(ZFPCompressionParam *param,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
(*err) += "`zfpCompressionPrecision` attribute not found.\n";
|
||||
}
|
||||
|
||||
} else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
|
||||
for (int i = 0; i < num_attributes; i++) {
|
||||
if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) &&
|
||||
@@ -9547,8 +9597,14 @@ bool FindZFPCompressionParam(ZFPCompressionParam *param,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
(*err) += "`zfpCompressionTolerance` attribute not found.\n";
|
||||
}
|
||||
} else {
|
||||
assert(0);
|
||||
if (err) {
|
||||
(*err) += "Unknown value specified for `zfpCompressionType`.\n";
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -9556,10 +9612,10 @@ bool FindZFPCompressionParam(ZFPCompressionParam *param,
|
||||
|
||||
// Assume pixel format is FLOAT for all channels.
|
||||
static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
|
||||
int num_channels, const unsigned char *src,
|
||||
size_t num_channels, const unsigned char *src,
|
||||
unsigned long src_size,
|
||||
const ZFPCompressionParam ¶m) {
|
||||
size_t uncompressed_size = dst_width * dst_num_lines * num_channels;
|
||||
size_t uncompressed_size = size_t(dst_width) * size_t(dst_num_lines) * num_channels;
|
||||
|
||||
if (uncompressed_size == src_size) {
|
||||
// Data is not compressed(Issue 40).
|
||||
@@ -9572,22 +9628,22 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
|
||||
assert((dst_width % 4) == 0);
|
||||
assert((dst_num_lines % 4) == 0);
|
||||
|
||||
if ((dst_width & 3U) || (dst_num_lines & 3U)) {
|
||||
if ((size_t(dst_width) & 3U) || (size_t(dst_num_lines) & 3U)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
field =
|
||||
zfp_field_2d(reinterpret_cast<void *>(const_cast<unsigned char *>(src)),
|
||||
zfp_type_float, dst_width, dst_num_lines * num_channels);
|
||||
zfp_type_float, static_cast<unsigned int>(dst_width), static_cast<unsigned int>(dst_num_lines) * static_cast<unsigned int>(num_channels));
|
||||
zfp = zfp_stream_open(NULL);
|
||||
|
||||
if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
|
||||
zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimention */ 2,
|
||||
zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimension */ 2,
|
||||
/* write random access */ 0);
|
||||
} else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
|
||||
zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
|
||||
zfp_stream_set_precision(zfp, param.precision);
|
||||
} else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
|
||||
zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
|
||||
zfp_stream_set_accuracy(zfp, param.tolerance);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
@@ -9600,17 +9656,17 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
|
||||
zfp_stream_set_bit_stream(zfp, stream);
|
||||
zfp_stream_rewind(zfp);
|
||||
|
||||
size_t image_size = dst_width * dst_num_lines;
|
||||
size_t image_size = size_t(dst_width) * size_t(dst_num_lines);
|
||||
|
||||
for (int c = 0; c < num_channels; c++) {
|
||||
for (size_t c = 0; c < size_t(num_channels); c++) {
|
||||
// decompress 4x4 pixel block.
|
||||
for (int y = 0; y < dst_num_lines; y += 4) {
|
||||
for (int x = 0; x < dst_width; x += 4) {
|
||||
for (size_t y = 0; y < size_t(dst_num_lines); y += 4) {
|
||||
for (size_t x = 0; x < size_t(dst_width); x += 4) {
|
||||
float fblock[16];
|
||||
zfp_decode_block_float_2(zfp, fblock);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dst[c * image_size + ((y + j) * dst_width + (x + i))] =
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
dst[c * image_size + ((y + j) * size_t(dst_width) + (x + i))] =
|
||||
fblock[j * 4 + i];
|
||||
}
|
||||
}
|
||||
@@ -9626,7 +9682,7 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
|
||||
}
|
||||
|
||||
// Assume pixel format is FLOAT for all channels.
|
||||
bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
|
||||
static bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
|
||||
const float *inPtr, int width, int num_lines, int num_channels,
|
||||
const ZFPCompressionParam ¶m) {
|
||||
zfp_stream *zfp = NULL;
|
||||
@@ -9635,22 +9691,22 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
|
||||
assert((width % 4) == 0);
|
||||
assert((num_lines % 4) == 0);
|
||||
|
||||
if ((width & 3U) || (num_lines & 3U)) {
|
||||
if ((size_t(width) & 3U) || (size_t(num_lines) & 3U)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create input array.
|
||||
field = zfp_field_2d(reinterpret_cast<void *>(const_cast<float *>(inPtr)),
|
||||
zfp_type_float, width, num_lines * num_channels);
|
||||
zfp_type_float, static_cast<unsigned int>(width), static_cast<unsigned int>(num_lines * num_channels));
|
||||
|
||||
zfp = zfp_stream_open(NULL);
|
||||
|
||||
if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
|
||||
zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0);
|
||||
} else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
|
||||
zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
|
||||
zfp_stream_set_precision(zfp, param.precision);
|
||||
} else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
|
||||
zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
|
||||
zfp_stream_set_accuracy(zfp, param.tolerance);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
@@ -9663,17 +9719,17 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
|
||||
zfp_stream_set_bit_stream(zfp, stream);
|
||||
zfp_field_free(field);
|
||||
|
||||
size_t image_size = width * num_lines;
|
||||
size_t image_size = size_t(width) * size_t(num_lines);
|
||||
|
||||
for (int c = 0; c < num_channels; c++) {
|
||||
for (size_t c = 0; c < size_t(num_channels); c++) {
|
||||
// compress 4x4 pixel block.
|
||||
for (int y = 0; y < num_lines; y += 4) {
|
||||
for (int x = 0; x < width; x += 4) {
|
||||
for (size_t y = 0; y < size_t(num_lines); y += 4) {
|
||||
for (size_t x = 0; x < size_t(width); x += 4) {
|
||||
float fblock[16];
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
fblock[j * 4 + i] =
|
||||
inPtr[c * image_size + ((y + j) * width + (x + i))];
|
||||
inPtr[c * image_size + ((y + j) * size_t(width) + (x + i))];
|
||||
}
|
||||
}
|
||||
zfp_encode_block_float_2(zfp, fblock);
|
||||
@@ -9682,7 +9738,7 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
|
||||
}
|
||||
|
||||
zfp_stream_flush(zfp);
|
||||
(*outSize) = zfp_stream_compressed_size(zfp);
|
||||
(*outSize) = static_cast<unsigned int>(zfp_stream_compressed_size(zfp));
|
||||
|
||||
zfp_stream_close(zfp);
|
||||
|
||||
@@ -10122,8 +10178,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
|
||||
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
|
||||
#if TINYEXR_USE_ZFP
|
||||
tinyexr::ZFPCompressionParam zfp_compression_param;
|
||||
if (!FindZFPCompressionParam(&zfp_compression_param, attributes,
|
||||
num_attributes)) {
|
||||
std::string e;
|
||||
if (!tinyexr::FindZFPCompressionParam(&zfp_compression_param, attributes,
|
||||
int(num_attributes), &e)) {
|
||||
// This code path should not be reachable.
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
@@ -10418,6 +10476,18 @@ static unsigned char **AllocateImage(int num_channels,
|
||||
return images;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static inline std::wstring UTF8ToWchar(const std::string &str) {
|
||||
int wstr_size =
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), NULL, 0);
|
||||
std::wstring wstr(wstr_size, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0],
|
||||
(int)wstr.size());
|
||||
return wstr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
|
||||
const EXRVersion *version, std::string *err,
|
||||
const unsigned char *buf, size_t size) {
|
||||
@@ -10798,7 +10868,7 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
|
||||
memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type,
|
||||
256);
|
||||
exr_header->custom_attributes[i].size = info.attributes[i].size;
|
||||
// Just copy poiner
|
||||
// Just copy pointer
|
||||
exr_header->custom_attributes[i].value = info.attributes[i].value;
|
||||
}
|
||||
|
||||
@@ -10822,7 +10892,16 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
|
||||
num_scanline_blocks = 32;
|
||||
} else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
|
||||
num_scanline_blocks = 16;
|
||||
|
||||
#if TINYEXR_USE_ZFP
|
||||
tinyexr::ZFPCompressionParam zfp_compression_param;
|
||||
if (!FindZFPCompressionParam(&zfp_compression_param, exr_header->custom_attributes,
|
||||
int(exr_header->num_custom_attributes), err)) {
|
||||
return TINYEXR_ERROR_INVALID_HEADER;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1;
|
||||
int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1;
|
||||
@@ -11947,11 +12026,21 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, filename, "rb");
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t errcode = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
|
||||
if (errcode != 0) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
// TODO(syoyo): return wfopen_s erro code
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
#else
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
@@ -12213,9 +12302,10 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
|
||||
// Use ZFP compression parameter from custom attributes(if such a parameter
|
||||
// exists)
|
||||
{
|
||||
std::string e;
|
||||
bool ret = tinyexr::FindZFPCompressionParam(
|
||||
&zfp_compression_param, exr_header->custom_attributes,
|
||||
exr_header->num_custom_attributes);
|
||||
exr_header->num_custom_attributes, &e);
|
||||
|
||||
if (!ret) {
|
||||
// Use predefined compression parameter.
|
||||
@@ -12225,7 +12315,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
|
||||
}
|
||||
#endif
|
||||
|
||||
// TOOD(LTE): C++11 thread
|
||||
// TODO(LTE): C++11 thread
|
||||
|
||||
// Use signed int since some OpenMP compiler doesn't allow unsigned type for
|
||||
// `parallel for`
|
||||
@@ -12538,14 +12628,23 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, filename, "wb");
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t errcode = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb");
|
||||
if (errcode != 0) {
|
||||
tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), err);
|
||||
return TINYEXR_ERROR_CANT_WRITE_FILE;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "wb");
|
||||
#endif
|
||||
#else
|
||||
fp = fopen(filename, "wb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot write a file", err);
|
||||
tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), err);
|
||||
return TINYEXR_ERROR_CANT_WRITE_FILE;
|
||||
}
|
||||
|
||||
@@ -12577,10 +12676,20 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
errno_t errcode = fopen_s(&fp, filename, "rb");
|
||||
if ((0 != errcode) || (!fp)) {
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t errcode = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
|
||||
if (errcode != 0) {
|
||||
tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
|
||||
err);
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
#else
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
|
||||
err);
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
@@ -13054,11 +13163,20 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, filename, "rb");
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t errcode = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
|
||||
if (errcode != 0) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
return TINYEXR_ERROR_INVALID_FILE;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
#else
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
@@ -13174,11 +13292,20 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, filename, "rb");
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t errcode = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
|
||||
if (errcode != 0) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
return TINYEXR_ERROR_INVALID_FILE;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
#else
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
@@ -13270,11 +13397,20 @@ int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) {
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, filename, "rb");
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t err = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
|
||||
if (err != 0) {
|
||||
// TODO(syoyo): return wfopen_s erro code
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
#else
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
@@ -13408,11 +13544,20 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, filename, "rb");
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
|
||||
errno_t errcode = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
|
||||
if (errcode != 0) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
// Unknown compiler
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
#else
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
|
||||
@@ -13582,5 +13727,5 @@ int SaveEXR(const float *data, int width, int height, int components,
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // TINYEXR_IMPLEMENTATION_DEIFNED
|
||||
#endif // TINYEXR_IMPLEMENTATION_DEFINED
|
||||
#endif // TINYEXR_IMPLEMENTATION
|
||||
|
||||
Reference in New Issue
Block a user