OpenEXR I/O
This commit is contained in:
parent
5ba47b0238
commit
594093c66c
62
stuff/doc/LICENSE/LICENSE_tinyexr_openexr.txt
Normal file
62
stuff/doc/LICENSE/LICENSE_tinyexr_openexr.txt
Normal file
|
@ -0,0 +1,62 @@
|
|||
tinyexr : Tiny OpenEXR image loader/saver library
|
||||
https://github.com/syoyo/tinyexr
|
||||
|
||||
Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Syoyo Fujita nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
tinyexr contains some OpenEXR code, which is licensed as follows.
|
||||
Note that OpenEXR had joined Academy Software Foudation projects in 2019.
|
||||
The latest code of OpenEXR can be found in
|
||||
https://github.com/AcademySoftwareFoundation/openexr .
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
OpenEXR
|
||||
|
||||
Copyright (c) 2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Industrial Light & Magic nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
8530
thirdparty/tinyexr/tinyexr.h
vendored
Normal file
8530
thirdparty/tinyexr/tinyexr.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -420,7 +420,9 @@ TImageP TImageReader::load0() {
|
|||
// assert(info.m_samplePerPixel == 3 || info.m_samplePerPixel == 4);
|
||||
|
||||
TRasterP _ras;
|
||||
if (info.m_bitsPerSample == 16) {
|
||||
// currently m_bitsPerSample == 32 is only possible when loading
|
||||
// full-float / uint EXR images
|
||||
if (info.m_bitsPerSample == 16 || info.m_bitsPerSample == 32) {
|
||||
if (m_is64BitEnabled || m_path.getType() != "tif") {
|
||||
// Standard 64-bit case.
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ set(HEADERS
|
|||
ffmpeg/tiio_ffmpeg.h
|
||||
sprite/tiio_sprite.h
|
||||
mesh/tiio_mesh.h
|
||||
exr/tinyexr_otmod.h
|
||||
exr/tiio_exr.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
|
@ -47,6 +49,7 @@ set(SOURCES
|
|||
ffmpeg/tiio_ffmpeg.cpp
|
||||
sprite/tiio_sprite.cpp
|
||||
mesh/tiio_mesh.cpp
|
||||
exr/tiio_exr.cpp
|
||||
)
|
||||
|
||||
|
||||
|
@ -121,6 +124,10 @@ if(BUILD_TARGET_WIN AND PLATFORM EQUAL 32)
|
|||
)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${SDKROOT}/tinyexr
|
||||
)
|
||||
|
||||
|
||||
_find_toonz_library(TNZLIBS "tnzcore;tnzbase;toonzlib")
|
||||
|
||||
|
|
426
toonz/sources/image/exr/tiio_exr.cpp
Normal file
426
toonz/sources/image/exr/tiio_exr.cpp
Normal file
|
@ -0,0 +1,426 @@
|
|||
#define TINYEXR_USE_MINIZ 0
|
||||
#include "zlib.h"
|
||||
|
||||
#define TINYEXR_OTMOD_IMPLEMENTATION
|
||||
#include "tinyexr_otmod.h"
|
||||
|
||||
#include "tiio_exr.h"
|
||||
#include "tpixel.h"
|
||||
|
||||
#include <QMap>
|
||||
|
||||
namespace {
|
||||
inline unsigned char ftouc(float f, float gamma = 2.2f) {
|
||||
int i = static_cast<int>(255.0f * powf(f, 1.0f / gamma));
|
||||
if (i > 255) i = 255;
|
||||
if (i < 0) i = 0;
|
||||
|
||||
return static_cast<unsigned char>(i);
|
||||
}
|
||||
inline float uctof(unsigned char uc, float gamma = 2.2f) {
|
||||
return powf(static_cast<float>(uc) / 255.0f, gamma);
|
||||
}
|
||||
|
||||
inline unsigned short ftous(float f, float gamma = 2.2f) {
|
||||
int i = static_cast<int>(65535.0f * powf(f, 1.0f / gamma));
|
||||
if (i > 65535) i = 65535;
|
||||
if (i < 0) i = 0;
|
||||
|
||||
return static_cast<unsigned short>(i);
|
||||
}
|
||||
inline float ustof(unsigned short us, float gamma = 2.2f) {
|
||||
return powf(static_cast<float>(us) / 65535.0f, gamma);
|
||||
}
|
||||
|
||||
const QMap<int, std::wstring> ExrCompTypeStr = {
|
||||
{TINYEXR_COMPRESSIONTYPE_NONE, L"None"},
|
||||
{TINYEXR_COMPRESSIONTYPE_RLE, L"RLE"},
|
||||
{TINYEXR_COMPRESSIONTYPE_ZIPS, L"ZIPS"},
|
||||
{TINYEXR_COMPRESSIONTYPE_ZIP, L"ZIP"},
|
||||
{TINYEXR_COMPRESSIONTYPE_PIZ, L"PIZ"}};
|
||||
|
||||
const std::wstring EXR_STORAGETYPE_SCANLINE = L"Store Image as Scanlines";
|
||||
const std::wstring EXR_STORAGETYPE_TILE = L"Store Image as Tiles";
|
||||
} // namespace
|
||||
|
||||
//**************************************************************************
|
||||
// ExrReader implementation
|
||||
//**************************************************************************
|
||||
|
||||
class ExrReader final : public Tiio::Reader {
|
||||
float* m_rgbaBuf;
|
||||
int m_row;
|
||||
EXRHeader* m_exr_header;
|
||||
FILE* m_fp;
|
||||
|
||||
public:
|
||||
ExrReader();
|
||||
~ExrReader();
|
||||
|
||||
void open(FILE* file) override;
|
||||
Tiio::RowOrder getRowOrder() const override;
|
||||
bool read16BitIsEnabled() const override;
|
||||
int skipLines(int lineCount) override;
|
||||
;
|
||||
void readLine(char* buffer, int x0, int x1, int shrink) override;
|
||||
void readLine(short* buffer, int x0, int x1, int shrink) override;
|
||||
void loadImage();
|
||||
};
|
||||
|
||||
ExrReader::ExrReader() : m_rgbaBuf(nullptr), m_row(0), m_exr_header(nullptr) {}
|
||||
|
||||
ExrReader::~ExrReader() {
|
||||
if (m_rgbaBuf) free(m_rgbaBuf);
|
||||
if (m_exr_header) FreeEXRHeader(m_exr_header);
|
||||
}
|
||||
|
||||
void ExrReader::open(FILE* file) {
|
||||
m_fp = file;
|
||||
m_exr_header = new EXRHeader();
|
||||
const char* err;
|
||||
{
|
||||
int ret = LoadEXRHeaderFromFileHandle(*m_exr_header, file, &err);
|
||||
if (ret != 0) {
|
||||
m_exr_header = nullptr;
|
||||
throw(std::string(err));
|
||||
}
|
||||
}
|
||||
m_info.m_lx =
|
||||
m_exr_header->data_window.max_x - m_exr_header->data_window.min_x + 1;
|
||||
m_info.m_ly =
|
||||
m_exr_header->data_window.max_y - m_exr_header->data_window.min_y + 1;
|
||||
|
||||
m_info.m_samplePerPixel = m_exr_header->num_channels;
|
||||
|
||||
int bps = 16;
|
||||
switch (m_exr_header->pixel_types[0]) {
|
||||
case TINYEXR_PIXELTYPE_UINT:
|
||||
case TINYEXR_PIXELTYPE_FLOAT:
|
||||
bps = 32;
|
||||
break;
|
||||
case TINYEXR_PIXELTYPE_HALF:
|
||||
bps = 16;
|
||||
break;
|
||||
}
|
||||
m_info.m_bitsPerSample = bps;
|
||||
}
|
||||
|
||||
Tiio::RowOrder ExrReader::getRowOrder() const { return Tiio::TOP2BOTTOM; }
|
||||
|
||||
bool ExrReader::read16BitIsEnabled() const { return true; }
|
||||
|
||||
int ExrReader::skipLines(int lineCount) {
|
||||
m_row += lineCount;
|
||||
return lineCount;
|
||||
}
|
||||
|
||||
void ExrReader::loadImage() {
|
||||
assert(!m_rgbaBuf);
|
||||
const char* err;
|
||||
{
|
||||
int ret =
|
||||
LoadEXRImageBufFromFileHandle(&m_rgbaBuf, *m_exr_header, m_fp, &err);
|
||||
if (ret != 0) {
|
||||
m_exr_header = nullptr;
|
||||
throw(std::string(err));
|
||||
}
|
||||
}
|
||||
// header memory is freed after loading image
|
||||
m_exr_header = nullptr;
|
||||
}
|
||||
|
||||
void ExrReader::readLine(char* buffer, int x0, int x1, int shrink) {
|
||||
const int pixelSize = 4;
|
||||
if (m_row < 0 || m_row >= m_info.m_ly) {
|
||||
memset(buffer, 0, (x1 - x0 + 1) * pixelSize);
|
||||
m_row++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_rgbaBuf) loadImage();
|
||||
|
||||
TPixel32* pix = (TPixel32*)buffer;
|
||||
float* v = m_rgbaBuf + m_row * m_info.m_lx * 4;
|
||||
|
||||
pix += x0;
|
||||
v += x0 * 4;
|
||||
|
||||
int width =
|
||||
(x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
pix->r = ftouc(v[0]);
|
||||
pix->g = ftouc(v[1]);
|
||||
pix->b = ftouc(v[2]);
|
||||
pix->m = ftouc(v[3]);
|
||||
|
||||
v += shrink * 4;
|
||||
pix += shrink;
|
||||
}
|
||||
|
||||
m_row++;
|
||||
}
|
||||
|
||||
void ExrReader::readLine(short* buffer, int x0, int x1, int shrink) {
|
||||
const int pixelSize = 8;
|
||||
if (m_row < 0 || m_row >= m_info.m_ly) {
|
||||
memset(buffer, 0, (x1 - x0 + 1) * pixelSize);
|
||||
m_row++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_rgbaBuf) loadImage();
|
||||
|
||||
TPixel64* pix = (TPixel64*)buffer;
|
||||
float* v = m_rgbaBuf + m_row * m_info.m_lx * 4;
|
||||
|
||||
pix += x0;
|
||||
v += x0 * 4;
|
||||
|
||||
int width =
|
||||
(x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
pix->r = ftous(v[0]);
|
||||
pix->g = ftous(v[1]);
|
||||
pix->b = ftous(v[2]);
|
||||
pix->m = ftous(v[3], 1.0f);
|
||||
|
||||
v += shrink * 4;
|
||||
pix += shrink;
|
||||
}
|
||||
|
||||
m_row++;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
Tiio::ExrWriterProperties::ExrWriterProperties()
|
||||
: m_compressionType("Compression Type")
|
||||
, m_storageType("Storage Type")
|
||||
, m_bitsPerPixel("Bits Per Pixel") {
|
||||
m_bitsPerPixel.addValue(L"48(RGB)");
|
||||
m_bitsPerPixel.addValue(L"64(RGBA)");
|
||||
m_bitsPerPixel.setValue(L"64(RGBA)");
|
||||
|
||||
m_compressionType.addValue(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_NONE));
|
||||
m_compressionType.addValue(ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_RLE));
|
||||
m_compressionType.addValue(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIPS));
|
||||
m_compressionType.addValue(ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIP));
|
||||
m_compressionType.addValue(ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_PIZ));
|
||||
|
||||
m_compressionType.setValue(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_NONE));
|
||||
|
||||
m_storageType.addValue(EXR_STORAGETYPE_SCANLINE);
|
||||
m_storageType.addValue(EXR_STORAGETYPE_TILE);
|
||||
m_storageType.setValue(EXR_STORAGETYPE_SCANLINE);
|
||||
|
||||
bind(m_bitsPerPixel);
|
||||
bind(m_compressionType);
|
||||
bind(m_storageType);
|
||||
}
|
||||
|
||||
void Tiio::ExrWriterProperties::updateTranslation() {
|
||||
m_bitsPerPixel.setQStringName(tr("Bits Per Pixel"));
|
||||
m_bitsPerPixel.setItemUIName(L"48(RGB)", tr("48(RGB Half Float)"));
|
||||
m_bitsPerPixel.setItemUIName(L"64(RGBA)", tr("64(RGBA Half Float)"));
|
||||
|
||||
m_compressionType.setQStringName(tr("Compression Type"));
|
||||
m_compressionType.setItemUIName(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_NONE), tr("No compression"));
|
||||
m_compressionType.setItemUIName(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_RLE),
|
||||
tr("Run Length Encoding (RLE)"));
|
||||
m_compressionType.setItemUIName(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIPS),
|
||||
tr("ZIP compression per Scanline (ZIPS)"));
|
||||
m_compressionType.setItemUIName(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIP),
|
||||
tr("ZIP compression per scanline band (ZIP)"));
|
||||
m_compressionType.setItemUIName(
|
||||
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_PIZ),
|
||||
tr("PIZ-based wavelet compression (PIZ)"));
|
||||
|
||||
m_storageType.setQStringName(tr("Storage Type"));
|
||||
m_storageType.setItemUIName(EXR_STORAGETYPE_SCANLINE, tr("Scan-line based"));
|
||||
m_storageType.setItemUIName(EXR_STORAGETYPE_TILE, tr("Tile based"));
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
class ExrWriter final : public Tiio::Writer {
|
||||
std::vector<float> m_imageBuf[4];
|
||||
EXRHeader m_header;
|
||||
EXRImage m_image;
|
||||
int m_row;
|
||||
FILE* m_fp;
|
||||
int m_bpp;
|
||||
|
||||
public:
|
||||
ExrWriter();
|
||||
~ExrWriter();
|
||||
|
||||
void open(FILE* file, const TImageInfo& info) override;
|
||||
void writeLine(char* buffer) override;
|
||||
void writeLine(short* buffer) override;
|
||||
|
||||
void flush() override;
|
||||
|
||||
Tiio::RowOrder getRowOrder() const override { return Tiio::TOP2BOTTOM; }
|
||||
|
||||
// m_bpp is set to "Bits Per Pixel" property value in the function open()
|
||||
bool writeAlphaSupported() const override { return m_bpp == 64; }
|
||||
};
|
||||
|
||||
ExrWriter::ExrWriter() : m_row(0), m_bpp(64) {}
|
||||
|
||||
ExrWriter::~ExrWriter() {
|
||||
free(m_header.channels);
|
||||
free(m_header.pixel_types);
|
||||
free(m_header.requested_pixel_types);
|
||||
}
|
||||
|
||||
void ExrWriter::open(FILE* file, const TImageInfo& info) {
|
||||
m_fp = file;
|
||||
m_info = info;
|
||||
InitEXRHeader(&m_header);
|
||||
InitEXRImage(&m_image);
|
||||
|
||||
if (!m_properties) m_properties = new Tiio::ExrWriterProperties();
|
||||
|
||||
TEnumProperty* bitsPerPixel =
|
||||
(TEnumProperty*)(m_properties->getProperty("Bits Per Pixel"));
|
||||
m_bpp = bitsPerPixel ? std::stoi(bitsPerPixel->getValue()) : 64;
|
||||
assert(m_bpp == 48 || m_bpp == 64);
|
||||
|
||||
std::wstring compressionType =
|
||||
((TEnumProperty*)(m_properties->getProperty("Compression Type")))
|
||||
->getValue();
|
||||
m_header.compression_type = ExrCompTypeStr.key(compressionType);
|
||||
|
||||
std::wstring storageType =
|
||||
((TEnumProperty*)(m_properties->getProperty("Storage Type")))->getValue();
|
||||
if (storageType == EXR_STORAGETYPE_TILE) {
|
||||
m_header.tiled = 1;
|
||||
m_header.tile_size_x = 128;
|
||||
m_header.tile_size_y = 128;
|
||||
m_header.tile_level_mode = TINYEXR_TILE_ONE_LEVEL;
|
||||
} else
|
||||
m_header.tiled = 0;
|
||||
|
||||
m_image.num_channels = (m_bpp == 64) ? 4 : 3;
|
||||
|
||||
for (int c = 0; c < m_image.num_channels; c++)
|
||||
m_imageBuf[c].resize(m_info.m_lx * m_info.m_ly);
|
||||
|
||||
m_image.width = m_info.m_lx;
|
||||
m_image.height = m_info.m_ly;
|
||||
|
||||
m_header.num_channels = m_image.num_channels;
|
||||
m_header.channels =
|
||||
(EXRChannelInfo*)malloc(sizeof(EXRChannelInfo) * m_header.num_channels);
|
||||
// Must be BGR(A) order, since most of EXR viewers expect this channel order.
|
||||
if (m_bpp == 64) {
|
||||
strncpy(m_header.channels[0].name, "A", 255);
|
||||
m_header.channels[0].name[strlen("A")] = '\0';
|
||||
strncpy(m_header.channels[1].name, "B", 255);
|
||||
m_header.channels[1].name[strlen("B")] = '\0';
|
||||
strncpy(m_header.channels[2].name, "G", 255);
|
||||
m_header.channels[2].name[strlen("G")] = '\0';
|
||||
strncpy(m_header.channels[3].name, "R", 255);
|
||||
m_header.channels[3].name[strlen("R")] = '\0';
|
||||
} else {
|
||||
strncpy(m_header.channels[0].name, "B", 255);
|
||||
m_header.channels[0].name[strlen("B")] = '\0';
|
||||
strncpy(m_header.channels[1].name, "G", 255);
|
||||
m_header.channels[1].name[strlen("G")] = '\0';
|
||||
strncpy(m_header.channels[2].name, "R", 255);
|
||||
m_header.channels[2].name[strlen("R")] = '\0';
|
||||
}
|
||||
|
||||
m_header.pixel_types = (int*)malloc(sizeof(int) * m_header.num_channels);
|
||||
m_header.requested_pixel_types =
|
||||
(int*)malloc(sizeof(int) * m_header.num_channels);
|
||||
for (int i = 0; i < m_header.num_channels; i++) {
|
||||
m_header.pixel_types[i] =
|
||||
TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
|
||||
m_header.requested_pixel_types[i] =
|
||||
TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in
|
||||
// .EXR
|
||||
}
|
||||
}
|
||||
|
||||
void ExrWriter::writeLine(char* buffer) {
|
||||
TPixel32* pix = (TPixel32*)buffer;
|
||||
TPixel32* endPix = pix + m_info.m_lx;
|
||||
|
||||
float* r_p = &m_imageBuf[0][m_row * m_info.m_lx];
|
||||
float* g_p = &m_imageBuf[1][m_row * m_info.m_lx];
|
||||
float* b_p = &m_imageBuf[2][m_row * m_info.m_lx];
|
||||
float* a_p;
|
||||
if (m_bpp == 64) a_p = &m_imageBuf[3][m_row * m_info.m_lx];
|
||||
while (pix < endPix) {
|
||||
*r_p++ = uctof(pix->r);
|
||||
*g_p++ = uctof(pix->g);
|
||||
*b_p++ = uctof(pix->b);
|
||||
if (m_bpp == 64) *a_p++ = uctof(pix->m, 1.0f);
|
||||
pix++;
|
||||
}
|
||||
m_row++;
|
||||
}
|
||||
void ExrWriter::writeLine(short* buffer) {
|
||||
TPixel64* pix = (TPixel64*)buffer;
|
||||
TPixel64* endPix = pix + m_info.m_lx;
|
||||
|
||||
float* r_p = &m_imageBuf[0][m_row * m_info.m_lx];
|
||||
float* g_p = &m_imageBuf[1][m_row * m_info.m_lx];
|
||||
float* b_p = &m_imageBuf[2][m_row * m_info.m_lx];
|
||||
float* a_p;
|
||||
if (m_bpp == 64) a_p = &m_imageBuf[3][m_row * m_info.m_lx];
|
||||
while (pix < endPix) {
|
||||
*r_p++ = ustof(pix->r);
|
||||
*g_p++ = ustof(pix->g);
|
||||
*b_p++ = ustof(pix->b);
|
||||
if (m_bpp == 64) *a_p++ = ustof(pix->m, 1.0f);
|
||||
pix++;
|
||||
}
|
||||
m_row++;
|
||||
}
|
||||
|
||||
void ExrWriter::flush() {
|
||||
if (m_bpp == 64) {
|
||||
float* image_ptr[4];
|
||||
image_ptr[0] = &(m_imageBuf[3].at(0)); // B
|
||||
image_ptr[1] = &(m_imageBuf[2].at(0)); // G
|
||||
image_ptr[2] = &(m_imageBuf[1].at(0)); // R
|
||||
image_ptr[3] = &(m_imageBuf[0].at(0)); // A
|
||||
m_image.images = (unsigned char**)image_ptr;
|
||||
const char* err;
|
||||
int ret = SaveEXRImageToFileHandle(&m_image, &m_header, m_fp, &err);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
throw(std::string(err));
|
||||
}
|
||||
} else {
|
||||
float* image_ptr[3];
|
||||
image_ptr[0] = &(m_imageBuf[2].at(0)); // B
|
||||
image_ptr[1] = &(m_imageBuf[1].at(0)); // G
|
||||
image_ptr[2] = &(m_imageBuf[0].at(0)); // R
|
||||
m_image.images = (unsigned char**)image_ptr;
|
||||
const char* err;
|
||||
int ret = SaveEXRImageToFileHandle(&m_image, &m_header, m_fp, &err);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
throw(std::string(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
Tiio::Reader* Tiio::makeExrReader() { return new ExrReader(); }
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
Tiio::Writer* Tiio::makeExrWriter() { return new ExrWriter(); }
|
32
toonz/sources/image/exr/tiio_exr.h
Normal file
32
toonz/sources/image/exr/tiio_exr.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef TTIO_EXR_INCLUDED
|
||||
#define TTIO_EXR_INCLUDED
|
||||
|
||||
#include "tiio.h"
|
||||
#include "tproperty.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
namespace Tiio {
|
||||
|
||||
//===========================================================================
|
||||
|
||||
class ExrWriterProperties final : public TPropertyGroup {
|
||||
Q_DECLARE_TR_FUNCTIONS(ExrWriterProperties)
|
||||
public:
|
||||
TEnumProperty m_compressionType;
|
||||
TEnumProperty m_storageType;
|
||||
TEnumProperty m_bitsPerPixel;
|
||||
|
||||
ExrWriterProperties();
|
||||
|
||||
void updateTranslation() override;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
||||
Tiio::Reader* makeExrReader();
|
||||
Tiio::Writer* makeExrWriter();
|
||||
} // namespace Tiio
|
||||
|
||||
#endif
|
496
toonz/sources/image/exr/tinyexr_otmod.h
Normal file
496
toonz/sources/image/exr/tinyexr_otmod.h
Normal file
|
@ -0,0 +1,496 @@
|
|||
#ifndef TINYEXR_OTMOD_H_
|
||||
#define TINYEXR_OTMOD_H_
|
||||
|
||||
#define TINYEXR_IMPLEMENTATION
|
||||
#include "tinyexr.h"
|
||||
|
||||
/*
|
||||
* This source is based on TinyEXR code, enabling to use file handle
|
||||
* as an argument instead of file path in order to fit usage in OpenToonz.
|
||||
* TinyEXR code is licensed under the following:
|
||||
*/
|
||||
|
||||
// Start of TinyEXR license -------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Syoyo Fujita nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
// End of TinyEXR license -------------------------------------------------
|
||||
// TinyEXR contains some OpenEXR code, which is licensed under ------------
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
|
||||
// Digital Ltd. LLC
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Industrial Light & Magic nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// End of OpenEXR license -------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int ParseEXRVersionFromFileHandle(EXRVersion *version, FILE *fp);
|
||||
|
||||
extern int ParseEXRHeaderFromFileHandle(EXRHeader *exr_header,
|
||||
const EXRVersion *exr_version, FILE *fp,
|
||||
const char **err);
|
||||
|
||||
extern int LoadEXRImageFromFileHandle(EXRImage *exr_image,
|
||||
const EXRHeader *exr_header, FILE *fp,
|
||||
const char **err);
|
||||
|
||||
extern int LoadEXRHeaderFromFileHandle(EXRHeader &exr_header, FILE *file,
|
||||
const char **err);
|
||||
|
||||
extern int LoadEXRImageBufFromFileHandle(float **out_rgba,
|
||||
EXRHeader &exr_header, FILE *file,
|
||||
const char **err);
|
||||
|
||||
extern int SaveEXRImageToFileHandle(const EXRImage *exr_image,
|
||||
const EXRHeader *exr_header, FILE *fp,
|
||||
const char **err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TINYEXR_OTMOD_H_
|
||||
|
||||
#ifdef TINYEXR_OTMOD_IMPLEMENTATION
|
||||
#ifndef TINYEXR_OTMOD_IMPLEMENTATION_DEFINED
|
||||
#define TINYEXR_OTMOD_IMPLEMENTATION_DEFINED
|
||||
|
||||
int ParseEXRVersionFromFileHandle(EXRVersion *version, FILE *fp) {
|
||||
if (!fp) {
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
|
||||
size_t file_size;
|
||||
// Compute size
|
||||
fseek(fp, 0, SEEK_END);
|
||||
file_size = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if (file_size < tinyexr::kEXRVersionSize) {
|
||||
return TINYEXR_ERROR_INVALID_FILE;
|
||||
}
|
||||
|
||||
unsigned char buf[tinyexr::kEXRVersionSize];
|
||||
size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp);
|
||||
// fclose(fp);
|
||||
|
||||
if (ret != tinyexr::kEXRVersionSize) {
|
||||
return TINYEXR_ERROR_INVALID_FILE;
|
||||
}
|
||||
|
||||
return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize);
|
||||
}
|
||||
|
||||
int ParseEXRHeaderFromFileHandle(EXRHeader *exr_header,
|
||||
const EXRVersion *exr_version, FILE *fp,
|
||||
const char **err) {
|
||||
if (exr_header == NULL || exr_version == NULL) {
|
||||
tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
|
||||
err);
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read file ", err);
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
|
||||
size_t filesize;
|
||||
// Compute size
|
||||
fseek(fp, 0, SEEK_END);
|
||||
filesize = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
std::vector<unsigned char> buf(filesize); // @todo { use mmap }
|
||||
{
|
||||
size_t ret;
|
||||
ret = fread(&buf[0], 1, filesize, fp);
|
||||
assert(ret == filesize);
|
||||
// fclose(fp);
|
||||
|
||||
if (ret != filesize) {
|
||||
tinyexr::SetErrorMessage("fread() error", err);
|
||||
return TINYEXR_ERROR_INVALID_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize,
|
||||
err);
|
||||
}
|
||||
|
||||
int LoadEXRImageFromFileHandle(EXRImage *exr_image, const EXRHeader *exr_header,
|
||||
FILE *fp, const char **err) {
|
||||
if (exr_image == NULL) {
|
||||
tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot read file", err);
|
||||
return TINYEXR_ERROR_CANT_OPEN_FILE;
|
||||
}
|
||||
|
||||
size_t filesize;
|
||||
// Compute size
|
||||
fseek(fp, 0, SEEK_END);
|
||||
filesize = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if (filesize < 16) {
|
||||
tinyexr::SetErrorMessage("File size too short", err);
|
||||
return TINYEXR_ERROR_INVALID_FILE;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buf(filesize); // @todo { use mmap }
|
||||
{
|
||||
size_t ret;
|
||||
ret = fread(&buf[0], 1, filesize, fp);
|
||||
assert(ret == filesize);
|
||||
// fclose(fp);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize,
|
||||
err);
|
||||
}
|
||||
|
||||
int LoadEXRHeaderFromFileHandle(EXRHeader &exr_header, FILE *file,
|
||||
const char **err) {
|
||||
EXRVersion exr_version;
|
||||
InitEXRHeader(&exr_header);
|
||||
|
||||
{
|
||||
FILE *_fp = file;
|
||||
int ret = ParseEXRVersionFromFileHandle(&exr_version, _fp);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
std::stringstream ss;
|
||||
ss << "Failed to open EXR file or read version info from EXR file. code("
|
||||
<< ret << ")";
|
||||
tinyexr::SetErrorMessage(ss.str(), err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (exr_version.multipart || exr_version.non_image) {
|
||||
tinyexr::SetErrorMessage(
|
||||
"Loading multipart or DeepImage is not supported in LoadEXR() API",
|
||||
err);
|
||||
return TINYEXR_ERROR_INVALID_DATA; // @fixme.
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FILE *_fp = file;
|
||||
int ret = ParseEXRHeaderFromFileHandle(&exr_header, &exr_version, _fp, err);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
FreeEXRHeader(&exr_header);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return TINYEXR_SUCCESS;
|
||||
}
|
||||
|
||||
int LoadEXRImageBufFromFileHandle(float **out_rgba, EXRHeader &exr_header,
|
||||
FILE *file, const char **err) {
|
||||
if (out_rgba == NULL) {
|
||||
tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
EXRImage exr_image;
|
||||
InitEXRImage(&exr_image);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Probably limit loading to layers (channels) selected by layer index
|
||||
{
|
||||
FILE *_fp = file;
|
||||
int ret = LoadEXRImageFromFileHandle(&exr_image, &exr_header, _fp, err);
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
FreeEXRHeader(&exr_header);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// RGBA
|
||||
int idxR = -1;
|
||||
int idxG = -1;
|
||||
int idxB = -1;
|
||||
int idxA = -1;
|
||||
|
||||
std::vector<std::string> layer_names;
|
||||
tinyexr::GetLayers(exr_header, layer_names);
|
||||
|
||||
std::vector<tinyexr::LayerChannel> channels;
|
||||
tinyexr::ChannelsInLayer(exr_header, "", channels);
|
||||
|
||||
if (channels.size() < 1) {
|
||||
tinyexr::SetErrorMessage("Layer Not Found", err);
|
||||
FreeEXRHeader(&exr_header);
|
||||
FreeEXRImage(&exr_image);
|
||||
return TINYEXR_ERROR_LAYER_NOT_FOUND;
|
||||
}
|
||||
|
||||
size_t ch_count = channels.size() < 4 ? channels.size() : 4;
|
||||
for (size_t c = 0; c < ch_count; c++) {
|
||||
const tinyexr::LayerChannel &ch = channels[c];
|
||||
|
||||
if (ch.name == "R") {
|
||||
idxR = int(ch.index);
|
||||
} else if (ch.name == "G") {
|
||||
idxG = int(ch.index);
|
||||
} else if (ch.name == "B") {
|
||||
idxB = int(ch.index);
|
||||
} else if (ch.name == "A") {
|
||||
idxA = int(ch.index);
|
||||
}
|
||||
}
|
||||
|
||||
if (channels.size() == 1) {
|
||||
int chIdx = int(channels.front().index);
|
||||
// Grayscale channel only.
|
||||
|
||||
(*out_rgba) = reinterpret_cast<float *>(
|
||||
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
|
||||
static_cast<size_t>(exr_image.height)));
|
||||
|
||||
if (exr_header.tiled) {
|
||||
for (int it = 0; it < exr_image.num_tiles; it++) {
|
||||
for (int j = 0; j < exr_header.tile_size_y; j++) {
|
||||
for (int i = 0; i < exr_header.tile_size_x; i++) {
|
||||
const int ii = exr_image.tiles[it].offset_x *
|
||||
static_cast<int>(exr_header.tile_size_x) +
|
||||
i;
|
||||
const int jj = exr_image.tiles[it].offset_y *
|
||||
static_cast<int>(exr_header.tile_size_y) +
|
||||
j;
|
||||
const int idx = ii + jj * static_cast<int>(exr_image.width);
|
||||
|
||||
// out of region check.
|
||||
if (ii >= exr_image.width) {
|
||||
continue;
|
||||
}
|
||||
if (jj >= exr_image.height) {
|
||||
continue;
|
||||
}
|
||||
const int srcIdx = i + j * exr_header.tile_size_x;
|
||||
unsigned char **src = exr_image.tiles[it].images;
|
||||
(*out_rgba)[4 * idx + 0] =
|
||||
reinterpret_cast<float **>(src)[chIdx][srcIdx];
|
||||
(*out_rgba)[4 * idx + 1] =
|
||||
reinterpret_cast<float **>(src)[chIdx][srcIdx];
|
||||
(*out_rgba)[4 * idx + 2] =
|
||||
reinterpret_cast<float **>(src)[chIdx][srcIdx];
|
||||
(*out_rgba)[4 * idx + 3] =
|
||||
reinterpret_cast<float **>(src)[chIdx][srcIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
|
||||
const float val =
|
||||
reinterpret_cast<float **>(exr_image.images)[chIdx][i];
|
||||
(*out_rgba)[4 * i + 0] = val;
|
||||
(*out_rgba)[4 * i + 1] = val;
|
||||
(*out_rgba)[4 * i + 2] = val;
|
||||
(*out_rgba)[4 * i + 3] = val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Assume RGB(A)
|
||||
|
||||
if (idxR == -1) {
|
||||
tinyexr::SetErrorMessage("R channel not found", err);
|
||||
|
||||
FreeEXRHeader(&exr_header);
|
||||
FreeEXRImage(&exr_image);
|
||||
return TINYEXR_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
if (idxG == -1) {
|
||||
tinyexr::SetErrorMessage("G channel not found", err);
|
||||
FreeEXRHeader(&exr_header);
|
||||
FreeEXRImage(&exr_image);
|
||||
return TINYEXR_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
if (idxB == -1) {
|
||||
tinyexr::SetErrorMessage("B channel not found", err);
|
||||
FreeEXRHeader(&exr_header);
|
||||
FreeEXRImage(&exr_image);
|
||||
return TINYEXR_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
(*out_rgba) = reinterpret_cast<float *>(
|
||||
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
|
||||
static_cast<size_t>(exr_image.height)));
|
||||
if (exr_header.tiled) {
|
||||
for (int it = 0; it < exr_image.num_tiles; it++) {
|
||||
for (int j = 0; j < exr_header.tile_size_y; j++) {
|
||||
for (int i = 0; i < exr_header.tile_size_x; i++) {
|
||||
const int ii =
|
||||
exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
|
||||
const int jj =
|
||||
exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
|
||||
const int idx = ii + jj * exr_image.width;
|
||||
|
||||
// out of region check.
|
||||
if (ii >= exr_image.width) {
|
||||
continue;
|
||||
}
|
||||
if (jj >= exr_image.height) {
|
||||
continue;
|
||||
}
|
||||
const int srcIdx = i + j * exr_header.tile_size_x;
|
||||
unsigned char **src = exr_image.tiles[it].images;
|
||||
(*out_rgba)[4 * idx + 0] =
|
||||
reinterpret_cast<float **>(src)[idxR][srcIdx];
|
||||
(*out_rgba)[4 * idx + 1] =
|
||||
reinterpret_cast<float **>(src)[idxG][srcIdx];
|
||||
(*out_rgba)[4 * idx + 2] =
|
||||
reinterpret_cast<float **>(src)[idxB][srcIdx];
|
||||
if (idxA != -1) {
|
||||
(*out_rgba)[4 * idx + 3] =
|
||||
reinterpret_cast<float **>(src)[idxA][srcIdx];
|
||||
} else {
|
||||
(*out_rgba)[4 * idx + 3] = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
|
||||
(*out_rgba)[4 * i + 0] =
|
||||
reinterpret_cast<float **>(exr_image.images)[idxR][i];
|
||||
(*out_rgba)[4 * i + 1] =
|
||||
reinterpret_cast<float **>(exr_image.images)[idxG][i];
|
||||
(*out_rgba)[4 * i + 2] =
|
||||
reinterpret_cast<float **>(exr_image.images)[idxB][i];
|
||||
if (idxA != -1) {
|
||||
(*out_rgba)[4 * i + 3] =
|
||||
reinterpret_cast<float **>(exr_image.images)[idxA][i];
|
||||
} else {
|
||||
(*out_rgba)[4 * i + 3] = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeEXRHeader(&exr_header);
|
||||
FreeEXRImage(&exr_image);
|
||||
|
||||
return TINYEXR_SUCCESS;
|
||||
}
|
||||
|
||||
int SaveEXRImageToFileHandle(const EXRImage *exr_image,
|
||||
const EXRHeader *exr_header, FILE *fp,
|
||||
const char **err) {
|
||||
if (exr_image == NULL || exr_header->compression_type < 0) {
|
||||
tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
|
||||
return TINYEXR_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#if !TINYEXR_USE_PIZ
|
||||
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
|
||||
tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
|
||||
err);
|
||||
return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !TINYEXR_USE_ZFP
|
||||
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
|
||||
tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
|
||||
err);
|
||||
return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fp) {
|
||||
tinyexr::SetErrorMessage("Cannot write a file", err);
|
||||
return TINYEXR_ERROR_CANT_WRITE_FILE;
|
||||
}
|
||||
|
||||
unsigned char *mem = NULL;
|
||||
size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
|
||||
if (mem_size == 0) {
|
||||
return TINYEXR_ERROR_SERIALZATION_FAILED;
|
||||
}
|
||||
|
||||
size_t written_size = 0;
|
||||
if ((mem_size > 0) && mem) {
|
||||
written_size = fwrite(mem, 1, mem_size, fp);
|
||||
}
|
||||
free(mem);
|
||||
|
||||
// fclose(fp);
|
||||
|
||||
if (written_size != mem_size) {
|
||||
tinyexr::SetErrorMessage("Cannot write a file", err);
|
||||
return TINYEXR_ERROR_CANT_WRITE_FILE;
|
||||
}
|
||||
|
||||
return TINYEXR_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // TINYEXR_OTMOD_IMPLEMENTATION_DEFINED
|
||||
#endif // TINYEXR_OTMOD_IMPLEMENTATION
|
|
@ -60,6 +60,7 @@
|
|||
#include "./ffmpeg/tiio_mov.h"
|
||||
#include "./mesh/tiio_mesh.h"
|
||||
#include "./sprite/tiio_sprite.h"
|
||||
#include "./exr/tiio_exr.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
|
@ -152,6 +153,11 @@ void initImageIo(bool lightVersion) {
|
|||
Tiio::defineWriterProperties("spritesheet",
|
||||
new Tiio::SpriteWriterProperties());
|
||||
|
||||
Tiio::defineReaderMaker("exr", Tiio::makeExrReader);
|
||||
Tiio::defineWriterMaker("exr", Tiio::makeExrWriter, true);
|
||||
TFileType::declare("exr", TFileType::RASTER_IMAGE);
|
||||
Tiio::defineWriterProperties("exr", new Tiio::ExrWriterProperties());
|
||||
|
||||
// ffmpeg
|
||||
#if !defined(_WIN32) || defined(x64) || (defined(_WIN32) && defined(__GNUC__))
|
||||
if (Ffmpeg::checkFfmpeg()) {
|
||||
|
|
Loading…
Reference in a new issue