From e0631dd78228af5d2183e73feeb2544ab53c8f94 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 28 Nov 2025 01:53:40 +0100 Subject: [PATCH] feat(exr): Write OpenEXR colorInteropID metadata based on oiio:ColorSpace If the colorspace exists and has an interop ID in an OCIO 2.5 config, use that. Otherwise check if the colorspace is equivalent to a known color interop ID. Signed-off-by: Brecht Van Lommel --- src/openexr.imageio/exroutput.cpp | 10 +++++++++ testsuite/openexr-suite/ref/out.txt | 34 +++++++++++++++++++++++++++++ testsuite/openexr-suite/run.py | 8 +++++++ 3 files changed, 52 insertions(+) diff --git a/src/openexr.imageio/exroutput.cpp b/src/openexr.imageio/exroutput.cpp index 11b350ff38..d164ee5690 100644 --- a/src/openexr.imageio/exroutput.cpp +++ b/src/openexr.imageio/exroutput.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -1026,6 +1027,15 @@ OpenEXROutput::spec_to_header(ImageSpec& spec, int subimage, } } + // Set color interop ID from colorspace + if (spec.get_string_attribute("colorInteropID").empty()) { + const ColorConfig& colorconfig(ColorConfig::default_colorconfig()); + string_view colorspace = spec.get_string_attribute("oiio:ColorSpace"); + string_view interop_id = colorconfig.get_color_interop_id(colorspace); + if (!interop_id.empty()) + spec.attribute("colorInteropID", interop_id); + } + // Deal with all other params for (const auto& p : spec.extra_attribs) put_parameter(p.name().string(), p.type(), p.data(), header); diff --git a/testsuite/openexr-suite/ref/out.txt b/testsuite/openexr-suite/ref/out.txt index a6affcc883..ca7553d0e3 100644 --- a/testsuite/openexr-suite/ref/out.txt +++ b/testsuite/openexr-suite/ref/out.txt @@ -369,3 +369,37 @@ Full command line was: oiiotool ERROR: -o : Cannot output non-compliant ACES Container in 'strict' mode. REASON: EXR data type is not 'HALF' as required for an ACES Container. Full command line was: > oiiotool --create 4x4 3 -d float --compression none -sattrib openexr:ACESContainerPolicy strict -o strict-fail.exr +Reading color_interop_id_scene_linear.exr +color_interop_id_scene_linear.exr : 4 x 4, 3 channel, float openexr + SHA-1: D7699308C38CD04EEB732577A82D31D04E05A339 + channel list: R, G, B + colorInteropID: "lin_ap1_scene" + compression: "zip" + PixelAspectRatio: 1 + screenWindowCenter: 0, 0 + screenWindowWidth: 1 + oiio:ColorSpace: "lin_ap1_scene" + oiio:subimages: 1 + openexr:lineOrder: "increasingY" +Reading color_interop_id_linear_adobergb.exr +color_interop_id_linear_adobergb.exr : 4 x 4, 3 channel, float openexr + SHA-1: D7699308C38CD04EEB732577A82D31D04E05A339 + channel list: R, G, B + colorInteropID: "lin_adobergb_scene" + compression: "zip" + PixelAspectRatio: 1 + screenWindowCenter: 0, 0 + screenWindowWidth: 1 + oiio:ColorSpace: "lin_adobergb_scene" + oiio:subimages: 1 + openexr:lineOrder: "increasingY" +Reading color_interop_id_unknown.exr +color_interop_id_unknown.exr : 4 x 4, 3 channel, float openexr + SHA-1: D7699308C38CD04EEB732577A82D31D04E05A339 + channel list: R, G, B + compression: "zip" + PixelAspectRatio: 1 + screenWindowCenter: 0, 0 + screenWindowWidth: 1 + oiio:subimages: 1 + openexr:lineOrder: "increasingY" diff --git a/testsuite/openexr-suite/run.py b/testsuite/openexr-suite/run.py index 105cd03ac2..8462ca8bf2 100755 --- a/testsuite/openexr-suite/run.py +++ b/testsuite/openexr-suite/run.py @@ -83,3 +83,11 @@ # Invalid data type command += oiiotool("--create 4x4 3 -d float --compression none -sattrib openexr:ACESContainerPolicy strict -o strict-fail.exr", failureok=True) + +# Check color interop ID output +command += oiiotool("--create 4x4 3 --attrib oiio:ColorSpace scene_linear -o color_interop_id_scene_linear.exr") +command += info_command("color_interop_id_scene_linear.exr", safematch=True) +command += oiiotool("--create 4x4 3 --attrib oiio:ColorSpace lin_adobergb_scene -o color_interop_id_linear_adobergb.exr") +command += info_command("color_interop_id_linear_adobergb.exr", safematch=True) +command += oiiotool("--create 4x4 3 --attrib oiio:ColorSpace unknown_interop_id -o color_interop_id_unknown.exr") +command += info_command("color_interop_id_unknown.exr", safematch=True)