|
shun-iwasawa |
7bad49 |
#ifndef TINYEXR_OTMOD_H_
|
|
shun-iwasawa |
7bad49 |
#define TINYEXR_OTMOD_H_
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#define TINYEXR_IMPLEMENTATION
|
|
shun-iwasawa |
7bad49 |
#include "tinyexr.h"
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
/*
|
|
shun-iwasawa |
7bad49 |
* This source is based on TinyEXR code, enabling to use file handle
|
|
shun-iwasawa |
7bad49 |
* as an argument instead of file path in order to fit usage in OpenToonz.
|
|
shun-iwasawa |
7bad49 |
* TinyEXR code is licensed under the following:
|
|
shun-iwasawa |
7bad49 |
*/
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// Start of TinyEXR license -------------------------------------------------
|
|
shun-iwasawa |
7bad49 |
/*
|
|
shun-iwasawa |
7bad49 |
Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
|
|
shun-iwasawa |
7bad49 |
All rights reserved.
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
Redistribution and use in source and binary forms, with or without
|
|
shun-iwasawa |
7bad49 |
modification, are permitted provided that the following conditions are met:
|
|
shun-iwasawa |
7bad49 |
* Redistributions of source code must retain the above copyright
|
|
shun-iwasawa |
7bad49 |
notice, this list of conditions and the following disclaimer.
|
|
shun-iwasawa |
7bad49 |
* Redistributions in binary form must reproduce the above copyright
|
|
shun-iwasawa |
7bad49 |
notice, this list of conditions and the following disclaimer in the
|
|
shun-iwasawa |
7bad49 |
documentation and/or other materials provided with the distribution.
|
|
shun-iwasawa |
7bad49 |
* Neither the name of the Syoyo Fujita nor the
|
|
shun-iwasawa |
7bad49 |
names of its contributors may be used to endorse or promote products
|
|
shun-iwasawa |
7bad49 |
derived from this software without specific prior written permission.
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
shun-iwasawa |
7bad49 |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
shun-iwasawa |
7bad49 |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
shun-iwasawa |
7bad49 |
DISCLAIMED. IN NO EVENT SHALL <copyright holder=""> BE LIABLE FOR ANY</copyright>
|
|
shun-iwasawa |
7bad49 |
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
shun-iwasawa |
7bad49 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
shun-iwasawa |
7bad49 |
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
shun-iwasawa |
7bad49 |
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
shun-iwasawa |
7bad49 |
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
shun-iwasawa |
7bad49 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
shun-iwasawa |
7bad49 |
*/
|
|
shun-iwasawa |
7bad49 |
// End of TinyEXR license -------------------------------------------------
|
|
shun-iwasawa |
7bad49 |
// TinyEXR contains some OpenEXR code, which is licensed under ------------
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
///////////////////////////////////////////////////////////////////////////
|
|
shun-iwasawa |
7bad49 |
//
|
|
shun-iwasawa |
7bad49 |
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
|
|
shun-iwasawa |
7bad49 |
// Digital Ltd. LLC
|
|
shun-iwasawa |
7bad49 |
//
|
|
shun-iwasawa |
7bad49 |
// All rights reserved.
|
|
shun-iwasawa |
7bad49 |
//
|
|
shun-iwasawa |
7bad49 |
// Redistribution and use in source and binary forms, with or without
|
|
shun-iwasawa |
7bad49 |
// modification, are permitted provided that the following conditions are
|
|
shun-iwasawa |
7bad49 |
// met:
|
|
shun-iwasawa |
7bad49 |
// * Redistributions of source code must retain the above copyright
|
|
shun-iwasawa |
7bad49 |
// notice, this list of conditions and the following disclaimer.
|
|
shun-iwasawa |
7bad49 |
// * Redistributions in binary form must reproduce the above
|
|
shun-iwasawa |
7bad49 |
// copyright notice, this list of conditions and the following disclaimer
|
|
shun-iwasawa |
7bad49 |
// in the documentation and/or other materials provided with the
|
|
shun-iwasawa |
7bad49 |
// distribution.
|
|
shun-iwasawa |
7bad49 |
// * Neither the name of Industrial Light & Magic nor the names of
|
|
shun-iwasawa |
7bad49 |
// its contributors may be used to endorse or promote products derived
|
|
shun-iwasawa |
7bad49 |
// from this software without specific prior written permission.
|
|
shun-iwasawa |
7bad49 |
//
|
|
shun-iwasawa |
7bad49 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
shun-iwasawa |
7bad49 |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
shun-iwasawa |
7bad49 |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
shun-iwasawa |
7bad49 |
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
shun-iwasawa |
7bad49 |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
shun-iwasawa |
7bad49 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
shun-iwasawa |
7bad49 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
shun-iwasawa |
7bad49 |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
shun-iwasawa |
7bad49 |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
shun-iwasawa |
7bad49 |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
shun-iwasawa |
7bad49 |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
shun-iwasawa |
7bad49 |
//
|
|
shun-iwasawa |
7bad49 |
///////////////////////////////////////////////////////////////////////////
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// End of OpenEXR license -------------------------------------------------
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#ifdef __cplusplus
|
|
shun-iwasawa |
7bad49 |
extern "C" {
|
|
shun-iwasawa |
7bad49 |
#endif
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
extern int ParseEXRVersionFromFileHandle(EXRVersion *version, FILE *fp);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
extern int ParseEXRHeaderFromFileHandle(EXRHeader *exr_header,
|
|
shun-iwasawa |
7bad49 |
const EXRVersion *exr_version, FILE *fp,
|
|
shun-iwasawa |
7bad49 |
const char **err);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
extern int LoadEXRImageFromFileHandle(EXRImage *exr_image,
|
|
shun-iwasawa |
7bad49 |
const EXRHeader *exr_header, FILE *fp,
|
|
shun-iwasawa |
7bad49 |
const char **err);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
extern int LoadEXRHeaderFromFileHandle(EXRHeader &exr_header, FILE *file,
|
|
shun-iwasawa |
7bad49 |
const char **err);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
extern int LoadEXRImageBufFromFileHandle(float **out_rgba,
|
|
shun-iwasawa |
7bad49 |
EXRHeader &exr_header, FILE *file,
|
|
shun-iwasawa |
7bad49 |
const char **err);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
extern int SaveEXRImageToFileHandle(const EXRImage *exr_image,
|
|
shun-iwasawa |
7bad49 |
const EXRHeader *exr_header, FILE *fp,
|
|
shun-iwasawa |
7bad49 |
const char **err);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#ifdef __cplusplus
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
#endif
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#endif // TINYEXR_OTMOD_H_
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#ifdef TINYEXR_OTMOD_IMPLEMENTATION
|
|
shun-iwasawa |
7bad49 |
#ifndef TINYEXR_OTMOD_IMPLEMENTATION_DEFINED
|
|
shun-iwasawa |
7bad49 |
#define TINYEXR_OTMOD_IMPLEMENTATION_DEFINED
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int ParseEXRVersionFromFileHandle(EXRVersion *version, FILE *fp) {
|
|
shun-iwasawa |
7bad49 |
if (!fp) {
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
size_t file_size;
|
|
shun-iwasawa |
7bad49 |
// Compute size
|
|
shun-iwasawa |
7bad49 |
fseek(fp, 0, SEEK_END);
|
|
shun-iwasawa |
7bad49 |
file_size = static_cast<size_t>(ftell(fp));</size_t>
|
|
shun-iwasawa |
7bad49 |
fseek(fp, 0, SEEK_SET);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (file_size < tinyexr::kEXRVersionSize) {
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
unsigned char buf[tinyexr::kEXRVersionSize];
|
|
shun-iwasawa |
7bad49 |
size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp);
|
|
shun-iwasawa |
7bad49 |
// fclose(fp);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (ret != tinyexr::kEXRVersionSize) {
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int ParseEXRHeaderFromFileHandle(EXRHeader *exr_header,
|
|
shun-iwasawa |
7bad49 |
const EXRVersion *exr_version, FILE *fp,
|
|
shun-iwasawa |
7bad49 |
const char **err) {
|
|
shun-iwasawa |
7bad49 |
if (exr_header == NULL || exr_version == NULL) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
|
|
shun-iwasawa |
7bad49 |
err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
if (!fp) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Cannot read file ", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
size_t filesize;
|
|
shun-iwasawa |
7bad49 |
// Compute size
|
|
shun-iwasawa |
7bad49 |
fseek(fp, 0, SEEK_END);
|
|
shun-iwasawa |
7bad49 |
filesize = static_cast<size_t>(ftell(fp));</size_t>
|
|
shun-iwasawa |
7bad49 |
fseek(fp, 0, SEEK_SET);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
std::vector<unsigned char=""> buf(filesize); // @todo { use mmap }</unsigned>
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
size_t ret;
|
|
shun-iwasawa |
7bad49 |
ret = fread(&buf[0], 1, filesize, fp);
|
|
shun-iwasawa |
7bad49 |
assert(ret == filesize);
|
|
shun-iwasawa |
7bad49 |
// fclose(fp);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (ret != filesize) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("fread() error", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize,
|
|
shun-iwasawa |
7bad49 |
err);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int LoadEXRImageFromFileHandle(EXRImage *exr_image, const EXRHeader *exr_header,
|
|
shun-iwasawa |
7bad49 |
FILE *fp, const char **err) {
|
|
shun-iwasawa |
7bad49 |
if (exr_image == NULL) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (!fp) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Cannot read file", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
size_t filesize;
|
|
shun-iwasawa |
7bad49 |
// Compute size
|
|
shun-iwasawa |
7bad49 |
fseek(fp, 0, SEEK_END);
|
|
shun-iwasawa |
7bad49 |
filesize = static_cast<size_t>(ftell(fp));</size_t>
|
|
shun-iwasawa |
7bad49 |
fseek(fp, 0, SEEK_SET);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (filesize < 16) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("File size too short", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
std::vector<unsigned char=""> buf(filesize); // @todo { use mmap }</unsigned>
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
size_t ret;
|
|
shun-iwasawa |
7bad49 |
ret = fread(&buf[0], 1, filesize, fp);
|
|
shun-iwasawa |
7bad49 |
assert(ret == filesize);
|
|
shun-iwasawa |
7bad49 |
// fclose(fp);
|
|
shun-iwasawa |
7bad49 |
(void)ret;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize,
|
|
shun-iwasawa |
7bad49 |
err);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int LoadEXRHeaderFromFileHandle(EXRHeader &exr_header, FILE *file,
|
|
shun-iwasawa |
7bad49 |
const char **err) {
|
|
shun-iwasawa |
7bad49 |
EXRVersion exr_version;
|
|
shun-iwasawa |
7bad49 |
InitEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
FILE *_fp = file;
|
|
shun-iwasawa |
7bad49 |
int ret = ParseEXRVersionFromFileHandle(&exr_version, _fp);
|
|
shun-iwasawa |
7bad49 |
if (ret != TINYEXR_SUCCESS) {
|
|
shun-iwasawa |
7bad49 |
std::stringstream ss;
|
|
shun-iwasawa |
7bad49 |
ss << "Failed to open EXR file or read version info from EXR file. code("
|
|
shun-iwasawa |
7bad49 |
<< ret << ")";
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage(ss.str(), err);
|
|
shun-iwasawa |
7bad49 |
return ret;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (exr_version.multipart || exr_version.non_image) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage(
|
|
shun-iwasawa |
7bad49 |
"Loading multipart or DeepImage is not supported in LoadEXR() API",
|
|
shun-iwasawa |
7bad49 |
err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_DATA; // @fixme.
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
FILE *_fp = file;
|
|
shun-iwasawa |
7bad49 |
int ret = ParseEXRHeaderFromFileHandle(&exr_header, &exr_version, _fp, err);
|
|
shun-iwasawa |
7bad49 |
if (ret != TINYEXR_SUCCESS) {
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
return ret;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_SUCCESS;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int LoadEXRImageBufFromFileHandle(float **out_rgba, EXRHeader &exr_header,
|
|
shun-iwasawa |
7bad49 |
FILE *file, const char **err) {
|
|
shun-iwasawa |
7bad49 |
if (out_rgba == NULL) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
EXRImage exr_image;
|
|
shun-iwasawa |
7bad49 |
InitEXRImage(&exr_image);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// Read HALF channel as FLOAT.
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < exr_header.num_channels; i++) {
|
|
shun-iwasawa |
7bad49 |
if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
|
|
shun-iwasawa |
7bad49 |
exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// TODO: Probably limit loading to layers (channels) selected by layer index
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
FILE *_fp = file;
|
|
shun-iwasawa |
7bad49 |
int ret = LoadEXRImageFromFileHandle(&exr_image, &exr_header, _fp, err);
|
|
shun-iwasawa |
7bad49 |
if (ret != TINYEXR_SUCCESS) {
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
return ret;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// RGBA
|
|
shun-iwasawa |
7bad49 |
int idxR = -1;
|
|
shun-iwasawa |
7bad49 |
int idxG = -1;
|
|
shun-iwasawa |
7bad49 |
int idxB = -1;
|
|
shun-iwasawa |
7bad49 |
int idxA = -1;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
std::vector<std::string> layer_names;</std::string>
|
|
shun-iwasawa |
7bad49 |
tinyexr::GetLayers(exr_header, layer_names);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
std::vector<tinyexr::layerchannel> channels;</tinyexr::layerchannel>
|
|
shun-iwasawa |
7bad49 |
tinyexr::ChannelsInLayer(exr_header, "", channels);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (channels.size() < 1) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Layer Not Found", err);
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
FreeEXRImage(&exr_image);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_LAYER_NOT_FOUND;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
size_t ch_count = channels.size() < 4 ? channels.size() : 4;
|
|
shun-iwasawa |
7bad49 |
for (size_t c = 0; c < ch_count; c++) {
|
|
shun-iwasawa |
7bad49 |
const tinyexr::LayerChannel &ch = channels[c];
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (ch.name == "R") {
|
|
shun-iwasawa |
7bad49 |
idxR = int(ch.index);
|
|
shun-iwasawa |
7bad49 |
} else if (ch.name == "G") {
|
|
shun-iwasawa |
7bad49 |
idxG = int(ch.index);
|
|
shun-iwasawa |
7bad49 |
} else if (ch.name == "B") {
|
|
shun-iwasawa |
7bad49 |
idxB = int(ch.index);
|
|
shun-iwasawa |
7bad49 |
} else if (ch.name == "A") {
|
|
shun-iwasawa |
7bad49 |
idxA = int(ch.index);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (channels.size() == 1) {
|
|
shun-iwasawa |
7bad49 |
int chIdx = int(channels.front().index);
|
|
shun-iwasawa |
7bad49 |
// Grayscale channel only.
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
(*out_rgba) = reinterpret_cast<float *="">(</float>
|
|
shun-iwasawa |
7bad49 |
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *</size_t>
|
|
shun-iwasawa |
7bad49 |
static_cast<size_t>(exr_image.height)));</size_t>
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (exr_header.tiled) {
|
|
shun-iwasawa |
7bad49 |
for (int it = 0; it < exr_image.num_tiles; it++) {
|
|
shun-iwasawa |
7bad49 |
for (int j = 0; j < exr_header.tile_size_y; j++) {
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < exr_header.tile_size_x; i++) {
|
|
shun-iwasawa |
7bad49 |
const int ii = exr_image.tiles[it].offset_x *
|
|
shun-iwasawa |
7bad49 |
static_cast<int>(exr_header.tile_size_x) +</int>
|
|
shun-iwasawa |
7bad49 |
i;
|
|
shun-iwasawa |
7bad49 |
const int jj = exr_image.tiles[it].offset_y *
|
|
shun-iwasawa |
7bad49 |
static_cast<int>(exr_header.tile_size_y) +</int>
|
|
shun-iwasawa |
7bad49 |
j;
|
|
shun-iwasawa |
7bad49 |
const int idx = ii + jj * static_cast<int>(exr_image.width);</int>
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// out of region check.
|
|
shun-iwasawa |
7bad49 |
if (ii >= exr_image.width) {
|
|
shun-iwasawa |
7bad49 |
continue;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
if (jj >= exr_image.height) {
|
|
shun-iwasawa |
7bad49 |
continue;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
const int srcIdx = i + j * exr_header.tile_size_x;
|
|
shun-iwasawa |
7bad49 |
unsigned char **src = exr_image.tiles[it].images;
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 0] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[chIdx][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 1] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[chIdx][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 2] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[chIdx][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 3] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[chIdx][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
|
|
shun-iwasawa |
7bad49 |
const float val =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(exr_image.images)[chIdx][i];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 0] = val;
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 1] = val;
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 2] = val;
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 3] = val;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
// Assume RGB(A)
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (idxR == -1) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("R channel not found", err);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
FreeEXRImage(&exr_image);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_DATA;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (idxG == -1) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("G channel not found", err);
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
FreeEXRImage(&exr_image);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_DATA;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (idxB == -1) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("B channel not found", err);
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
FreeEXRImage(&exr_image);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_DATA;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
(*out_rgba) = reinterpret_cast<float *="">(</float>
|
|
shun-iwasawa |
7bad49 |
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *</size_t>
|
|
shun-iwasawa |
7bad49 |
static_cast<size_t>(exr_image.height)));</size_t>
|
|
shun-iwasawa |
7bad49 |
if (exr_header.tiled) {
|
|
shun-iwasawa |
7bad49 |
for (int it = 0; it < exr_image.num_tiles; it++) {
|
|
shun-iwasawa |
7bad49 |
for (int j = 0; j < exr_header.tile_size_y; j++) {
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < exr_header.tile_size_x; i++) {
|
|
shun-iwasawa |
7bad49 |
const int ii =
|
|
shun-iwasawa |
7bad49 |
exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
|
|
shun-iwasawa |
7bad49 |
const int jj =
|
|
shun-iwasawa |
7bad49 |
exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
|
|
shun-iwasawa |
7bad49 |
const int idx = ii + jj * exr_image.width;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// out of region check.
|
|
shun-iwasawa |
7bad49 |
if (ii >= exr_image.width) {
|
|
shun-iwasawa |
7bad49 |
continue;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
if (jj >= exr_image.height) {
|
|
shun-iwasawa |
7bad49 |
continue;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
const int srcIdx = i + j * exr_header.tile_size_x;
|
|
shun-iwasawa |
7bad49 |
unsigned char **src = exr_image.tiles[it].images;
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 0] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[idxR][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 1] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[idxG][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 2] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[idxB][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
if (idxA != -1) {
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 3] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(src)[idxA][srcIdx];</float>
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * idx + 3] = 1.0;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 0] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(exr_image.images)[idxR][i];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 1] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(exr_image.images)[idxG][i];</float>
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 2] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(exr_image.images)[idxB][i];</float>
|
|
shun-iwasawa |
7bad49 |
if (idxA != -1) {
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 3] =
|
|
shun-iwasawa |
7bad49 |
reinterpret_cast<float **="">(exr_image.images)[idxA][i];</float>
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
(*out_rgba)[4 * i + 3] = 1.0;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
FreeEXRHeader(&exr_header);
|
|
shun-iwasawa |
7bad49 |
FreeEXRImage(&exr_image);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_SUCCESS;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int SaveEXRImageToFileHandle(const EXRImage *exr_image,
|
|
shun-iwasawa |
7bad49 |
const EXRHeader *exr_header, FILE *fp,
|
|
shun-iwasawa |
7bad49 |
const char **err) {
|
|
shun-iwasawa |
7bad49 |
if (exr_image == NULL || exr_header->compression_type < 0) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#if !TINYEXR_USE_PIZ
|
|
shun-iwasawa |
7bad49 |
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
|
|
shun-iwasawa |
7bad49 |
err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
#endif
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#if !TINYEXR_USE_ZFP
|
|
shun-iwasawa |
7bad49 |
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
|
|
shun-iwasawa |
7bad49 |
err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
#endif
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (!fp) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Cannot write a file", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_CANT_WRITE_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
unsigned char *mem = NULL;
|
|
shun-iwasawa |
7bad49 |
size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
|
|
shun-iwasawa |
7bad49 |
if (mem_size == 0) {
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_SERIALZATION_FAILED;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
size_t written_size = 0;
|
|
shun-iwasawa |
7bad49 |
if ((mem_size > 0) && mem) {
|
|
shun-iwasawa |
7bad49 |
written_size = fwrite(mem, 1, mem_size, fp);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
free(mem);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// fclose(fp);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (written_size != mem_size) {
|
|
shun-iwasawa |
7bad49 |
tinyexr::SetErrorMessage("Cannot write a file", err);
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_ERROR_CANT_WRITE_FILE;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return TINYEXR_SUCCESS;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#endif // TINYEXR_OTMOD_IMPLEMENTATION_DEFINED
|
|
shun-iwasawa |
7bad49 |
#endif // TINYEXR_OTMOD_IMPLEMENTATION
|