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(); }