Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cmake/testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ macro (oiio_add_all_tests)
# properly supported all compression types (DWA in particular).
list (APPEND all_openexr_tests openexr-compression)
endif ()
if (OpenEXR_VERSION VERSION_GREATER_EQUAL 3.3)
# OpenEXR 3.3 is when IDManifest was introduced
list (APPEND all_openexr_tests openexr-idmanifest)
endif ()
# Run all OpenEXR tests without core library
oiio_add_tests (${all_openexr_tests} openexr-luminance-chroma
ENVIRONMENT OPENIMAGEIO_OPTIONS=openexr:core=0
Expand Down
13 changes: 13 additions & 0 deletions src/doc/builtinplugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,19 @@ The official OpenEXR site is http://www.openexr.com/.
- If nonzero, indicates whether the image is a luminance-chroma image.
Upon reading, the subsampled Y/BY/RY(/A) channels of luminance-chroma
images are automatically converted to RGB(A) channels.
* - ``openexr::deepImageState``
- string
- If present in a deep file, reveals the deep image state, one of:
``"messy"``, ``"sorted"``, ``"non_overlapping"``, or ``"tidy"``.
See the OpenEXR documentation for explanations. This metadata was
added in OpenImageIO 3.1.
* - ``openexr::compressedIDManifest``
- uint8[]
- A byte array whose first 8 bytes are the uncompressed size of the
manifest, as a little-endian uint64. Then beginning at byte 8,
the remainder is the zip-compressed serialized manifest.
This metadata was added in OpenImageIO 3.1, and is only supported when
OIIO is built against OpenEXR 3.1 or newer.
* - *other*
-
- All other attributes will be added to the ImageSpec by their name and
Expand Down
40 changes: 40 additions & 0 deletions src/openexr.imageio/exrinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ OIIO_GCC_PRAGMA(GCC diagnostic ignored "-Wunused-parameter")
#include <OpenEXR/ImfChromaticitiesAttribute.h>
#include <OpenEXR/ImfCompressionAttribute.h>
#include <OpenEXR/ImfDeepFrameBuffer.h>
#include <OpenEXR/ImfDeepImageStateAttribute.h>
#include <OpenEXR/ImfDeepScanLineInputPart.h>
#include <OpenEXR/ImfDeepTiledInputPart.h>
#include <OpenEXR/ImfDoubleAttribute.h>
#include <OpenEXR/ImfEnvmapAttribute.h>
#include <OpenEXR/ImfFloatAttribute.h>
#include <OpenEXR/ImfFloatVectorAttribute.h>
#include <OpenEXR/ImfHeader.h>
#include <OpenEXR/ImfIDManifestAttribute.h>
#include <OpenEXR/ImfInputPart.h>
#include <OpenEXR/ImfIntAttribute.h>
#include <OpenEXR/ImfKeyCodeAttribute.h>
Expand Down Expand Up @@ -642,6 +644,44 @@ OpenEXRInput::PartInfo::parse_header(OpenEXRInput* in,
default: break;
}
spec.attribute("openexr:lineOrder", lineOrder);
} else if (type == "deepImageState") {
auto attr = header->findTypedAttribute<Imf::DeepImageStateAttribute>(
name);
if (attr) {
const char* val = "messy";
switch (attr->value()) {
case Imf::DIS_MESSY: val = "messy"; break;
case Imf::DIS_SORTED: val = "sorted"; break;
case Imf::DIS_NON_OVERLAPPING: val = "non_overlapping"; break;
case Imf::DIS_TIDY: val = "tidy"; break;
default: break;
}
spec.attribute("openexr:deepImageState", val);
}
} else if (type == "idmanifest") {
auto attr = header->findTypedAttribute<Imf::IDManifestAttribute>(
name);
if (attr) {
// print("CompressedIDManifest size {}\n",
// attr->value()._compressedDataSize);
size_t csize(attr->value()._compressedDataSize);
// NOTE: The blob of bytes we're making consists of:
// Bytes 0-7: little endian uint64 giving the *uncompressed*
// size that will be needed for the serialized IDM.
// Bytes 8-(csize-1): the zip-compressed serialized IDManifest.
size_t blobsize = csize + 8;
std::unique_ptr<std::byte[]> blob(new std::byte[blobsize]);
uint64_t usize = attr->value()._uncompressedDataSize;
if constexpr (bigendian())
usize = byteswap(usize);
memcpy(blob.get(), &usize, sizeof(usize));
memcpy(blob.get() + 8, attr->value()._data, csize);
spec.attribute("openexr:compressedIDManifest",
TypeDesc(TypeDesc::UINT8, blobsize), blob.get());
} else {
// print("idManifest found but not retrieved?\n");
}

} else {
#if 0
print(std::cerr, " unknown attribute '{}' name '{}'\n",
Expand Down
37 changes: 36 additions & 1 deletion src/openexr.imageio/exrinput_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ static std::map<std::string, std::string> cexr_tag_to_oiio_std {
{ "chunkCount", "openexr:chunkCount" },
{ "maxSamplesPerPixel", "openexr:maxSamplesPerPixel" },
{ "dwaCompressionLevel", "openexr:dwaCompressionLevel" },
{ "idManifest", "openexr:compressedIDManifest" },
// Ones to skip because we handle specially or consider them irrelevant
{ "channels", "" },
{ "compression", "" },
Expand Down Expand Up @@ -742,8 +743,42 @@ OpenEXRCoreInput::PartInfo::parse_header(OpenEXRCoreInput* in,
break;
}

#if OPENEXR_CODED_VERSION >= 30300
case EXR_ATTR_DEEP_IMAGE_STATE: {
const char* val = "messy";
switch (attr->uc) {
case EXR_DIS_MESSY: val = "messy"; break;
case EXR_DIS_SORTED: val = "sorted"; break;
case EXR_DIS_NON_OVERLAPPING: val = "non_overlapping"; break;
case EXR_DIS_TIDY: val = "tidy"; break;
default: break;
}
spec.attribute("openexr:deepImageState", val);
break;
}
#endif

#if OPENEXR_CODED_VERSION >= 30400
case EXR_ATTR_BYTES: {
spec.attribute(oname, TypeDesc(TypeDesc::UINT8, attr->bytes->size),
make_span(attr->bytes->data, attr->bytes->size));
break;
}
#endif

case EXR_ATTR_OPAQUE: {
if (Strutil::iequals(oname, "idManifest"))
oname = "openexr:compressedIDManifeset"; // our name for this
spec.attribute(oname, TypeDesc(TypeDesc::UINT8, attr->opaque->size),
attr->opaque->packed_data);
// NOTE: The blob of bytes we're making consists of:
// Bytes 0-7: little endian uint64 giving the *uncompressed*
// size that will be needed for the serialized IDM.
// Bytes 8-(size-1): the zip-compressed serialized IDManifest.
break;
}

case EXR_ATTR_PREVIEW:
case EXR_ATTR_OPAQUE:
case EXR_ATTR_ENVMAP:
case EXR_ATTR_COMPRESSION:
case EXR_ATTR_CHLIST:
Expand Down
51 changes: 42 additions & 9 deletions src/openexr.imageio/exroutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ OIIO_GCC_PRAGMA(GCC diagnostic ignored "-Wunused-parameter")
#include <OpenEXR/ImfCRgbaFile.h> // JUST to get symbols to figure out version!
#include <OpenEXR/ImfChromaticitiesAttribute.h>
#include <OpenEXR/ImfCompressionAttribute.h>
#include <OpenEXR/ImfDeepImageStateAttribute.h>
#include <OpenEXR/ImfEnvmapAttribute.h>
#include <OpenEXR/ImfFloatAttribute.h>
#include <OpenEXR/ImfFloatVectorAttribute.h>
#include <OpenEXR/ImfHeader.h>
#include <OpenEXR/ImfIDManifestAttribute.h>
#include <OpenEXR/ImfIntAttribute.h>
#include <OpenEXR/ImfKeyCodeAttribute.h>
#include <OpenEXR/ImfMatrixAttribute.h>
Expand Down Expand Up @@ -937,7 +939,7 @@ OpenEXROutput::put_parameter(const std::string& name, TypeDesc type,

// Special cases
if (Strutil::iequals(xname, "Compression") && type == TypeString) {
const char* str = *(char**)data;
const char* str = *(const char**)data;
header.compression() = Imf::ZIP_COMPRESSION; // Default
if (str) {
if (Strutil::iequals(str, "none"))
Expand Down Expand Up @@ -974,7 +976,7 @@ OpenEXROutput::put_parameter(const std::string& name, TypeDesc type,
}

if (Strutil::iequals(xname, "openexr:lineOrder") && type == TypeString) {
const char* str = *(char**)data;
const char* str = *(const char**)data;
header.lineOrder() = Imf::INCREASING_Y; // Default
if (str) {
if (Strutil::iequals(str, "randomY")
Expand All @@ -987,6 +989,36 @@ OpenEXROutput::put_parameter(const std::string& name, TypeDesc type,
return true;
}

if (Strutil::iequals(xname, "openexr:deepImageState")
&& type == TypeString) {
const char* str = *(const char**)data;
Imf::DeepImageState val = Imf::DeepImageState::DIS_MESSY;
if (!strcmp(str, "sorted"))
val = Imf::DeepImageState::DIS_SORTED;
else if (!strcmp(str, "non_overlapping"))
val = Imf::DeepImageState::DIS_NON_OVERLAPPING;
else if (!strcmp(str, "tidy"))
val = Imf::DeepImageState::DIS_TIDY;
header.insert(xname.c_str(), Imf::DeepImageStateAttribute(val));
return true;
}

if (Strutil::iequals(xname, "openexr:compressedIDManifest")
&& type.basetype == TypeDesc::UINT8 && type.arraylen > 8) {
const unsigned char* bdata = (const unsigned char*)data;
uint64_t usize = 0;
memcpy(&usize, bdata, sizeof(usize));
if constexpr (bigendian())
usize = byteswap(usize);
Imf::CompressedIDManifest idm;
idm._compressedDataSize = static_cast<int>(type.size() - 8);
idm._uncompressedDataSize = usize;
idm._data = const_cast<unsigned char*>(bdata + 8);
header.insert("idManifest", Imf::IDManifestAttribute(idm));
idm._data = nullptr;
return true;
}

// Special handling of any remaining "oiio:*" metadata.
if (Strutil::istarts_with(xname, "oiio:")) {
if (Strutil::iequals(xname, "oiio:ConstantColor")
Expand Down Expand Up @@ -1052,27 +1084,28 @@ OpenEXROutput::put_parameter(const std::string& name, TypeDesc type,
if (type.aggregate == TypeDesc::SCALAR) {
if (type == TypeDesc::INT || type == TypeDesc::UINT) {
header.insert(xname.c_str(),
Imf::IntAttribute(*(int*)data));
Imf::IntAttribute(*(const int*)data));
return true;
}
if (type == TypeDesc::INT16) {
header.insert(xname.c_str(),
Imf::IntAttribute(*(short*)data));
Imf::IntAttribute(*(const short*)data));
return true;
}
if (type == TypeDesc::UINT16) {
header.insert(xname.c_str(),
Imf::IntAttribute(*(unsigned short*)data));
Imf::IntAttribute(
*(const unsigned short*)data));
return true;
}
if (type == TypeDesc::FLOAT) {
header.insert(xname.c_str(),
Imf::FloatAttribute(*(float*)data));
Imf::FloatAttribute(*(const float*)data));
return true;
}
if (type == TypeDesc::HALF) {
header.insert(xname.c_str(),
Imf::FloatAttribute((float)*(half*)data));
header.insert(xname.c_str(), Imf::FloatAttribute((float)*(
const half*)data));
return true;
}
if (type == TypeString && !((const ustring*)data)->empty()) {
Expand All @@ -1083,7 +1116,7 @@ OpenEXROutput::put_parameter(const std::string& name, TypeDesc type,
}
if (type == TypeDesc::DOUBLE) {
header.insert(xname.c_str(),
Imf::DoubleAttribute(*(double*)data));
Imf::DoubleAttribute(*(const double*)data));
return true;
}
}
Expand Down
28 changes: 28 additions & 0 deletions testsuite/openexr-idmanifest/ref/out.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Reading src/manifest.exr
src/manifest.exr : 16 x 16, 8 channel, deep half/half/half/half/half/uint/uint/uint openexr
SHA-1: 526B00A9E52F6EF667E02168CF20772957ACA451
channel list: R (half), G (half), B (half), A (half), Z (half), materialid (uint), modelid (uint), particleid (uint)
compression: "zips"
PixelAspectRatio: 1
screenWindowCenter: 0, 0
screenWindowWidth: 1
version: 1
oiio:subimages: 1
openexr:chunkCount: 16
openexr:compressedIDManifest: 55, 1, 0, 0, 0, 0, 0, 0, 120, 94, 99, 0, 2, 110, 32, 230, ... [250 x uint8]
openexr:deepImageState: "tidy"
openexr:lineOrder: "increasingY"
Reading manifest.exr
manifest.exr : 16 x 16, 8 channel, deep half/half/half/half/half/uint/uint/uint openexr
SHA-1: 526B00A9E52F6EF667E02168CF20772957ACA451
channel list: R (half), G (half), B (half), A (half), Z (half), materialid (uint), modelid (uint), particleid (uint)
compression: "zips"
PixelAspectRatio: 1
screenWindowCenter: 0, 0
screenWindowWidth: 1
version: 1
oiio:subimages: 1
openexr:chunkCount: 16
openexr:compressedIDManifest: 55, 1, 0, 0, 0, 0, 0, 0, 120, 94, 99, 0, 2, 110, 32, 230, ... [250 x uint8]
openexr:deepImageState: "tidy"
openexr:lineOrder: "increasingY"
13 changes: 13 additions & 0 deletions testsuite/openexr-idmanifest/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python

# Copyright Contributors to the OpenImageIO project.
# SPDX-License-Identifier: Apache-2.0
# https://github.com/AcademySoftwareFoundation/OpenImageIO


# Multi-part, not deep
command += info_command ("src/manifest.exr", safematch = True)
command += oiiotool ("src/manifest.exr -o manifest.exr")
command += info_command ("./manifest.exr", safematch = True)

outputs += [ "out.txt" ]
Binary file added testsuite/openexr-idmanifest/src/manifest.exr
Binary file not shown.
Loading