25#include <OpenEXR/OpenEXRConfig.h>
26#define COMBINED_OPENEXR_VERSION \
27 ((10000 * OPENEXR_VERSION_MAJOR) + (100 * OPENEXR_VERSION_MINOR) + OPENEXR_VERSION_PATCH)
29#if COMBINED_OPENEXR_VERSION >= 20599
31# include <Imath/half.h>
32# include <OpenEXR/ImfFrameBuffer.h>
33# define exr_file_offset_t uint64_t
36# include <OpenEXR/half.h>
37# define exr_file_offset_t Int64
40#include <OpenEXR/Iex.h>
41#include <OpenEXR/ImfArray.h>
42#include <OpenEXR/ImfAttribute.h>
43#include <OpenEXR/ImfChannelList.h>
44#include <OpenEXR/ImfChromaticities.h>
45#include <OpenEXR/ImfCompression.h>
46#include <OpenEXR/ImfCompressionAttribute.h>
47#include <OpenEXR/ImfIO.h>
48#include <OpenEXR/ImfInputFile.h>
49#include <OpenEXR/ImfIntAttribute.h>
50#include <OpenEXR/ImfOutputFile.h>
51#include <OpenEXR/ImfPixelType.h>
52#include <OpenEXR/ImfPreviewImage.h>
53#include <OpenEXR/ImfRgbaFile.h>
54#include <OpenEXR/ImfStandardAttributes.h>
55#include <OpenEXR/ImfStringAttribute.h>
56#include <OpenEXR/ImfVersion.h>
59#include <OpenEXR/ImfInputPart.h>
60#include <OpenEXR/ImfMultiPartInputFile.h>
61#include <OpenEXR/ImfMultiPartOutputFile.h>
62#include <OpenEXR/ImfMultiView.h>
63#include <OpenEXR/ImfOutputPart.h>
64#include <OpenEXR/ImfPartHelper.h>
65#include <OpenEXR/ImfPartType.h>
66#include <OpenEXR/ImfTiledOutputPart.h>
102using namespace Imath;
118 {1.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f / 3.0f, 1.0f / 3.0f}};
121 {0.7347f, 0.2653f}, {0.0f, 1.0f}, {0.0001f, -0.077f}, {0.32168f, 0.33767f}};
127 IMemStream(
uchar *exrbuf,
size_t exrsize) : IStream(
"<memory>"), _exrpos(0), _exrsize(exrsize)
132 bool read(
char c[],
int n)
override
134 if (n + _exrpos <= _exrsize) {
135 memcpy(c, (
void *)(&_exrbuf[_exrpos]), n);
143 if (_exrpos < _exrsize && (n + _exrpos < _exrsize + 8192)) {
144 const size_t remainder = _exrsize - _exrpos;
146 memcpy(c, (
void *)(&_exrbuf[_exrpos]), remainder);
147 memset(c + remainder, 0, n - remainder);
182 throw IEX_NAMESPACE::InputExc(
"file not found");
189 if (_mmap_file ==
nullptr) {
190 throw IEX_NAMESPACE::InputExc(
"BLI_mmap_open failed");
206 bool read(
char c[],
int n)
override
208 if (_exrpos + n > _exrsize) {
209 throw Iex::InputExc(
"Unexpected end of file.");
211 memcpy(c, _exrbuf + _exrpos, n);
214 return _exrpos < _exrsize;
243 ifs.open(wfilepath, std::ios_base::binary);
246 ifs.open(filepath, std::ios_base::binary);
250 Iex::throwErrnoExc();
254 bool read(
char c[],
int n)
override
257 throw Iex::InputExc(
"Unexpected end of file.");
262 return check_error();
267 return std::streamoff(ifs.tellg());
286 Iex::throwErrnoExc();
304 void write(
const char c[],
int n)
override
306 ensure_size(offset + n);
307 memcpy(ibuf->encoded_buffer.data + offset, c, n);
309 ibuf->encoded_size += n;
329 throw Iex::ErrnoExc(
"Out of memory.");
347 ofs.open(wfilepath, std::ios_base::binary);
350 ofs.open(filepath, std::ios_base::binary);
354 Iex::throwErrnoExc();
358 void write(
const char c[],
int n)
override
367 return std::streamoff(ofs.tellp());
381 Iex::throwErrnoExc();
384 throw Iex::ErrnoExc(
"File output failed.");
412 return Imf::isImfMagic((
const char *)mem);
422 constexpr int x0 = 100, y0 = 0;
423 constexpr int x1 = 90, y1 = 45;
424 q = y0 + (q - x0) * (y1 - y0) / (x1 - x0);
430 switch (compression) {
432 header->compression() = NO_COMPRESSION;
435 header->compression() = PXR24_COMPRESSION;
438 header->compression() = ZIP_COMPRESSION;
441 header->compression() = PIZ_COMPRESSION;
444 header->compression() = RLE_COMPRESSION;
447 header->compression() = ZIPS_COMPRESSION;
450 header->compression() = B44_COMPRESSION;
453 header->compression() = B44A_COMPRESSION;
455#if OPENEXR_VERSION_MAJOR > 2 || (OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2)
457 header->compression() = DWAA_COMPRESSION;
461 header->compression() = DWAB_COMPRESSION;
466 header->compression() = ZIP_COMPRESSION;
473 switch (header.compression()) {
476 case RLE_COMPRESSION:
478 case ZIPS_COMPRESSION:
480 case ZIP_COMPRESSION:
482 case PIZ_COMPRESSION:
484 case PXR24_COMPRESSION:
486 case B44_COMPRESSION:
488 case B44A_COMPRESSION:
490 case DWAA_COMPRESSION:
492 case DWAB_COMPRESSION:
494 case NUM_COMPRESSION_METHODS:
505 header->insert(prop->name, StringAttribute(
IDP_String(prop)));
510 if (ibuf->
ppm[0] > 0.0 && ibuf->
ppm[1] > 0.0) {
512 addXDensity(*header, ibuf->
ppm[0] * 0.0254);
525 if (aces_colorspace &&
STREQ(aces_colorspace, ibuf_colorspace)) {
533 const char *propname,
538 header->insert(propname, StringAttribute(prop));
543 const int channels = ibuf->
channels;
544 const bool is_alpha = (channels >= 4) && (ibuf->
planes == 32);
545 const int width = ibuf->
x;
546 const int height = ibuf->
y;
547 OStream *file_stream =
nullptr;
550 Header header(width, height);
557 header.channels().insert(
"R", Channel(
HALF));
558 header.channels().insert(
"G", Channel(
HALF));
559 header.channels().insert(
"B", Channel(
HALF));
561 header.channels().insert(
"A", Channel(
HALF));
564 FrameBuffer frameBuffer;
573 OutputFile file(*file_stream, header);
576 std::unique_ptr<RGBAZ[]> pixels = std::unique_ptr<RGBAZ[]>(
new RGBAZ[
int64_t(height) * width]);
577 RGBAZ *to = pixels.get();
578 int xstride =
sizeof(
RGBAZ);
579 int ystride = xstride * width;
582 frameBuffer.insert(
"R", Slice(
HALF, (
char *)&to->
r, xstride, ystride));
583 frameBuffer.insert(
"G", Slice(
HALF, (
char *)&to->
g, xstride, ystride));
584 frameBuffer.insert(
"B", Slice(
HALF, (
char *)&to->
b, xstride, ystride));
586 frameBuffer.insert(
"A", Slice(
HALF, (
char *)&to->
a, xstride, ystride));
591 for (
int i = ibuf->
y - 1;
i >= 0;
i--) {
594 for (
int j = ibuf->
x; j > 0; j--) {
607 for (
int i = ibuf->
y - 1;
i >= 0;
i--) {
610 for (
int j = ibuf->
x; j > 0; j--) {
614 to->
a = channels >= 4 ? float(from[3]) / 255.0f : 1.0f;
621 exr_printf(
"OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
623 file.setFrameBuffer(frameBuffer);
624 file.writePixels(height);
626 catch (
const std::exception &exc) {
628 printf(
"OpenEXR-save: ERROR: %s\n", exc.what());
634 printf(
"OpenEXR-save: UNKNOWN ERROR\n");
645 const int channels = ibuf->
channels;
646 const bool is_alpha = (channels >= 4) && (ibuf->
planes == 32);
647 const int width = ibuf->
x;
648 const int height = ibuf->
y;
649 OStream *file_stream =
nullptr;
652 Header header(width, height);
659 header.channels().insert(
"R", Channel(Imf::FLOAT));
660 header.channels().insert(
"G", Channel(Imf::FLOAT));
661 header.channels().insert(
"B", Channel(Imf::FLOAT));
663 header.channels().insert(
"A", Channel(Imf::FLOAT));
666 FrameBuffer frameBuffer;
675 OutputFile file(*file_stream, header);
677 int xstride =
sizeof(float) * channels;
678 int ystride = -xstride * width;
681 float *rect[4] = {
nullptr,
nullptr,
nullptr,
nullptr};
683 rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
684 rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
685 rect[3] = (channels >= 4) ?
689 frameBuffer.insert(
"R", Slice(Imf::FLOAT, (
char *)rect[0], xstride, ystride));
690 frameBuffer.insert(
"G", Slice(Imf::FLOAT, (
char *)rect[1], xstride, ystride));
691 frameBuffer.insert(
"B", Slice(Imf::FLOAT, (
char *)rect[2], xstride, ystride));
693 frameBuffer.insert(
"A", Slice(Imf::FLOAT, (
char *)rect[3], xstride, ystride));
696 file.setFrameBuffer(frameBuffer);
697 file.writePixels(height);
699 catch (
const std::exception &exc) {
700 printf(
"OpenEXR-save: ERROR: %s\n", exc.what());
705 printf(
"OpenEXR-save: UNKNOWN ERROR\n");
777 MultiViewChannelName *
m;
812 data->multiView =
new StringVector();
822 if (
data ==
nullptr) {
834 data->multiView->emplace_back(name);
840 for (StringVector::const_iterator
i = views.begin();
count < views.size(); ++
i) {
856 StringVector sv = multiView(file.header(0));
857 for (
const std::string &view_name : sv) {
858 views.push_back(view_name);
864 for (
int p = 0; p < file.parts(); p++) {
866 if (file.header(p).hasView()) {
867 view = file.header(p).view();
871 views.push_back(
view);
879 const char *passname,
880 const char *viewname)
886 if (viewname ==
nullptr || viewname[0] ==
'\0') {
887 BLI_strncpy(name_full, passname, name_full_maxncpy);
891 const char delims[] = {
'.',
'\0'};
899 BLI_snprintf(name_full, name_full_maxncpy,
"%.*s.%s.%s",
int(
len), passname, viewname, token);
902 BLI_snprintf(name_full, name_full_maxncpy,
"%s.%s", passname, viewname);
908 const char *passname,
909 const char *viewname,
919 echan->
m =
new MultiViewChannelName();
921 if (layname && layname[0] !=
'\0') {
922 echan->
m->name = layname;
923 echan->
m->name.append(
".");
924 echan->
m->name.append(passname);
927 echan->
m->name.assign(passname);
930 echan->
m->internal_name = echan->
m->name;
932 echan->
m->view.assign(viewname ? viewname :
"");
938 if (layname && layname[0] !=
'\0') {
941 else if (!
data->multiView->empty()) {
942 std::string raw_name = insertViewName(echan->
m->name, *
data->multiView, echan->
view_id);
955 data->num_half_channels++;
963 const char *filepath,
972 Header header(width, height);
975 data->height = height;
977 bool is_singlelayer, is_multilayer, is_multiview;
980 header.channels().insert(echan->name, Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
989 header.channels(), *
data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
992 header.insert(
"BlenderMultiChannel", StringAttribute(
"Blender V2.55.1 and newer"));
996 addMultiView(header, *
data->multiView);
999 if (ppm[0] != 0.0 && ppm[1] != 0.0) {
1000 addXDensity(header, ppm[0] * 0.0254);
1008 data->ofile =
new OutputFile(*(
data->ofile_stream), header);
1010 catch (
const std::exception &exc) {
1011 std::cerr <<
"IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
1014 delete data->ofile_stream;
1016 data->ofile =
nullptr;
1017 data->ofile_stream =
nullptr;
1020 std::cerr <<
"IMB_exr_begin_write: UNKNOWN ERROR" << std::endl;
1023 delete data->ofile_stream;
1025 data->ofile =
nullptr;
1026 data->ofile_stream =
nullptr;
1029 return (
data->ofile !=
nullptr);
1033 void *handle,
const char *filepath,
int *width,
int *height,
const bool parse_channels)
1046 data->ifile =
new MultiPartInputFile(*(
data->ifile_stream));
1050 delete data->ifile_stream;
1052 data->ifile =
nullptr;
1053 data->ifile_stream =
nullptr;
1060 Box2i dw =
data->ifile->header(0).dataWindow();
1061 data->width = *width = dw.max.x - dw.min.x + 1;
1062 data->height = *height = dw.max.y - dw.min.y + 1;
1074 std::vector<MultiViewChannelName> channels;
1075 GetChannelsInMultiPartFile(*
data->ifile, channels);
1077 for (
const MultiViewChannelName &channel : channels) {
1079 data,
nullptr, channel.name.c_str(), channel.view.c_str(), 0, 0,
nullptr,
false);
1082 echan->
m->name = channel.name;
1083 echan->
m->view = channel.view;
1084 echan->
m->part_number = channel.part_number;
1085 echan->
m->internal_name = channel.internal_name;
1093 void *handle,
const char *layname,
const char *passname,
int xstride,
int ystride,
float *rect)
1098 if (layname && layname[0] !=
'\0') {
1103 SNPRINTF(name,
"%s.%s", lay, pass);
1112 if (echan ==
nullptr) {
1125 FrameBuffer frameBuffer;
1127 if (
data->channels.first) {
1128 const size_t num_pixels = size_t(
data->width) *
data->height;
1129 half *rect_half =
nullptr, *current_rect_half =
nullptr;
1132 if (
data->num_half_channels != 0) {
1134 current_rect_half = rect_half;
1139 if (echan->use_half_float) {
1140 const float *rect = echan->rect;
1141 half *cur = current_rect_half;
1142 for (
size_t i = 0;
i < num_pixels;
i++, cur++) {
1145 half *rect_to_write = current_rect_half + (
data->height - 1L) *
data->width;
1148 Slice(Imf::HALF, (
char *)rect_to_write,
sizeof(
half), -
data->width *
sizeof(
half)));
1149 current_rect_half += num_pixels;
1152 float *rect = echan->rect + echan->xstride * (
data->height - 1L) *
data->width;
1153 frameBuffer.insert(echan->name,
1156 echan->xstride *
sizeof(
float),
1157 -echan->ystride *
sizeof(
float)));
1161 data->ofile->setFrameBuffer(frameBuffer);
1163 data->ofile->writePixels(
data->height);
1165 catch (
const std::exception &exc) {
1166 std::cerr <<
"OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
1169 std::cerr <<
"OpenEXR-writePixels: UNKNOWN ERROR" << std::endl;
1172 if (rect_half !=
nullptr) {
1177 printf(
"Error: attempt to save MultiLayer without layers.\n");
1184 int numparts =
data->ifile->parts();
1187 const StringAttribute *ta =
data->ifile->header(0).findTypedAttribute<StringAttribute>(
1188 "BlenderMultiChannel");
1191 short flip = (ta &&
STRPREFIX(ta->value().c_str(),
"Blender V2.43"));
1194 "\nIMB_exr_read_channels\n%s %-6s %-22s "
1195 "\"%s\"\n---------------------------------------------------------------------\n",
1201 for (
int i = 0;
i < numparts;
i++) {
1203 InputPart
in(*
data->ifile,
i);
1205 Box2i dw = header.dataWindow();
1208 FrameBuffer frameBuffer;
1211 if (echan->m->part_number !=
i) {
1216 echan->m->part_number,
1217 echan->m->view.c_str(),
1218 echan->m->name.c_str(),
1219 echan->m->internal_name.c_str());
1222 float *rect = echan->rect;
1223 size_t xstride = echan->xstride *
sizeof(float);
1224 size_t ystride = echan->ystride *
sizeof(float);
1228 rect -= echan->xstride * (dw.min.x - dw.min.y *
data->width);
1230 rect += echan->xstride * (
data->height - 1) *
data->width;
1235 rect -= echan->xstride * (dw.min.x + dw.min.y *
data->width);
1238 frameBuffer.insert(echan->m->internal_name,
1239 Slice(Imf::FLOAT, (
char *)rect, xstride, ystride));
1245 in.setFrameBuffer(frameBuffer);
1246 exr_printf(
"readPixels:readPixels[%d]: min.y: %d, max.y: %d\n",
i, dw.min.y, dw.max.y);
1247 in.readPixels(dw.min.y, dw.max.y);
1249 catch (
const std::exception &exc) {
1250 std::cerr <<
"OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
1254 std::cerr <<
"OpenEXR-readPixels: UNKNOWN ERROR: " << std::endl;
1262 void *(*addview)(
void *base,
const char *
str),
1263 void *(*addlayer)(
void *base,
const char *
str),
1264 void (*addpass)(
void *base,
1269 const char *chan_id,
1275 if (
data->multiView->empty()) {
1280 for (
const std::string &view_name : *
data->multiView) {
1281 addview(base, view_name.c_str());
1286 printf(
"cannot convert multilayer, no layers in handle\n");
1291 void *laybase = addlayer(base, lay->name);
1296 pass->internal_name,
1301 pass->rect =
nullptr;
1312 delete data->ifile_stream;
1314 delete data->mpofile;
1315 delete data->ofile_stream;
1316 delete data->multiView;
1318 data->ifile =
nullptr;
1319 data->ifile_stream =
nullptr;
1320 data->ofile =
nullptr;
1321 data->mpofile =
nullptr;
1322 data->ofile_stream =
nullptr;
1348 const char delims[] = {
'.',
'\0'};
1357 return int(end - *token);
1362 const char *channelname,
1363 const bool has_xyz_channels)
1370 else if (echan->
chan_id ==
'Y' && !has_xyz_channels) {
1371 BLI_strncpy(passname, channelname, passname_maxncpy);
1373 else if (
ELEM(echan->
chan_id,
'R',
'G',
'B',
'A',
'V',
'X',
'Y',
'Z')) {
1374 BLI_strncpy(passname,
"Combined", passname_maxncpy);
1377 BLI_strncpy(passname, channelname, passname_maxncpy);
1383 const char *channelname,
1393 BLI_strncpy(passname, channelname, passname_maxncpy);
1399 bool has_xyz_channels)
1402 const char *name = echan->
m->name.c_str();
1403 const char *end = name + strlen(name);
1423 printf(
"multilayer read: bad channel name: %s\n", name);
1428 BLI_strncpy(channelname, token, std::min(
len + 1,
sizeof(channelname)));
1445 if (
ELEM(chan_id,
'X',
'Y',
'Z',
'R',
'G',
'B',
'U',
'V',
'A')) {
1477 printf(
"multilayer read: bad channel name: %s\n", name);
1490 BLI_strncpy(layname, name, std::min(layname_maxncpy,
int(end - name) + 1));
1503 if (lay ==
nullptr) {
1516 if (pass ==
nullptr) {
1519 if (
STREQ(passname,
"Combined")) {
1534 bool x_found =
false;
1535 bool y_found =
false;
1536 bool z_found =
false;
1538 if (
ELEM(channel->m->name,
"X",
"x")) {
1541 if (
ELEM(channel->m->name,
"Y",
"y")) {
1544 if (
ELEM(channel->m->name,
"Z",
"z")) {
1549 return x_found && y_found && z_found;
1555 const MultiPartInputFile &file)
1557 std::vector<MultiViewChannelName> channels;
1560 StringVector multiview;
1561 bool has_multiview =
false;
1562 if (file.parts() == 1) {
1563 if (hasMultiView(file.header(0))) {
1564 multiview = multiView(file.header(0));
1565 has_multiview =
true;
1570 for (
int p = 0; p < file.parts(); p++) {
1571 const ChannelList &c = file.header(p).channels();
1574 if (file.header(p).hasView()) {
1575 part_view = file.header(p).view();
1578 if (file.header(p).hasName()) {
1579 part_name = file.header(p).name();
1583 if (part_name.
endswith(
"." + part_view)) {
1586 else if (part_name.
endswith(
"-" + part_view)) {
1590 for (ChannelList::ConstIterator
i = c.begin();
i != c.end();
i++) {
1591 MultiViewChannelName m;
1592 m.name = std::string(
i.name());
1593 m.internal_name = m.name;
1595 if (has_multiview) {
1596 m.view = viewFromChannelName(m.name, multiview);
1597 m.name = removeViewName(m.internal_name, m.view);
1606 m.name = part_name +
"." + m.name;
1610 channels.push_back(m);
1623 for (
const MultiViewChannelName &channel : channels) {
1625 data,
nullptr, channel.name.c_str(), channel.view.c_str(), 0, 0,
nullptr,
false);
1628 echan->
m->name = channel.name;
1629 echan->
m->view = channel.view;
1630 echan->
m->part_number = channel.part_number;
1631 echan->
m->internal_name = channel.internal_name;
1639 for (; echan; echan = echan->
next) {
1642 const char *
view = echan->
m->view.c_str();
1645 STRNCPY(internal_name, passname);
1647 if (
view[0] !=
'\0') {
1668 printf(
"error, too many channels in one pass: %s\n", echan->
m->name.c_str());
1675 if (pass->totchan) {
1677 size_t(
data->width) *
size_t(
data->height) *
size_t(pass->totchan),
"pass rect");
1678 if (pass->totchan == 1) {
1680 echan->
rect = pass->rect;
1683 pass->chan_id[0] = echan->
chan_id;
1688 memset(lookup, 0,
sizeof(lookup));
1691 if (
ELEM(pass->totchan, 3, 4)) {
1692 if (pass->chan[0]->chan_id ==
'B' || pass->chan[1]->chan_id ==
'B' ||
1693 pass->chan[2]->chan_id ==
'B')
1695 lookup[
uint(
'R')] = 0;
1696 lookup[
uint(
'G')] = 1;
1697 lookup[
uint(
'B')] = 2;
1698 lookup[
uint(
'A')] = 3;
1700 else if (pass->chan[0]->chan_id ==
'Y' || pass->chan[1]->chan_id ==
'Y' ||
1701 pass->chan[2]->chan_id ==
'Y')
1703 lookup[
uint(
'X')] = 0;
1704 lookup[
uint(
'Y')] = 1;
1705 lookup[
uint(
'Z')] = 2;
1706 lookup[
uint(
'W')] = 3;
1709 lookup[
uint(
'U')] = 0;
1710 lookup[
uint(
'V')] = 1;
1711 lookup[
uint(
'A')] = 2;
1713 for (
int a = 0; a < pass->totchan; a++) {
1714 echan = pass->chan[a];
1716 echan->
xstride = pass->totchan;
1722 for (
int a = 0; a < pass->totchan; a++) {
1724 echan->
rect = pass->rect + a;
1725 echan->
xstride = pass->totchan;
1727 pass->chan_id[a] = echan->
chan_id;
1740 MultiPartInputFile &file,
1746 data->ifile_stream = &file_stream;
1747 data->ifile = &file;
1749 data->width = width;
1750 data->height = height;
1767 va_start(args, fmt);
1777 int numparts = file.parts();
1778 if (numparts == 1 && hasMultiView(file.header(0))) {
1779 const StringVector views = multiView(file.header(0));
1780 printf(
"OpenEXR-load: MultiView file\n");
1781 printf(
"OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
1782 for (
const std::string &
view : views) {
1783 printf(
"OpenEXR-load: Found view %s\n",
view.c_str());
1786 else if (numparts > 1) {
1787 printf(
"OpenEXR-load: MultiPart file\n");
1788 for (
int i = 0;
i < numparts;
i++) {
1789 if (file.header(
i).hasView()) {
1790 printf(
"OpenEXR-load: Part %d: view = \"%s\"\n",
i, file.header(
i).view().c_str());
1795 for (
int j = 0; j < numparts; j++) {
1796 const ChannelList &channels = file.header(j).channels();
1797 for (ChannelList::ConstIterator
i = channels.begin();
i != channels.end(); ++
i) {
1798 const Channel &channel =
i.channel();
1799 printf(
"OpenEXR-load: Found channel %s of type %d\n",
i.name(), channel.type);
1807 const ChannelList &channels = file.header(0).channels();
1809 for (ChannelList::ConstIterator
i = channels.begin();
i != channels.end(); ++
i) {
1811 const char *
str =
i.name();
1822static int exr_has_rgb(MultiPartInputFile &file,
const char *rgb_channels[3])
1826 static const char *channel_names[] = {
1827 "V",
"R",
"Red",
"G",
"Green",
"B",
"Blue",
"AR",
"RA",
"AG",
"GA",
"AB",
"BA",
nullptr};
1829 const Header &header = file.header(0);
1830 int num_channels = 0;
1832 for (
int i = 0; channel_names[
i];
i++) {
1834 std::string lower_case_name = std::string(channel_names[
i]);
1835 std::transform(lower_case_name.begin(),
1836 lower_case_name.end(),
1837 lower_case_name.begin(),
1838 [](
uchar c) { return std::tolower(c); });
1840 if (header.channels().findChannel(channel_names[
i]) ||
1841 header.channels().findChannel(lower_case_name))
1843 rgb_channels[num_channels++] = channel_names[
i];
1844 if (num_channels == 3) {
1850 return num_channels;
1858 const Header &header = file.header(0);
1859 return header.channels().findChannel(
"Y") !=
nullptr;
1864 const Header &header = file.header(0);
1865 return header.channels().findChannel(
"BY") !=
nullptr &&
1866 header.channels().findChannel(
"RY") !=
nullptr;
1871 const Header &header = file.header(0);
1872 return !(header.channels().findChannel(
"A") ==
nullptr);
1877 const Header &header = file.header(0);
1878 return (header.channels().findChannel(
"X") !=
nullptr ||
1879 header.channels().findChannel(
"x") !=
nullptr) &&
1880 (header.channels().findChannel(
"Y") !=
nullptr ||
1881 header.channels().findChannel(
"y") !=
nullptr) &&
1882 (header.channels().findChannel(
"Z") !=
nullptr ||
1883 header.channels().findChannel(
"z") !=
nullptr);
1888 const ChannelList &channels = file.header(0).channels();
1889 for (ChannelList::ConstIterator
i = channels.begin();
i != channels.end(); ++
i) {
1890 const Channel &channel =
i.channel();
1891 if (channel.type !=
HALF) {
1900 const ChannelList &channels = file.header(0).channels();
1901 std::set<std::string> layerNames;
1905 channels.layers(layerNames);
1907 return !layerNames.empty();
1911 StringVector &views,
1912 bool *r_singlelayer,
1916 std::set<std::string> layerNames;
1918 *r_singlelayer =
true;
1919 *r_multilayer = *r_multiview =
false;
1922 channels.layers(layerNames);
1924 if (!views.empty() && !views[0].empty()) {
1925 *r_multiview =
true;
1928 *r_singlelayer =
false;
1929 *r_multilayer = (layerNames.size() > 1);
1930 *r_multiview =
false;
1934 if (!layerNames.empty()) {
1942 for (ChannelList::ConstIterator
i = channels.begin();
i != channels.end();
i++) {
1943 for (
const std::string &layer_name : layerNames) {
1946 std::string layerName = layer_name;
1947 size_t pos = layerName.rfind(
'.');
1949 if (
pos == std::string::npos) {
1950 *r_multilayer =
true;
1951 *r_singlelayer =
false;
1959 *r_singlelayer =
true;
1960 *r_multilayer =
false;
1968 for (
int p = 0; p < file.parts(); p++) {
1969 if (hasMultiView(file.header(p))) {
1979 return file.parts() > 1;
2010 const float tolerance_v = 0.000001f;
2011 return (test_v < (ref_v + tolerance_v)) && (test_v > (ref_v - tolerance_v));
2016 const Imf::Chromaticities &
b)
2033 const IntAttribute *header_aces_container = header.findTypedAttribute<IntAttribute>(
2034 "acesImageContainerFlag");
2035 const ChromaticitiesAttribute *header_chromaticities =
2036 header.findTypedAttribute<ChromaticitiesAttribute>(
"chromaticities");
2038 if ((header_aces_container && header_aces_container->value() == 1) ||
2039 (header_chromaticities &&
2044 if (known_colorspace) {
2048 else if (header_chromaticities &&
2058 const Header &header = file.header(0);
2059 if (!hasXDensity(header)) {
2062 ppm[0] = double(xDensity(header)) / 0.0254;
2063 ppm[1] = ppm[0] * double(header.pixelAspectRatio());
2075 ImBuf *ibuf =
nullptr;
2077 MultiPartInputFile *file =
nullptr;
2087 file =
new MultiPartInputFile(*membuf);
2089 const Header &file_header = file->header(0);
2090 Box2i dw = file_header.dataWindow();
2091 const size_t width = dw.max.x - dw.min.x + 1;
2092 const size_t height = dw.max.y - dw.min.y + 1;
2105 printf(
"Error: can't process EXR multilayer file\n");
2123 Header::ConstIterator iter;
2126 for (iter = file_header.begin(); iter != file_header.end(); iter++) {
2127 const StringAttribute *attr = file_header.findTypedAttribute<StringAttribute>(
2148 const char *rgb_channels[3];
2149 const int num_rgb_channels =
exr_has_rgb(*file, rgb_channels);
2152 FrameBuffer frameBuffer;
2154 size_t xstride =
sizeof(
float[4]);
2155 size_t ystride = -xstride * width;
2164 first += 4 * (height - 1) * width;
2166 if (num_rgb_channels > 0) {
2167 for (
int i = 0;
i < num_rgb_channels;
i++) {
2169 Slice(Imf::FLOAT, (
char *)(first +
i), xstride, ystride));
2174 Slice(Imf::FLOAT, (
char *)first, xstride, ystride));
2176 Slice(Imf::FLOAT, (
char *)(first + 1), xstride, ystride));
2178 Slice(Imf::FLOAT, (
char *)(first + 2), xstride, ystride));
2180 else if (has_luma) {
2182 Slice(Imf::FLOAT, (
char *)first, xstride, ystride));
2185 Slice(Imf::FLOAT, (
char *)(first + 1), xstride, ystride, 1, 1, 0.5f));
2188 Slice(Imf::FLOAT, (
char *)(first + 2), xstride, ystride, 1, 1, 0.5f));
2193 Slice(Imf::FLOAT, (
char *)(first + 3), xstride, ystride, 1, 1, 1.0f));
2195 InputPart
in(*file, 0);
2196 in.setFrameBuffer(frameBuffer);
2197 in.readPixels(dw.min.y, dw.max.y);
2207 if (
flag & IM_rect) {
2212 if (num_rgb_channels == 0 && has_luma &&
exr_has_chroma(*file)) {
2213 for (
size_t a = 0; a < size_t(ibuf->
x) * ibuf->
y; a++) {
2224 else if (!has_xyz && num_rgb_channels <= 1) {
2226 for (
size_t a = 0; a < size_t(ibuf->
x) * ibuf->
y; a++) {
2228 color[1] = color[0];
2229 color[2] = color[0];
2249 catch (
const std::exception &exc) {
2250 std::cerr << exc.what() << std::endl;
2260 std::cerr <<
"OpenEXR-Load: UNKNOWN ERROR" << std::endl;
2273 const size_t max_thumb_size,
2278 ImBuf *ibuf =
nullptr;
2279 IStream *stream =
nullptr;
2280 Imf::RgbaInputFile *file =
nullptr;
2298 file =
new RgbaInputFile(*stream, 1);
2300 if (!file->isComplete()) {
2306 Imath::Box2i dw = file->dataWindow();
2307 int source_w = dw.max.x - dw.min.x + 1;
2308 int source_h = dw.max.y - dw.min.y + 1;
2309 *r_width = source_w;
2310 *r_height = source_h;
2312 const Header &file_header = file->header();
2315 if (file_header.hasPreviewImage()) {
2316 const Imf::PreviewImage &preview = file->header().previewImage();
2318 (uint8_t *)preview.pixels(),
nullptr, preview.width(), preview.height(), 4);
2329 float scale_factor = std::min(
float(max_thumb_size) /
float(source_w),
2330 float(max_thumb_size) /
float(source_h));
2331 int dest_w = std::max(
int(source_w * scale_factor), 1);
2332 int dest_h = std::max(
int(source_h * scale_factor), 1);
2337 Imf::Array<Imf::Rgba> pixels(source_w);
2340 for (
int h = 0; h < dest_h; h++) {
2343 int source_y = int(
float(h) / scale_factor) + dw.min.y;
2344 file->setFrameBuffer(&pixels[0] - dw.min.x - source_y * source_w, 1, source_w);
2345 file->readPixels(source_y);
2347 for (
int w = 0;
w < dest_w;
w++) {
2349 int source_x = int(std::min<int>((
w / scale_factor), dw.max.x - 1));
2351 dest_px[0] = pixels[source_x].r;
2352 dest_px[1] = pixels[source_x].g;
2353 dest_px[2] = pixels[source_x].b;
2354 dest_px[3] = pixels[source_x].a;
2358 if (file->lineOrder() == INCREASING_Y) {
2368 catch (
const std::exception &exc) {
2369 std::cerr << exc.what() << std::endl;
2379 std::cerr <<
"OpenEXR-Thumbnail: UNKNOWN ERROR" << std::endl;
2396 Imf::staticInitialize();
2403 Imf::setGlobalThreadCount(0);
void BKE_stamp_info_callback(void *data, StampData *stamp_data, StampCallback callback, bool noskip)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_kdtree_nd_ free(KDTree *tree)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void * BLI_rfindstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float clamp_f(float value, float min, float max)
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace)
float srgb_to_linearrgb(float c)
#define BLI_YCC_ITU_BT709
void * BLI_mmap_get_pointer(BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT
void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1)
BLI_mmap_file * BLI_mmap_open(int fd) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
size_t BLI_mmap_get_length(const BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT
#define SNPRINTF(dst, format,...)
char BLI_toupper_ascii(const char c) ATTR_WARN_UNUSED_RESULT
int bool bool bool size_t size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf) ATTR_NONNULL(1
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
int bool bool bool size_t size_t size_t BLI_str_partition_ex(const char *str, const char *end, const char delim[], const char **sep, const char **suf, bool from_right) ATTR_NONNULL(1
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
int BLI_system_thread_count(void)
const char * IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
@ COLOR_ROLE_ACES_INTERCHANGE
const char * IMB_colormanagement_role_colorspace_name_get(int role)
blender::ocio::ColorSpace ColorSpace
void IMB_flipy(ImBuf *ibuf)
ImBuf * IMB_allocFromBuffer(const uint8_t *byte_buffer, const float *float_buffer, unsigned int w, unsigned int h, unsigned int channels)
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
bool IMB_alloc_float_pixels(ImBuf *ibuf, const unsigned int channels, bool initialize_pixels=true)
#define OPENEXR_CODEC_MASK
Read Guarded memory(de)allocation.
bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf)
bool imb_addencodedbufferImBuf(ImBuf *ibuf)
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
void seekg(exr_file_offset_t pos) override
bool read(char c[], int n) override
exr_file_offset_t tellg() override
IFileStream(const char *filepath)
void seekg(exr_file_offset_t pos) override
IMMapStream(const char *filepath)
exr_file_offset_t tellg() override
bool read(char c[], int n) override
IMemStream(uchar *exrbuf, size_t exrsize)
void seekg(exr_file_offset_t pos) override
bool read(char c[], int n) override
exr_file_offset_t tellg() override
OFileStream(const char *filepath)
exr_file_offset_t tellp() override
void seekp(exr_file_offset_t pos) override
void write(const char c[], int n) override
void write(const char c[], int n) override
void seekp(exr_file_offset_t pos) override
exr_file_offset_t tellp() override
constexpr bool is_empty() const
constexpr bool startswith(StringRef prefix) const
constexpr bool endswith(StringRef suffix) const
constexpr StringRef drop_known_suffix(StringRef suffix) const
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
static bool parse_channels(const ImageSpec &in_spec, vector< MergeImageLayer > &layers, string &error)
T clamp(const T &a, const T &min, const T &max)
T safe_divide(const T &a, const T &b)
static Imf::Chromaticities CHROMATICITIES_ACES_2065_1
static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data)
static bool exr_has_multiview(MultiPartInputFile &file)
static std::vector< MultiViewChannelName > exr_channels_in_multi_part_file(const MultiPartInputFile &file)
static void exr_printf(const char *__restrict fmt,...)
void IMB_exr_add_view(void *handle, const char *name)
static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname, bool has_xyz_channels)
static bool exr_has_xyz(MultiPartInputFile &file)
static void openexr_header_metadata_callback(void *data, const char *propname, char *prop, int)
static int imb_exr_get_multiView_id(StringVector &views, const std::string &name)
bool IMB_exr_has_multilayer(void *handle)
static struct ExrPass * imb_exr_get_pass(ListBase *lb, const char *passname)
void * IMB_exr_get_handle_name(const char *name)
bool IMB_exr_begin_write(void *handle, const char *filepath, int width, int height, const double ppm[2], int compress, int quality, const StampData *stamp)
static bool imb_save_openexr_float(ImBuf *ibuf, const char *filepath, const int flags)
void IMB_exr_close(void *handle)
bool IMB_exr_get_ppm(void *handle, double ppm[2])
static ExrHandle * imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height)
static bool exr_is_half_float(MultiPartInputFile &file)
static void imb_exr_pass_name_from_channel(char *passname, const ExrChannel *echan, const char *channelname, const bool has_xyz_channels)
static bool imb_exr_is_multi(MultiPartInputFile &file)
static bool exr_has_luma(MultiPartInputFile &file)
ImBuf * imb_load_filepath_thumbnail_openexr(const char *filepath, const int, const size_t max_thumb_size, ImFileColorSpace &r_colorspace, size_t *r_width, size_t *r_height)
static int exr_has_rgb(MultiPartInputFile &file, const char *rgb_channels[3])
static bool exr_get_ppm(MultiPartInputFile &file, double ppm[2])
bool IMB_exr_begin_read(void *handle, const char *filepath, int *width, int *height, const bool parse_channels)
static bool imb_check_chromaticity_matches(const Imf::Chromaticities &a, const Imf::Chromaticities &b)
static int imb_exr_split_token(const char *str, const char *end, const char **token)
static void imb_exr_set_known_colorspace(const Header &header, ImFileColorSpace &r_colorspace)
static int openexr_jpg_like_quality_to_dwa_quality(int q)
#define exr_file_offset_t
void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *viewname, int xstride, int ystride, float *rect, bool use_half_float)
void IMB_exr_write_channels(void *handle)
static bool exr_has_chroma(MultiPartInputFile &file)
static bool imb_exr_is_multilayer_file(MultiPartInputFile &file)
bool imb_save_openexr(ImBuf *ibuf, const char *filepath, int flags)
bool imb_is_a_openexr(const uchar *mem, const size_t size)
static void imb_exr_insert_view_name(char name_full[EXR_TOT_MAXNAME+1], const char *passname, const char *viewname)
static ExrLayer * imb_exr_get_layer(ListBase *lb, const char *layname)
void IMB_exr_read_channels(void *handle)
static half float_to_half_safe(const float value)
ImBuf * imb_load_openexr(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
static void openexr_header_compression(Header *header, int compression, int quality)
static bool imb_check_chromaticity_val(float test_v, float ref_v)
static ListBase exrhandles
static bool exr_has_multipart_file(MultiPartInputFile &file)
static void exr_print_filecontents(MultiPartInputFile &file)
static void imb_exr_type_by_channels(ChannelList &channels, StringVector &views, bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
static bool exr_has_xyz_channels(ExrHandle *exr_handle)
static int openexr_header_get_compression(const Header &header)
bool IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
static Imf::Chromaticities CHROMATICITIES_XYZ_E
static void imb_exr_get_views(MultiPartInputFile &file, StringVector &views)
static bool imb_save_openexr_half(ImBuf *ibuf, const char *filepath, const int flags)
void IMB_exr_multilayer_convert(void *handle, void *base, void *(*addview)(void *base, const char *str), void *(*addlayer)(void *base, const char *str), void(*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view))
static void openexr_header_metadata(Header *header, ImBuf *ibuf)
static const char * exr_rgba_channelname(MultiPartInputFile &file, const char *chan)
void * IMB_exr_get_handle()
static bool exr_has_alpha(MultiPartInputFile &file)
static void imb_exr_pass_name_from_channel_name(char *passname, const ExrChannel *, const char *channelname, const bool)
char name[EXR_TOT_MAXNAME+1]
OFileStream * ofile_stream
MultiPartInputFile * ifile
MultiPartOutputFile * mpofile
char name[EXR_LAY_MAXNAME+1]
char chan_id[EXR_PASS_MAXCHAN]
char view[EXR_VIEW_MAXNAME]
char name[EXR_PASS_MAXNAME]
char internal_name[EXR_PASS_MAXNAME]
ExrChannel * chan[EXR_PASS_MAXCHAN]
const ColorSpace * colorspace
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned int encoded_buffer_size
unsigned int encoded_size
char metadata_colorspace[IM_MAX_SPACE]
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)