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/ImfChannelList.h>
43#include <OpenEXR/ImfCompression.h>
44#include <OpenEXR/ImfCompressionAttribute.h>
45#include <OpenEXR/ImfIO.h>
46#include <OpenEXR/ImfInputFile.h>
47#include <OpenEXR/ImfOutputFile.h>
48#include <OpenEXR/ImfPixelType.h>
49#include <OpenEXR/ImfPreviewImage.h>
50#include <OpenEXR/ImfRgbaFile.h>
51#include <OpenEXR/ImfStandardAttributes.h>
52#include <OpenEXR/ImfStringAttribute.h>
53#include <OpenEXR/ImfVersion.h>
56#include <OpenEXR/ImfInputPart.h>
57#include <OpenEXR/ImfMultiPartInputFile.h>
58#include <OpenEXR/ImfMultiPartOutputFile.h>
59#include <OpenEXR/ImfMultiView.h>
60#include <OpenEXR/ImfOutputPart.h>
61#include <OpenEXR/ImfPartHelper.h>
62#include <OpenEXR/ImfPartType.h>
63#include <OpenEXR/ImfTiledOutputPart.h>
113 IMemStream(
uchar *exrbuf,
size_t exrsize) : IStream(
"<memory>"), _exrpos(0), _exrsize(exrsize)
118 bool read(
char c[],
int n)
override
120 if (n + _exrpos <= _exrsize) {
121 memcpy(c, (
void *)(&_exrbuf[_exrpos]), n);
155 throw IEX_NAMESPACE::InputExc(
"file not found");
162 if (_mmap_file ==
nullptr) {
163 throw IEX_NAMESPACE::InputExc(
"BLI_mmap_open failed");
179 bool read(
char c[],
int n)
override
181 if (_exrpos + n > _exrsize) {
182 throw Iex::InputExc(
"Unexpected end of file.");
184 memcpy(c, _exrbuf + _exrpos, n);
187 return _exrpos < _exrsize;
216 ifs.open(wfilepath, std::ios_base::binary);
219 ifs.open(filepath, std::ios_base::binary);
223 Iex::throwErrnoExc();
227 bool read(
char c[],
int n)
override
230 throw Iex::InputExc(
"Unexpected end of file.");
235 return check_error();
240 return std::streamoff(ifs.tellg());
259 Iex::throwErrnoExc();
277 void write(
const char c[],
int n)
override
279 ensure_size(offset + n);
302 throw Iex::ErrnoExc(
"Out of memory.");
320 ofs.open(wfilepath, std::ios_base::binary);
323 ofs.open(filepath, std::ios_base::binary);
327 Iex::throwErrnoExc();
331 void write(
const char c[],
int n)
override
340 return std::streamoff(ofs.tellp());
354 Iex::throwErrnoExc();
357 throw Iex::ErrnoExc(
"File output failed.");
385 return Imf::isImfMagic((
const char *)mem);
390 switch (compression) {
392 header->compression() = NO_COMPRESSION;
395 header->compression() = PXR24_COMPRESSION;
398 header->compression() = ZIP_COMPRESSION;
401 header->compression() = PIZ_COMPRESSION;
404 header->compression() = RLE_COMPRESSION;
407 header->compression() = ZIPS_COMPRESSION;
410 header->compression() = B44_COMPRESSION;
413 header->compression() = B44A_COMPRESSION;
415#if OPENEXR_VERSION_MAJOR > 2 || (OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2)
417 header->compression() = DWAA_COMPRESSION;
420 header->compression() = DWAB_COMPRESSION;
424 header->compression() = ZIP_COMPRESSION;
434 header->insert(prop->name, StringAttribute(
IDP_String(prop)));
439 if (ibuf->
ppm[0] > 0.0) {
441 addXDensity(*header, ibuf->
ppm[0] * 0.0254);
446 const char *propname,
451 header->insert(propname, StringAttribute(prop));
456 const int channels = ibuf->
channels;
457 const bool is_alpha = (channels >= 4) && (ibuf->
planes == 32);
458 const int width = ibuf->
x;
459 const int height = ibuf->
y;
460 OStream *file_stream =
nullptr;
463 Header header(width, height);
469 header.channels().insert(
"R", Channel(
HALF));
470 header.channels().insert(
"G", Channel(
HALF));
471 header.channels().insert(
"B", Channel(
HALF));
473 header.channels().insert(
"A", Channel(
HALF));
476 FrameBuffer frameBuffer;
485 OutputFile
file(*file_stream, header);
488 std::vector<RGBAZ> pixels(height * width);
489 RGBAZ *to = pixels.data();
490 int xstride =
sizeof(
RGBAZ);
491 int ystride = xstride * width;
494 frameBuffer.insert(
"R", Slice(
HALF, (
char *)&to->r, xstride, ystride));
495 frameBuffer.insert(
"G", Slice(
HALF, (
char *)&to->g, xstride, ystride));
496 frameBuffer.insert(
"B", Slice(
HALF, (
char *)&to->b, xstride, ystride));
498 frameBuffer.insert(
"A", Slice(
HALF, (
char *)&to->a, xstride, ystride));
503 for (
int i = ibuf->
y - 1; i >= 0; i--) {
506 for (
int j = ibuf->
x; j > 0; j--) {
519 for (
int i = ibuf->
y - 1; i >= 0; i--) {
522 for (
int j = ibuf->
x; j > 0; j--) {
526 to->a = channels >= 4 ?
float(from[3]) / 255.0f : 1.0f;
533 exr_printf(
"OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
535 file.setFrameBuffer(frameBuffer);
536 file.writePixels(height);
538 catch (
const std::exception &exc) {
540 printf(
"OpenEXR-save: ERROR: %s\n", exc.what());
546 printf(
"OpenEXR-save: UNKNOWN ERROR\n");
557 const int channels = ibuf->
channels;
558 const bool is_alpha = (channels >= 4) && (ibuf->
planes == 32);
559 const int width = ibuf->
x;
560 const int height = ibuf->
y;
561 OStream *file_stream =
nullptr;
564 Header header(width, height);
570 header.channels().insert(
"R", Channel(Imf::FLOAT));
571 header.channels().insert(
"G", Channel(Imf::FLOAT));
572 header.channels().insert(
"B", Channel(Imf::FLOAT));
574 header.channels().insert(
"A", Channel(Imf::FLOAT));
577 FrameBuffer frameBuffer;
586 OutputFile
file(*file_stream, header);
588 int xstride =
sizeof(
float) * channels;
589 int ystride = -xstride * width;
592 float *rect[4] = {
nullptr,
nullptr,
nullptr,
nullptr};
594 rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
595 rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
596 rect[3] = (channels >= 4) ?
600 frameBuffer.insert(
"R", Slice(Imf::FLOAT, (
char *)rect[0], xstride, ystride));
601 frameBuffer.insert(
"G", Slice(Imf::FLOAT, (
char *)rect[1], xstride, ystride));
602 frameBuffer.insert(
"B", Slice(Imf::FLOAT, (
char *)rect[2], xstride, ystride));
604 frameBuffer.insert(
"A", Slice(Imf::FLOAT, (
char *)rect[3], xstride, ystride));
607 file.setFrameBuffer(frameBuffer);
608 file.writePixels(height);
610 catch (
const std::exception &exc) {
611 printf(
"OpenEXR-save: ERROR: %s\n", exc.what());
616 printf(
"OpenEXR-save: UNKNOWN ERROR\n");
688 MultiViewChannelName *
m;
722 ExrHandle *data = MEM_cnew<ExrHandle>(
"exr handle");
723 data->multiView =
new StringVector();
733 if (data ==
nullptr) {
751 for (StringVector::const_iterator i = views.begin();
count < views.size(); ++i) {
767 StringVector sv = multiView(file.header(0));
768 for (
const std::string &view_name : sv) {
769 views.push_back(view_name);
775 for (
int p = 0; p < file.parts(); p++) {
777 if (file.header(p).hasView()) {
778 view = file.header(p).view();
782 views.push_back(view);
790 const char *passname,
791 const char *viewname)
797 if (viewname ==
nullptr || viewname[0] ==
'\0') {
798 BLI_strncpy(name_full, passname, name_full_maxncpy);
802 const char delims[] = {
'.',
'\0'};
810 BLI_snprintf(name_full, name_full_maxncpy,
"%.*s.%s.%s",
int(
len), passname, viewname, token);
813 BLI_snprintf(name_full, name_full_maxncpy,
"%s.%s", passname, viewname);
819 const char *passname,
820 const char *viewname,
829 echan = MEM_cnew<ExrChannel>(
"exr channel");
830 echan->
m =
new MultiViewChannelName();
832 if (layname && layname[0] !=
'\0') {
833 echan->
m->name = layname;
834 echan->
m->name.append(
".");
835 echan->
m->name.append(passname);
838 echan->
m->name.assign(passname);
841 echan->
m->internal_name = echan->
m->name;
843 echan->
m->view.assign(viewname ? viewname :
"");
849 if (layname && layname[0] !=
'\0') {
852 else if (!data->multiView->empty()) {
853 std::string raw_name = insertViewName(echan->
m->name, *data->multiView, echan->
view_id);
866 data->num_half_channels++;
874 const char *filepath,
881 Header header(width, height);
884 data->height = height;
886 bool is_singlelayer, is_multilayer, is_multiview;
889 header.channels().insert(echan->name, Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
898 header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
901 header.insert(
"BlenderMultiChannel", StringAttribute(
"Blender V2.55.1 and newer"));
905 addMultiView(header, *data->multiView);
912 data->ofile =
new OutputFile(*(data->ofile_stream), header);
914 catch (
const std::exception &exc) {
915 std::cerr <<
"IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
918 delete data->ofile_stream;
920 data->ofile =
nullptr;
921 data->ofile_stream =
nullptr;
924 std::cerr <<
"IMB_exr_begin_write: UNKNOWN ERROR" << std::endl;
927 delete data->ofile_stream;
929 data->ofile =
nullptr;
930 data->ofile_stream =
nullptr;
933 return (data->ofile !=
nullptr);
937 void *handle,
const char *filepath,
int mipmap,
int width,
int height,
int tilex,
int tiley)
940 Header header(width, height);
941 std::vector<Header> headers;
946 data->height = height;
947 data->mipmap = mipmap;
949 header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
950 header.compression() = RLE_COMPRESSION;
951 header.setType(TILEDIMAGE);
953 header.insert(
"BlenderMultiChannel", StringAttribute(
"Blender V2.43"));
955 int numparts = data->multiView->size();
959 for (
int i = 0; i < numparts; i++) {
960 headers.push_back(header);
961 headers[headers.size() - 1].setView((*(data->multiView))[i]);
962 headers[headers.size() - 1].setName((*(data->multiView))[i]);
966 exr_printf(
"%s %-6s %-22s \"%s\"\n",
"p",
"view",
"name",
"internal_name");
967 exr_printf(
"---------------------------------------------------------------\n");
974 echan->m->internal_name = echan->m->name;
975 echan->m->part_number = echan->view_id;
977 headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
979 echan->m->part_number,
980 echan->m->view.c_str(),
981 echan->m->name.c_str(),
982 echan->m->internal_name.c_str());
989 data->mpofile =
new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
992 delete data->mpofile;
993 delete data->ofile_stream;
995 data->mpofile =
nullptr;
996 data->ofile_stream =
nullptr;
1001 void *handle,
const char *filepath,
int *width,
int *height,
const bool parse_channels)
1014 data->ifile =
new MultiPartInputFile(*(data->ifile_stream));
1018 delete data->ifile_stream;
1020 data->ifile =
nullptr;
1021 data->ifile_stream =
nullptr;
1028 Box2i dw = data->ifile->header(0).dataWindow();
1029 data->width = *width = dw.max.x - dw.min.x + 1;
1030 data->height = *height = dw.max.y - dw.min.y + 1;
1042 std::vector<MultiViewChannelName>
channels;
1043 GetChannelsInMultiPartFile(*data->ifile, channels);
1045 for (
const MultiViewChannelName &channel :
channels) {
1047 data,
nullptr, channel.name.c_str(), channel.view.c_str(), 0, 0,
nullptr,
false);
1050 echan->
m->name = channel.name;
1051 echan->
m->view = channel.view;
1052 echan->
m->part_number = channel.part_number;
1053 echan->
m->internal_name = channel.internal_name;
1061 void *handle,
const char *layname,
const char *passname,
int xstride,
int ystride,
float *rect)
1066 if (layname && layname[0] !=
'\0') {
1071 SNPRINTF(name,
"%s.%s", lay, pass);
1080 if (echan ==
nullptr) {
1091 const char *layname,
1092 const char *passname,
1093 const char *viewname)
1104 SNPRINTF(name,
"%s.%s", lay, pass);
1111 if (layname && layname[0] !=
'\0') {
1116 else if (!data->multiView->empty()) {
1118 std::string raw_name = insertViewName(name, *data->multiView, view_id);
1119 STRNCPY(name, raw_name.c_str());
1145 FrameBuffer frameBuffer;
1147 if (data->channels.first) {
1148 const size_t num_pixels = size_t(data->width) * data->
height;
1149 half *rect_half =
nullptr, *current_rect_half =
nullptr;
1152 if (data->num_half_channels != 0) {
1155 current_rect_half = rect_half;
1160 if (echan->use_half_float) {
1161 const float *rect = echan->rect;
1162 half *cur = current_rect_half;
1163 for (
size_t i = 0; i < num_pixels; i++, cur++) {
1166 half *rect_to_write = current_rect_half + (data->height - 1L) * data->width;
1169 Slice(Imf::HALF, (
char *)rect_to_write,
sizeof(
half), -data->width *
sizeof(
half)));
1170 current_rect_half += num_pixels;
1173 float *rect = echan->rect + echan->xstride * (data->height - 1L) * data->width;
1174 frameBuffer.insert(echan->name,
1177 echan->xstride *
sizeof(
float),
1178 -echan->ystride *
sizeof(
float)));
1182 data->ofile->setFrameBuffer(frameBuffer);
1184 data->ofile->writePixels(data->height);
1186 catch (
const std::exception &exc) {
1187 std::cerr <<
"OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
1190 std::cerr <<
"OpenEXR-writePixels: UNKNOWN ERROR" << std::endl;
1193 if (rect_half !=
nullptr) {
1198 printf(
"Error: attempt to save MultiLayer without layers.\n");
1203 void *handle,
int partx,
int party,
int level,
const char *viewname,
bool empty)
1207 FrameBuffer frameBuffer;
1208 std::string
view(viewname);
1211 exr_printf(
"\nIMB_exrtile_write_channels(view: %s)\n", viewname);
1212 exr_printf(
"%s %-6s %-22s \"%s\"\n",
"p",
"view",
"name",
"internal_name");
1213 exr_printf(
"---------------------------------------------------------------------\n");
1219 if (!
STREQ(viewname, echan->m->view.c_str())) {
1224 echan->m->part_number,
1225 echan->m->view.c_str(),
1226 echan->m->name.c_str(),
1227 echan->m->internal_name.c_str());
1229 float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
1230 frameBuffer.insert(echan->m->internal_name,
1233 echan->xstride *
sizeof(
float),
1234 echan->ystride *
sizeof(
float)));
1238 TiledOutputPart out(*data->mpofile, view_id);
1239 out.setFrameBuffer(frameBuffer);
1243 out.writeTile(partx / data->tilex, party / data->tiley, level);
1245 catch (
const std::exception &exc) {
1246 std::cerr <<
"OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
1249 std::cerr <<
"OpenEXR-writeTile: UNKNOWN ERROR" << std::endl;
1256 int numparts = data->
ifile->parts();
1259 const StringAttribute *ta = data->ifile->header(0).findTypedAttribute<StringAttribute>(
1260 "BlenderMultiChannel");
1263 short flip = (ta &&
STRPREFIX(ta->value().c_str(),
"Blender V2.43"));
1266 "\nIMB_exr_read_channels\n%s %-6s %-22s "
1267 "\"%s\"\n---------------------------------------------------------------------\n",
1273 for (
int i = 0; i < numparts; i++) {
1275 InputPart in(*data->ifile, i);
1276 Header header = in.header();
1277 Box2i dw = header.dataWindow();
1280 FrameBuffer frameBuffer;
1283 if (echan->m->part_number != i) {
1288 echan->m->part_number,
1289 echan->m->view.c_str(),
1290 echan->m->name.c_str(),
1291 echan->m->internal_name.c_str());
1294 float *rect = echan->rect;
1295 size_t xstride = echan->xstride *
sizeof(
float);
1296 size_t ystride = echan->ystride *
sizeof(
float);
1300 rect -= echan->xstride * (dw.min.x - dw.min.y * data->width);
1302 rect += echan->xstride * (data->height - 1) * data->width;
1307 rect -= echan->xstride * (dw.min.x + dw.min.y * data->width);
1310 frameBuffer.insert(echan->m->internal_name,
1311 Slice(Imf::FLOAT, (
char *)rect, xstride, ystride));
1317 in.setFrameBuffer(frameBuffer);
1318 exr_printf(
"readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, dw.min.y, dw.max.y);
1319 in.readPixels(dw.min.y, dw.max.y);
1321 catch (
const std::exception &exc) {
1322 std::cerr <<
"OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
1326 std::cerr <<
"OpenEXR-readPixels: UNKNOWN ERROR: " << std::endl;
1334 void *(*addview)(
void *base,
const char *
str),
1335 void *(*addlayer)(
void *base,
const char *
str),
1336 void (*addpass)(
void *base,
1341 const char *chan_id,
1347 if (data->multiView->empty()) {
1352 for (
const std::string &view_name : *data->multiView) {
1353 addview(base, view_name.c_str());
1358 printf(
"cannot convert multilayer, no layers in handle\n");
1363 void *laybase = addlayer(base, lay->name);
1368 pass->internal_name,
1373 pass->rect =
nullptr;
1384 delete data->ifile_stream;
1386 delete data->mpofile;
1387 delete data->ofile_stream;
1388 delete data->multiView;
1390 data->ifile =
nullptr;
1391 data->ifile_stream =
nullptr;
1392 data->ofile =
nullptr;
1393 data->mpofile =
nullptr;
1394 data->ofile_stream =
nullptr;
1420 const char delims[] = {
'.',
'\0'};
1429 return int(end - *token);
1434 const char *channelname,
1435 const bool has_xyz_channels)
1442 else if (echan->
chan_id ==
'Y' && !has_xyz_channels) {
1443 BLI_strncpy(passname, channelname, passname_maxncpy);
1445 else if (
ELEM(echan->
chan_id,
'R',
'G',
'B',
'A',
'V',
'X',
'Y',
'Z')) {
1446 BLI_strncpy(passname,
"Combined", passname_maxncpy);
1449 BLI_strncpy(passname, channelname, passname_maxncpy);
1455 const char *channelname,
1465 BLI_strncpy(passname, channelname, passname_maxncpy);
1471 bool has_xyz_channels)
1474 const char *name = echan->
m->name.c_str();
1475 const char *end = name + strlen(name);
1495 printf(
"multilayer read: bad channel name: %s\n", name);
1500 BLI_strncpy(channelname, token, std::min(
len + 1,
sizeof(channelname)));
1516 if (
ELEM(chan_id,
'X',
'Y',
'Z',
'R',
'G',
'B',
'U',
'V',
'A')) {
1548 printf(
"multilayer read: bad channel name: %s\n", name);
1561 BLI_strncpy(layname, name, std::min(layname_maxncpy,
int(end - name) + 1));
1574 if (lay ==
nullptr) {
1575 lay = MEM_cnew<ExrLayer>(
"exr layer");
1587 if (pass ==
nullptr) {
1588 pass = MEM_cnew<ExrPass>(
"exr pass");
1590 if (
STREQ(passname,
"Combined")) {
1598 STRNCPY(pass->name, passname);
1605 bool x_found =
false;
1606 bool y_found =
false;
1607 bool z_found =
false;
1609 if (
ELEM(channel->m->name,
"X",
"x")) {
1612 if (
ELEM(channel->m->name,
"Y",
"y")) {
1615 if (
ELEM(channel->m->name,
"Z",
"z")) {
1620 return x_found && y_found && z_found;
1626 const MultiPartInputFile &file)
1628 std::vector<MultiViewChannelName>
channels;
1631 StringVector multiview;
1632 bool has_multiview =
false;
1633 if (file.parts() == 1) {
1634 if (hasMultiView(file.header(0))) {
1635 multiview = multiView(file.header(0));
1636 has_multiview =
true;
1641 for (
int p = 0; p < file.parts(); p++) {
1642 const ChannelList &c = file.header(p).channels();
1644 std::string part_view =
"";
1645 if (file.header(p).hasView()) {
1646 part_view = file.header(p).view();
1648 std::string part_name =
"";
1649 if (file.header(p).hasName()) {
1650 part_name = file.header(p).name();
1653 for (ChannelList::ConstIterator i = c.begin(); i != c.end(); i++) {
1654 MultiViewChannelName m;
1655 m.name = std::string(i.name());
1656 m.internal_name = m.name;
1658 if (has_multiview) {
1659 m.view = viewFromChannelName(m.name, multiview);
1660 m.name = removeViewName(m.internal_name, m.view);
1667 if (!part_name.empty()) {
1668 m.name = part_name +
"." + m.name;
1672 channels.push_back(m);
1685 for (
const MultiViewChannelName &channel :
channels) {
1687 data,
nullptr, channel.name.c_str(), channel.view.c_str(), 0, 0,
nullptr,
false);
1690 echan->
m->name = channel.name;
1691 echan->
m->view = channel.view;
1692 echan->
m->part_number = channel.part_number;
1693 echan->
m->internal_name = channel.internal_name;
1701 for (; echan; echan = echan->
next) {
1704 const char *view = echan->
m->view.c_str();
1707 STRNCPY(internal_name, passname);
1709 if (view[0] !=
'\0') {
1711 SNPRINTF(tmp_pass,
"%s.%s", passname, view);
1718 pass->chan[pass->totchan] = echan;
1722 STRNCPY(pass->internal_name, internal_name);
1730 printf(
"error, too many channels in one pass: %s\n", echan->
m->name.c_str());
1737 if (pass->totchan) {
1739 data->width * data->height * pass->totchan *
sizeof(
float),
"pass rect");
1740 if (pass->totchan == 1) {
1742 echan->
rect = pass->rect;
1745 pass->chan_id[0] = echan->
chan_id;
1750 memset(lookup, 0,
sizeof(lookup));
1753 if (
ELEM(pass->totchan, 3, 4)) {
1754 if (pass->chan[0]->chan_id ==
'B' || pass->chan[1]->chan_id ==
'B' ||
1755 pass->chan[2]->chan_id ==
'B')
1757 lookup[
uint(
'R')] = 0;
1758 lookup[
uint(
'G')] = 1;
1759 lookup[
uint(
'B')] = 2;
1760 lookup[
uint(
'A')] = 3;
1762 else if (pass->chan[0]->chan_id ==
'Y' || pass->chan[1]->chan_id ==
'Y' ||
1763 pass->chan[2]->chan_id ==
'Y')
1765 lookup[
uint(
'X')] = 0;
1766 lookup[
uint(
'Y')] = 1;
1767 lookup[
uint(
'Z')] = 2;
1768 lookup[
uint(
'W')] = 3;
1771 lookup[
uint(
'U')] = 0;
1772 lookup[
uint(
'V')] = 1;
1773 lookup[
uint(
'A')] = 2;
1775 for (
int a = 0; a < pass->totchan; a++) {
1776 echan = pass->chan[a];
1778 echan->
xstride = pass->totchan;
1779 echan->
ystride = data->width * pass->totchan;
1784 for (
int a = 0; a < pass->totchan; a++) {
1786 echan->
rect = pass->rect + a;
1787 echan->
xstride = pass->totchan;
1788 echan->
ystride = data->width * pass->totchan;
1789 pass->chan_id[a] = echan->
chan_id;
1802 MultiPartInputFile &file,
1809 data->ifile = &
file;
1811 data->width = width;
1812 data->height = height;
1829 va_start(args, fmt);
1839 int numparts = file.parts();
1840 if (numparts == 1 && hasMultiView(file.header(0))) {
1841 const StringVector views = multiView(file.header(0));
1842 printf(
"OpenEXR-load: MultiView file\n");
1843 printf(
"OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
1844 for (
const std::string &view : views) {
1845 printf(
"OpenEXR-load: Found view %s\n", view.c_str());
1848 else if (numparts > 1) {
1849 printf(
"OpenEXR-load: MultiPart file\n");
1850 for (
int i = 0; i < numparts; i++) {
1851 if (file.header(i).hasView()) {
1852 printf(
"OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
1857 for (
int j = 0; j < numparts; j++) {
1858 const ChannelList &channels = file.header(j).channels();
1859 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1860 const Channel &channel = i.channel();
1861 printf(
"OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
1869 const ChannelList &channels = file.header(0).channels();
1871 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1873 const char *
str = i.name();
1884static int exr_has_rgb(MultiPartInputFile &file,
const char *rgb_channels[3])
1888 static const char *channel_names[] = {
1889 "V",
"R",
"Red",
"G",
"Green",
"B",
"Blue",
"AR",
"RA",
"AG",
"GA",
"AB",
"BA",
nullptr};
1891 const Header &header = file.header(0);
1892 int num_channels = 0;
1894 for (
int i = 0; channel_names[i]; i++) {
1896 std::string lower_case_name = std::string(channel_names[i]);
1897 std::transform(lower_case_name.begin(),
1898 lower_case_name.end(),
1899 lower_case_name.begin(),
1900 [](
uchar c) { return std::tolower(c); });
1902 if (header.channels().findChannel(channel_names[i]) ||
1903 header.channels().findChannel(lower_case_name))
1905 rgb_channels[num_channels++] = channel_names[i];
1906 if (num_channels == 3) {
1912 return num_channels;
1920 const Header &header = file.header(0);
1921 return header.channels().findChannel(
"Y") !=
nullptr;
1926 const Header &header = file.header(0);
1927 return header.channels().findChannel(
"BY") !=
nullptr &&
1928 header.channels().findChannel(
"RY") !=
nullptr;
1933 const Header &header = file.header(0);
1934 return !(header.channels().findChannel(
"A") ==
nullptr);
1939 const Header &header = file.header(0);
1940 return (header.channels().findChannel(
"X") !=
nullptr ||
1941 header.channels().findChannel(
"x") !=
nullptr) &&
1942 (header.channels().findChannel(
"Y") !=
nullptr ||
1943 header.channels().findChannel(
"y") !=
nullptr) &&
1944 (header.channels().findChannel(
"Z") !=
nullptr ||
1945 header.channels().findChannel(
"z") !=
nullptr);
1950 const ChannelList &channels = file.header(0).channels();
1951 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1952 const Channel &channel = i.channel();
1953 if (channel.type !=
HALF) {
1962 const ChannelList &channels = file.header(0).channels();
1963 std::set<std::string> layerNames;
1967 channels.layers(layerNames);
1969 return !layerNames.empty();
1973 StringVector &views,
1974 bool *r_singlelayer,
1978 std::set<std::string> layerNames;
1980 *r_singlelayer =
true;
1981 *r_multilayer = *r_multiview =
false;
1984 channels.layers(layerNames);
1986 if (!views.empty() && !views[0].empty()) {
1987 *r_multiview =
true;
1990 *r_singlelayer =
false;
1991 *r_multilayer = (layerNames.size() > 1);
1992 *r_multiview =
false;
1996 if (!layerNames.empty()) {
2004 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
2005 for (
const std::string &layer_name : layerNames) {
2008 std::string layerName = layer_name;
2009 size_t pos = layerName.rfind(
'.');
2011 if (
pos == std::string::npos) {
2012 *r_multilayer =
true;
2013 *r_singlelayer =
false;
2021 *r_singlelayer =
true;
2022 *r_multilayer =
false;
2030 for (
int p = 0; p < file.parts(); p++) {
2031 if (hasMultiView(file.header(p))) {
2041 return file.parts() > 1;
2072 ImBuf *ibuf =
nullptr;
2074 MultiPartInputFile *file =
nullptr;
2086 file =
new MultiPartInputFile(*membuf);
2088 Box2i dw = file->header(0).dataWindow();
2089 const size_t width = dw.max.x - dw.min.x + 1;
2090 const size_t height = dw.max.y - dw.min.y + 1;
2103 printf(
"Error: can't process EXR multilayer file\n");
2111 if (hasXDensity(file->header(0))) {
2113 ibuf->
ppm[0] =
double(xDensity(file->header(0))) / 0.0254;
2114 ibuf->
ppm[1] = ibuf->
ppm[0] *
double(file->header(0).pixelAspectRatio());
2122 const Header &header = file->header(0);
2123 Header::ConstIterator iter;
2126 for (iter = header.begin(); iter != header.end(); iter++) {
2127 const StringAttribute *attr = file->header(0).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 IStream *stream =
nullptr;
2279 Imf::RgbaInputFile *file =
nullptr;
2297 file =
new RgbaInputFile(*stream, 1);
2299 if (!file->isComplete()) {
2303 Imath::Box2i dw = file->dataWindow();
2304 int source_w = dw.max.x - dw.min.x + 1;
2305 int source_h = dw.max.y - dw.min.y + 1;
2306 *r_width = source_w;
2307 *r_height = source_h;
2310 if (file->header().hasPreviewImage()) {
2311 const Imf::PreviewImage &preview = file->header().previewImage();
2313 (
uint8_t *)preview.pixels(),
nullptr, preview.width(), preview.height(), 4);
2322 if (colorspace && colorspace[0]) {
2326 float scale_factor = std::min(
float(max_thumb_size) /
float(source_w),
2327 float(max_thumb_size) /
float(source_h));
2328 int dest_w = std::max(
int(source_w * scale_factor), 1);
2329 int dest_h = std::max(
int(source_h * scale_factor), 1);
2334 Imf::Array<Imf::Rgba> pixels(source_w);
2337 for (
int h = 0; h < dest_h; h++) {
2340 int source_y =
int(
float(h) / scale_factor) + dw.min.y;
2341 file->setFrameBuffer(&pixels[0] - dw.min.x - source_y * source_w, 1, source_w);
2342 file->readPixels(source_y);
2344 for (
int w = 0;
w < dest_w;
w++) {
2346 int source_x =
int(std::min<int>((
w / scale_factor), dw.max.x - 1));
2348 dest_px[0] = pixels[source_x].r;
2349 dest_px[1] = pixels[source_x].g;
2350 dest_px[2] = pixels[source_x].b;
2351 dest_px[3] = pixels[source_x].a;
2355 if (file->lineOrder() == INCREASING_Y) {
2365 catch (
const std::exception &exc) {
2366 std::cerr << exc.what() << std::endl;
2372 std::cerr <<
"OpenEXR-Thumbnail: UNKNOWN ERROR" << std::endl;
2385 Imf::staticInitialize();
2392 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)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void * BLI_rfindstring(const struct 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 STRNCPY(dst, src)
#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
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)
typedef double(DMatrix)[4][4]
@ COLOR_ROLE_DEFAULT_FLOAT
void IMB_flipy(ImBuf *ibuf)
void IMB_rect_from_float(ImBuf *ibuf)
bool imb_addrectfloatImBuf(ImBuf *ibuf, const unsigned int channels, bool initialize_pixels=true)
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf)
bool imb_addencodedbufferImBuf(ImBuf *ibuf)
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
void colorspace_set_default_role(char *colorspace, int size, int role)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
struct ImBuf * IMB_allocFromBuffer(const uint8_t *, const float *, unsigned int, unsigned int, unsigned int)
void IMB_freeImBuf(ImBuf *)
void *(* MEM_mallocN)(size_t len, const char *str)
void MEM_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
static bool parse_channels(const ImageSpec &in_spec, vector< MergeImageLayer > &layers, string &error)
bool IMB_exr_begin_write(void *handle, const char *filepath, int width, int height, int compress, const StampData *stamp)
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)
ImBuf * imb_load_filepath_thumbnail_openexr(const char *filepath, const int, const size_t max_thumb_size, char colorspace[], size_t *r_width, size_t *r_height)
static void openexr_header_compression(Header *header, int compression)
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)
ImBuf * imb_load_openexr(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
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)
static bool imb_save_openexr_float(ImBuf *ibuf, const char *filepath, const int flags)
void IMB_exr_close(void *handle)
void IMB_exrtile_begin_write(void *handle, const char *filepath, int mipmap, int width, int height, int tilex, int tiley)
void IMB_exr_clear_channels(void *handle)
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)
static int exr_has_rgb(MultiPartInputFile &file, const char *rgb_channels[3])
bool IMB_exr_begin_read(void *handle, const char *filepath, int *width, int *height, const bool parse_channels)
static int imb_exr_split_token(const char *str, const char *end, const char **token)
float * IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
#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)
void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname, bool empty)
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)
bool IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
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 internal_name[EXR_PASS_MAXNAME]
ExrChannel * chan[EXR_PASS_MAXCHAN]
ImBufFloatBuffer float_buffer
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned int encoded_buffer_size
ImBufByteBuffer encoded_buffer
unsigned int encoded_size
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)