|
shun-iwasawa |
7bad49 |
#define TINYEXR_USE_MINIZ 0
|
|
shun-iwasawa |
7bad49 |
#include "zlib.h"
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#define TINYEXR_OTMOD_IMPLEMENTATION
|
|
shun-iwasawa |
7bad49 |
#include "tinyexr_otmod.h"
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#include "tiio_exr.h"
|
|
shun-iwasawa |
7bad49 |
#include "tpixel.h"
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
#include <qmap></qmap>
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
namespace {
|
|
shun-iwasawa |
7bad49 |
inline unsigned char ftouc(float f, float gamma = 2.2f) {
|
|
shun-iwasawa |
7bad49 |
int i = static_cast<int>(255.0f * powf(f, 1.0f / gamma));</int>
|
|
shun-iwasawa |
7bad49 |
if (i > 255) i = 255;
|
|
shun-iwasawa |
7bad49 |
if (i < 0) i = 0;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return static_cast<unsigned char="">(i);</unsigned>
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
inline float uctof(unsigned char uc, float gamma = 2.2f) {
|
|
shun-iwasawa |
7bad49 |
return powf(static_cast<float>(uc) / 255.0f, gamma);</float>
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
inline unsigned short ftous(float f, float gamma = 2.2f) {
|
|
shun-iwasawa |
7bad49 |
int i = static_cast<int>(65535.0f * powf(f, 1.0f / gamma));</int>
|
|
shun-iwasawa |
7bad49 |
if (i > 65535) i = 65535;
|
|
shun-iwasawa |
7bad49 |
if (i < 0) i = 0;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
return static_cast<unsigned short="">(i);</unsigned>
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
inline float ustof(unsigned short us, float gamma = 2.2f) {
|
|
shun-iwasawa |
7bad49 |
return powf(static_cast<float>(us) / 65535.0f, gamma);</float>
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
const QMap<int, std::wstring=""> ExrCompTypeStr = {</int,>
|
|
shun-iwasawa |
7bad49 |
{TINYEXR_COMPRESSIONTYPE_NONE, L"None"},
|
|
shun-iwasawa |
7bad49 |
{TINYEXR_COMPRESSIONTYPE_RLE, L"RLE"},
|
|
shun-iwasawa |
7bad49 |
{TINYEXR_COMPRESSIONTYPE_ZIPS, L"ZIPS"},
|
|
shun-iwasawa |
7bad49 |
{TINYEXR_COMPRESSIONTYPE_ZIP, L"ZIP"},
|
|
shun-iwasawa |
7bad49 |
{TINYEXR_COMPRESSIONTYPE_PIZ, L"PIZ"}};
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
const std::wstring EXR_STORAGETYPE_SCANLINE = L"Store Image as Scanlines";
|
|
shun-iwasawa |
7bad49 |
const std::wstring EXR_STORAGETYPE_TILE = L"Store Image as Tiles";
|
|
shun-iwasawa |
7bad49 |
} // namespace
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
//**************************************************************************
|
|
shun-iwasawa |
7bad49 |
// ExrReader implementation
|
|
shun-iwasawa |
7bad49 |
//**************************************************************************
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
class ExrReader final : public Tiio::Reader {
|
|
shun-iwasawa |
7bad49 |
float* m_rgbaBuf;
|
|
shun-iwasawa |
7bad49 |
int m_row;
|
|
shun-iwasawa |
7bad49 |
EXRHeader* m_exr_header;
|
|
shun-iwasawa |
7bad49 |
FILE* m_fp;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
public:
|
|
shun-iwasawa |
7bad49 |
ExrReader();
|
|
shun-iwasawa |
7bad49 |
~ExrReader();
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void open(FILE* file) override;
|
|
shun-iwasawa |
7bad49 |
Tiio::RowOrder getRowOrder() const override;
|
|
shun-iwasawa |
7bad49 |
bool read16BitIsEnabled() const override;
|
|
shun-iwasawa |
7bad49 |
int skipLines(int lineCount) override;
|
|
shun-iwasawa |
7bad49 |
;
|
|
shun-iwasawa |
7bad49 |
void readLine(char* buffer, int x0, int x1, int shrink) override;
|
|
shun-iwasawa |
7bad49 |
void readLine(short* buffer, int x0, int x1, int shrink) override;
|
|
shun-iwasawa |
7bad49 |
void loadImage();
|
|
shun-iwasawa |
7bad49 |
};
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
ExrReader::ExrReader() : m_rgbaBuf(nullptr), m_row(0), m_exr_header(nullptr) {}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
ExrReader::~ExrReader() {
|
|
shun-iwasawa |
7bad49 |
if (m_rgbaBuf) free(m_rgbaBuf);
|
|
shun-iwasawa |
7bad49 |
if (m_exr_header) FreeEXRHeader(m_exr_header);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrReader::open(FILE* file) {
|
|
shun-iwasawa |
7bad49 |
m_fp = file;
|
|
shun-iwasawa |
7bad49 |
m_exr_header = new EXRHeader();
|
|
shun-iwasawa |
7bad49 |
const char* err;
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
int ret = LoadEXRHeaderFromFileHandle(*m_exr_header, file, &err);
|
|
shun-iwasawa |
7bad49 |
if (ret != 0) {
|
|
shun-iwasawa |
7bad49 |
m_exr_header = nullptr;
|
|
shun-iwasawa |
7bad49 |
throw(std::string(err));
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
m_info.m_lx =
|
|
shun-iwasawa |
7bad49 |
m_exr_header->data_window.max_x - m_exr_header->data_window.min_x + 1;
|
|
shun-iwasawa |
7bad49 |
m_info.m_ly =
|
|
shun-iwasawa |
7bad49 |
m_exr_header->data_window.max_y - m_exr_header->data_window.min_y + 1;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_info.m_samplePerPixel = m_exr_header->num_channels;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int bps = 16;
|
|
shun-iwasawa |
7bad49 |
switch (m_exr_header->pixel_types[0]) {
|
|
shun-iwasawa |
7bad49 |
case TINYEXR_PIXELTYPE_UINT:
|
|
shun-iwasawa |
7bad49 |
case TINYEXR_PIXELTYPE_FLOAT:
|
|
shun-iwasawa |
7bad49 |
bps = 32;
|
|
shun-iwasawa |
7bad49 |
break;
|
|
shun-iwasawa |
7bad49 |
case TINYEXR_PIXELTYPE_HALF:
|
|
shun-iwasawa |
7bad49 |
bps = 16;
|
|
shun-iwasawa |
7bad49 |
break;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
m_info.m_bitsPerSample = bps;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
Tiio::RowOrder ExrReader::getRowOrder() const { return Tiio::TOP2BOTTOM; }
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
bool ExrReader::read16BitIsEnabled() const { return true; }
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int ExrReader::skipLines(int lineCount) {
|
|
shun-iwasawa |
7bad49 |
m_row += lineCount;
|
|
shun-iwasawa |
7bad49 |
return lineCount;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrReader::loadImage() {
|
|
shun-iwasawa |
7bad49 |
assert(!m_rgbaBuf);
|
|
shun-iwasawa |
7bad49 |
const char* err;
|
|
shun-iwasawa |
7bad49 |
{
|
|
shun-iwasawa |
7bad49 |
int ret =
|
|
shun-iwasawa |
7bad49 |
LoadEXRImageBufFromFileHandle(&m_rgbaBuf, *m_exr_header, m_fp, &err);
|
|
shun-iwasawa |
7bad49 |
if (ret != 0) {
|
|
shun-iwasawa |
7bad49 |
m_exr_header = nullptr;
|
|
shun-iwasawa |
7bad49 |
throw(std::string(err));
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
// header memory is freed after loading image
|
|
shun-iwasawa |
7bad49 |
m_exr_header = nullptr;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrReader::readLine(char* buffer, int x0, int x1, int shrink) {
|
|
shun-iwasawa |
7bad49 |
const int pixelSize = 4;
|
|
shun-iwasawa |
7bad49 |
if (m_row < 0 || m_row >= m_info.m_ly) {
|
|
shun-iwasawa |
7bad49 |
memset(buffer, 0, (x1 - x0 + 1) * pixelSize);
|
|
shun-iwasawa |
7bad49 |
m_row++;
|
|
shun-iwasawa |
7bad49 |
return;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (!m_rgbaBuf) loadImage();
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
TPixel32* pix = (TPixel32*)buffer;
|
|
shun-iwasawa |
7bad49 |
float* v = m_rgbaBuf + m_row * m_info.m_lx * 4;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
pix += x0;
|
|
shun-iwasawa |
7bad49 |
v += x0 * 4;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int width =
|
|
shun-iwasawa |
7bad49 |
(x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < width; i++) {
|
|
shun-iwasawa |
7bad49 |
pix->r = ftouc(v[0]);
|
|
shun-iwasawa |
7bad49 |
pix->g = ftouc(v[1]);
|
|
shun-iwasawa |
7bad49 |
pix->b = ftouc(v[2]);
|
|
shun-iwasawa |
7bad49 |
pix->m = ftouc(v[3]);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
v += shrink * 4;
|
|
shun-iwasawa |
7bad49 |
pix += shrink;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_row++;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrReader::readLine(short* buffer, int x0, int x1, int shrink) {
|
|
shun-iwasawa |
7bad49 |
const int pixelSize = 8;
|
|
shun-iwasawa |
7bad49 |
if (m_row < 0 || m_row >= m_info.m_ly) {
|
|
shun-iwasawa |
7bad49 |
memset(buffer, 0, (x1 - x0 + 1) * pixelSize);
|
|
shun-iwasawa |
7bad49 |
m_row++;
|
|
shun-iwasawa |
7bad49 |
return;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (!m_rgbaBuf) loadImage();
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
TPixel64* pix = (TPixel64*)buffer;
|
|
shun-iwasawa |
7bad49 |
float* v = m_rgbaBuf + m_row * m_info.m_lx * 4;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
pix += x0;
|
|
shun-iwasawa |
7bad49 |
v += x0 * 4;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
int width =
|
|
shun-iwasawa |
7bad49 |
(x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < width; i++) {
|
|
shun-iwasawa |
7bad49 |
pix->r = ftous(v[0]);
|
|
shun-iwasawa |
7bad49 |
pix->g = ftous(v[1]);
|
|
shun-iwasawa |
7bad49 |
pix->b = ftous(v[2]);
|
|
shun-iwasawa |
7bad49 |
pix->m = ftous(v[3], 1.0f);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
v += shrink * 4;
|
|
shun-iwasawa |
7bad49 |
pix += shrink;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_row++;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
//============================================================
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
Tiio::ExrWriterProperties::ExrWriterProperties()
|
|
shun-iwasawa |
7bad49 |
: m_compressionType("Compression Type")
|
|
shun-iwasawa |
7bad49 |
, m_storageType("Storage Type")
|
|
shun-iwasawa |
7bad49 |
, m_bitsPerPixel("Bits Per Pixel") {
|
|
shun-iwasawa |
7bad49 |
m_bitsPerPixel.addValue(L"48(RGB)");
|
|
shun-iwasawa |
7bad49 |
m_bitsPerPixel.addValue(L"64(RGBA)");
|
|
shun-iwasawa |
7bad49 |
m_bitsPerPixel.setValue(L"64(RGBA)");
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_compressionType.addValue(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_NONE));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.addValue(ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_RLE));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.addValue(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIPS));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.addValue(ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIP));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.addValue(ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_PIZ));
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setValue(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_NONE));
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_storageType.addValue(EXR_STORAGETYPE_SCANLINE);
|
|
shun-iwasawa |
7bad49 |
m_storageType.addValue(EXR_STORAGETYPE_TILE);
|
|
shun-iwasawa |
7bad49 |
m_storageType.setValue(EXR_STORAGETYPE_SCANLINE);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
bind(m_bitsPerPixel);
|
|
shun-iwasawa |
7bad49 |
bind(m_compressionType);
|
|
shun-iwasawa |
7bad49 |
bind(m_storageType);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void Tiio::ExrWriterProperties::updateTranslation() {
|
|
shun-iwasawa |
7bad49 |
m_bitsPerPixel.setQStringName(tr("Bits Per Pixel"));
|
|
shun-iwasawa |
7bad49 |
m_bitsPerPixel.setItemUIName(L"48(RGB)", tr("48(RGB Half Float)"));
|
|
shun-iwasawa |
7bad49 |
m_bitsPerPixel.setItemUIName(L"64(RGBA)", tr("64(RGBA Half Float)"));
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setQStringName(tr("Compression Type"));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setItemUIName(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_NONE), tr("No compression"));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setItemUIName(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_RLE),
|
|
shun-iwasawa |
7bad49 |
tr("Run Length Encoding (RLE)"));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setItemUIName(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIPS),
|
|
shun-iwasawa |
7bad49 |
tr("ZIP compression per Scanline (ZIPS)"));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setItemUIName(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_ZIP),
|
|
shun-iwasawa |
7bad49 |
tr("ZIP compression per scanline band (ZIP)"));
|
|
shun-iwasawa |
7bad49 |
m_compressionType.setItemUIName(
|
|
shun-iwasawa |
7bad49 |
ExrCompTypeStr.value(TINYEXR_COMPRESSIONTYPE_PIZ),
|
|
shun-iwasawa |
7bad49 |
tr("PIZ-based wavelet compression (PIZ)"));
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_storageType.setQStringName(tr("Storage Type"));
|
|
shun-iwasawa |
7bad49 |
m_storageType.setItemUIName(EXR_STORAGETYPE_SCANLINE, tr("Scan-line based"));
|
|
shun-iwasawa |
7bad49 |
m_storageType.setItemUIName(EXR_STORAGETYPE_TILE, tr("Tile based"));
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
//============================================================
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
class ExrWriter final : public Tiio::Writer {
|
|
shun-iwasawa |
7bad49 |
std::vector<float> m_imageBuf[4];</float>
|
|
shun-iwasawa |
7bad49 |
EXRHeader m_header;
|
|
shun-iwasawa |
7bad49 |
EXRImage m_image;
|
|
shun-iwasawa |
7bad49 |
int m_row;
|
|
shun-iwasawa |
7bad49 |
FILE* m_fp;
|
|
shun-iwasawa |
7bad49 |
int m_bpp;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
public:
|
|
shun-iwasawa |
7bad49 |
ExrWriter();
|
|
shun-iwasawa |
7bad49 |
~ExrWriter();
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void open(FILE* file, const TImageInfo& info) override;
|
|
shun-iwasawa |
7bad49 |
void writeLine(char* buffer) override;
|
|
shun-iwasawa |
7bad49 |
void writeLine(short* buffer) override;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void flush() override;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
Tiio::RowOrder getRowOrder() const override { return Tiio::TOP2BOTTOM; }
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
// m_bpp is set to "Bits Per Pixel" property value in the function open()
|
|
shun-iwasawa |
7bad49 |
bool writeAlphaSupported() const override { return m_bpp == 64; }
|
|
shun-iwasawa |
7bad49 |
};
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
ExrWriter::ExrWriter() : m_row(0), m_bpp(64) {}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
ExrWriter::~ExrWriter() {
|
|
shun-iwasawa |
7bad49 |
free(m_header.channels);
|
|
shun-iwasawa |
7bad49 |
free(m_header.pixel_types);
|
|
shun-iwasawa |
7bad49 |
free(m_header.requested_pixel_types);
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrWriter::open(FILE* file, const TImageInfo& info) {
|
|
shun-iwasawa |
7bad49 |
m_fp = file;
|
|
shun-iwasawa |
7bad49 |
m_info = info;
|
|
shun-iwasawa |
7bad49 |
InitEXRHeader(&m_header);
|
|
shun-iwasawa |
7bad49 |
InitEXRImage(&m_image);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
if (!m_properties) m_properties = new Tiio::ExrWriterProperties();
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
TEnumProperty* bitsPerPixel =
|
|
shun-iwasawa |
7bad49 |
(TEnumProperty*)(m_properties->getProperty("Bits Per Pixel"));
|
|
shun-iwasawa |
7bad49 |
m_bpp = bitsPerPixel ? std::stoi(bitsPerPixel->getValue()) : 64;
|
|
shun-iwasawa |
7bad49 |
assert(m_bpp == 48 || m_bpp == 64);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
std::wstring compressionType =
|
|
shun-iwasawa |
7bad49 |
((TEnumProperty*)(m_properties->getProperty("Compression Type")))
|
|
shun-iwasawa |
7bad49 |
->getValue();
|
|
shun-iwasawa |
7bad49 |
m_header.compression_type = ExrCompTypeStr.key(compressionType);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
std::wstring storageType =
|
|
shun-iwasawa |
7bad49 |
((TEnumProperty*)(m_properties->getProperty("Storage Type")))->getValue();
|
|
shun-iwasawa |
7bad49 |
if (storageType == EXR_STORAGETYPE_TILE) {
|
|
shun-iwasawa |
7bad49 |
m_header.tiled = 1;
|
|
shun-iwasawa |
7bad49 |
m_header.tile_size_x = 128;
|
|
shun-iwasawa |
7bad49 |
m_header.tile_size_y = 128;
|
|
shun-iwasawa |
7bad49 |
m_header.tile_level_mode = TINYEXR_TILE_ONE_LEVEL;
|
|
shun-iwasawa |
7bad49 |
} else
|
|
shun-iwasawa |
7bad49 |
m_header.tiled = 0;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_image.num_channels = (m_bpp == 64) ? 4 : 3;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
for (int c = 0; c < m_image.num_channels; c++)
|
|
shun-iwasawa |
7bad49 |
m_imageBuf[c].resize(m_info.m_lx * m_info.m_ly);
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_image.width = m_info.m_lx;
|
|
shun-iwasawa |
7bad49 |
m_image.height = m_info.m_ly;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_header.num_channels = m_image.num_channels;
|
|
shun-iwasawa |
7bad49 |
m_header.channels =
|
|
shun-iwasawa |
7bad49 |
(EXRChannelInfo*)malloc(sizeof(EXRChannelInfo) * m_header.num_channels);
|
|
shun-iwasawa |
7bad49 |
// Must be BGR(A) order, since most of EXR viewers expect this channel order.
|
|
shun-iwasawa |
7bad49 |
if (m_bpp == 64) {
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[0].name, "A", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[0].name[strlen("A")] = '\0';
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[1].name, "B", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[1].name[strlen("B")] = '\0';
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[2].name, "G", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[2].name[strlen("G")] = '\0';
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[3].name, "R", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[3].name[strlen("R")] = '\0';
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[0].name, "B", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[0].name[strlen("B")] = '\0';
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[1].name, "G", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[1].name[strlen("G")] = '\0';
|
|
shun-iwasawa |
7bad49 |
strncpy(m_header.channels[2].name, "R", 255);
|
|
shun-iwasawa |
7bad49 |
m_header.channels[2].name[strlen("R")] = '\0';
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
m_header.pixel_types = (int*)malloc(sizeof(int) * m_header.num_channels);
|
|
shun-iwasawa |
7bad49 |
m_header.requested_pixel_types =
|
|
shun-iwasawa |
7bad49 |
(int*)malloc(sizeof(int) * m_header.num_channels);
|
|
shun-iwasawa |
7bad49 |
for (int i = 0; i < m_header.num_channels; i++) {
|
|
shun-iwasawa |
7bad49 |
m_header.pixel_types[i] =
|
|
shun-iwasawa |
7bad49 |
TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
|
|
shun-iwasawa |
7bad49 |
m_header.requested_pixel_types[i] =
|
|
shun-iwasawa |
7bad49 |
TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in
|
|
shun-iwasawa |
7bad49 |
// .EXR
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrWriter::writeLine(char* buffer) {
|
|
shun-iwasawa |
7bad49 |
TPixel32* pix = (TPixel32*)buffer;
|
|
shun-iwasawa |
7bad49 |
TPixel32* endPix = pix + m_info.m_lx;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
float* r_p = &m_imageBuf[0][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
float* g_p = &m_imageBuf[1][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
float* b_p = &m_imageBuf[2][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
float* a_p;
|
|
shun-iwasawa |
7bad49 |
if (m_bpp == 64) a_p = &m_imageBuf[3][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
while (pix < endPix) {
|
|
shun-iwasawa |
7bad49 |
*r_p++ = uctof(pix->r);
|
|
shun-iwasawa |
7bad49 |
*g_p++ = uctof(pix->g);
|
|
shun-iwasawa |
7bad49 |
*b_p++ = uctof(pix->b);
|
|
shun-iwasawa |
7bad49 |
if (m_bpp == 64) *a_p++ = uctof(pix->m, 1.0f);
|
|
shun-iwasawa |
7bad49 |
pix++;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
m_row++;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
void ExrWriter::writeLine(short* buffer) {
|
|
shun-iwasawa |
7bad49 |
TPixel64* pix = (TPixel64*)buffer;
|
|
shun-iwasawa |
7bad49 |
TPixel64* endPix = pix + m_info.m_lx;
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
float* r_p = &m_imageBuf[0][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
float* g_p = &m_imageBuf[1][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
float* b_p = &m_imageBuf[2][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
float* a_p;
|
|
shun-iwasawa |
7bad49 |
if (m_bpp == 64) a_p = &m_imageBuf[3][m_row * m_info.m_lx];
|
|
shun-iwasawa |
7bad49 |
while (pix < endPix) {
|
|
shun-iwasawa |
7bad49 |
*r_p++ = ustof(pix->r);
|
|
shun-iwasawa |
7bad49 |
*g_p++ = ustof(pix->g);
|
|
shun-iwasawa |
7bad49 |
*b_p++ = ustof(pix->b);
|
|
shun-iwasawa |
7bad49 |
if (m_bpp == 64) *a_p++ = ustof(pix->m, 1.0f);
|
|
shun-iwasawa |
7bad49 |
pix++;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
m_row++;
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
void ExrWriter::flush() {
|
|
shun-iwasawa |
7bad49 |
if (m_bpp == 64) {
|
|
shun-iwasawa |
7bad49 |
float* image_ptr[4];
|
|
shun-iwasawa |
7bad49 |
image_ptr[0] = &(m_imageBuf[3].at(0)); // B
|
|
shun-iwasawa |
7bad49 |
image_ptr[1] = &(m_imageBuf[2].at(0)); // G
|
|
shun-iwasawa |
7bad49 |
image_ptr[2] = &(m_imageBuf[1].at(0)); // R
|
|
shun-iwasawa |
7bad49 |
image_ptr[3] = &(m_imageBuf[0].at(0)); // A
|
|
shun-iwasawa |
7bad49 |
m_image.images = (unsigned char**)image_ptr;
|
|
shun-iwasawa |
7bad49 |
const char* err;
|
|
shun-iwasawa |
7bad49 |
int ret = SaveEXRImageToFileHandle(&m_image, &m_header, m_fp, &err);
|
|
shun-iwasawa |
7bad49 |
if (ret != TINYEXR_SUCCESS) {
|
|
shun-iwasawa |
7bad49 |
throw(std::string(err));
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
} else {
|
|
shun-iwasawa |
7bad49 |
float* image_ptr[3];
|
|
shun-iwasawa |
7bad49 |
image_ptr[0] = &(m_imageBuf[2].at(0)); // B
|
|
shun-iwasawa |
7bad49 |
image_ptr[1] = &(m_imageBuf[1].at(0)); // G
|
|
shun-iwasawa |
7bad49 |
image_ptr[2] = &(m_imageBuf[0].at(0)); // R
|
|
shun-iwasawa |
7bad49 |
m_image.images = (unsigned char**)image_ptr;
|
|
shun-iwasawa |
7bad49 |
const char* err;
|
|
shun-iwasawa |
7bad49 |
int ret = SaveEXRImageToFileHandle(&m_image, &m_header, m_fp, &err);
|
|
shun-iwasawa |
7bad49 |
if (ret != TINYEXR_SUCCESS) {
|
|
shun-iwasawa |
7bad49 |
throw(std::string(err));
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
}
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
//============================================================
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
Tiio::Reader* Tiio::makeExrReader() { return new ExrReader(); }
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
//------------------------------------------------------------
|
|
shun-iwasawa |
7bad49 |
|
|
shun-iwasawa |
7bad49 |
Tiio::Writer* Tiio::makeExrWriter() { return new ExrWriter(); }
|