Skip to content

Refine colorInteropID support - #2560

Open
doug-walker wants to merge 4 commits into
AcademySoftwareFoundation:mainfrom
doug-walker:walker/interopid
Open

Refine colorInteropID support#2560
doug-walker wants to merge 4 commits into
AcademySoftwareFoundation:mainfrom
doug-walker:walker/interopid

Conversation

@doug-walker

@doug-walker doug-walker commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Now that the ASWF Color Interop Forum has published the Recommendations for the Color Interop ID and for identifying the color space of OpenEXR files, I've made an attempt to build on Cary's earlier PR and integrate the standard colorInteropID attribute more fully into the library.

  • Updated StandardAttributes and TechnicalIntroduction website pages.
  • Add support for colorInteropID to command-line tool exrstdattr.
  • Added API functions to validate color metadata in the header to both the C++ and core APIs.
  • Extended the exrinfo command-line tool to print warnings regarding header color metadata.
  • Added helper functions to convert between chromaticities and colorInteropID.
  • Added Python bindings for all new functions.
  • Added C++ and Python unit tests for all of the above. All tests pass locally on my machine.
  • Replaced links to the earlier draft recommendations on Google Docs with the Color Interop Forum URLs.

The exr2aces command-line tool and ImfAcesFile classes are obsolete and never actually implemented SMPTE ST-2065-4. They are unmodified by this PR and will be removed/deprecated in a separate PR, per TSC discussion.

Multi-part File Handling

The CIF Recommendation states that in a multi-part file, the colorInteropID of later parts should not be different than the first part. The allowed exceptions are if the colorInteropID is missing in the later part, or set to 'data'. Here's how that is handled via this PR:

  • MultiPartInputFile and the core API file reader, by default, will read non-conforming files. However, if strictHeaderValidation is true, it will throw/fail.
  • MultiPartOutputFile will throw, by default, if attempting to write non-conforming files. However, if overrideSharedAttributes is set to true, writing is allowed but subsequent non-conforming headers are set to match the first part.
  • Writing multi-part files with the core API allows creation of non-conforming files.

This is looser than how chromaticities are handled. Neither the C++ or core APIs are able to read a multi-part file where the chromaticities are different in each part. This is regardless of how strictHeaderValidation is set. The C++ API will not allow creation of such a file, although the core API will (I added a TODO regarding this as it seems undesirable to have the library able to produce files which may not be read).

This PR was assisted by Claude Code Sonnet 5.

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 29, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: doug-walker / name: Doug Walker (03d72ad)

@doug-walker doug-walker left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some comments that might be helpful to reviewers of this PR.

// New in OpenEXR v3.4

IMF_STD_ATTRIBUTE_DEF (colorInteropID, ColorInteropID, std::string)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the links and moved this up to be next to chromaticities.

Comment thread website/bin/exr2aces.rst Outdated
For RGB images, specifies the CIE (x,y) chromaticities of the
primaries and the white point.
primaries and the white point. Note: For most purposes, this
attribute has now been superseded by the colorInteropID.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was trying to figure out the right language here to capture the fact that the CIF OpenEXR document recommends that people switch over to using colorInteropID rather than chromaticities for most purposes.


</td>
</tr>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the links and moved this up to be next to chromaticities.

Comment thread website/TechnicalIntroduction.rst Outdated
Application developers are asked to take care when writing OpenEXR
files to avoid writing or propagating color space metadata which may
be incorrect. The colorInteropID should be omitted or set to ``unknown``
unless the application is confident in the value being written.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrote this based on colorInteropID rather than chromaticities.

In particular, you will notice that I removed the sentence: "If a file doesn't have a chromaticities attribute, display software should assume that the file's primaries and the white point match Rec. ITU-R BT.709-3." This was intentional for several reasons:

  1. It contradicts the new Color Interop Forum OpenEXR recommendation.
  2. It should probably be up to the application and/or color management system to determine the default, rather than making a blanket statement in OpenEXR.
  3. I feel this is partially responsible for application developers sometimes setting the chromaticities to Rec.709 even if they have no idea what the color space actually is, thereby breaking trust in the chromaticities attribute.

And I removed the part about CIE XYZ since it was misleading. If anyone did want to write XYZ values into an EXR file, it would typically not be using illuminant E (1/3, 1/3) as the white point.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be worth retaining some description of the chromaticities attribute, even if it is described as deprecated/legacy/ACES-only, since such files will continue to exist and need to be understood.
I'm also not clear if there's still a use case for using it to store completely arbitrary chromaticities, which the recommendation allows as long as no colorInteropID is set.
The Rec,709 and XYZ bits can go, though!

Color Interop ID. Provides a mechanism to identify the color space of the RGB images.
See `An ID for Color Interop <https://github.com/AcademySoftwareFoundation/ColorInterop/blob/main/Recommendations/03_ColorInteropID/ColorInteropID.md>`_
and `Identifying the Color Space of OpenEXR Files <https://github.com/AcademySoftwareFoundation/ColorInterop/blob/main/Recommendations/04_OpenEXRFiles/OpenEXRFiles.md>`_ for details.
New in OpenEXR v3.4.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the links and moved it up to be next to chromaticities.

Comment thread src/lib/OpenEXR/ImfAcesFile.h Outdated
// ColorInteropID -- leave a part's existing "data" tag alone, since
// it marks image data that is intentionally not color managed.
//
if (!hasColorInteropID (dst) || colorInteropID (dst) != "data")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this enforce that if the first part is data, then all parts must be data, but not the other way round? Is that intentional? (or should the clause also be skipped if src has a colorInteropID set to data, and the checkSharedAttributesvalues function have a similar clause?)

In any case, if parts are written with different colorinteropIDs, this function will delete that information from other parts, causing the reader to treat them as being in the wrong space. I would prefer either that the library always checked for colorInteropID consistency on MultiPartOutputFile with no option to bypass test or automatically "fix" attribute, or else all the colorInteropID logic was dropped from the SharedAttribute code, making the multipart rules of the Recommendation less strict.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it should not try to modify an existing value. Is it okay if I just handle it the same as chromaticities then?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the existing handling of chromaticities is a little dangerous, since it silently overrides potentially accurate metadata, without changing the pixels.

I'd be tempted leave out the colorInteropID from all this verification, which would allow files that don't strictly follow the recommendation. I certainly don't think anything should modify the metadata - it should either ignore problems or report an error.

One option for now would be to extend the API with a verification method that takes a list of headers and checks the attributes conform (including conflicts between chromaticities and colorInteropID attributes in the same part). That could be an optional method available for reading and writing files. A future update could call that by default on writing files, so preventing non-conforming files.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added verification functions.

@peterhillman

Copy link
Copy Markdown
Collaborator

What are your thoughts about adding support for colorInteropID names to the Chromaticities? Perhaps the spaces listed in the recommendation (lin_rec709_scene, lin_ap0_scene, lin_ap1_scene, lin_p3d65_scene, lin_rec2020_scene, lin_adobergb_scene) could be added as static Chromaticities variables, and a function added to turn those strings into chromaticities?

For lightweight utilities that aren't intended to be part of a VFX pipeline so don't need OpenColorIO, some kind of built-in support to help convert images to and from known space could encourage adoption of the attribute.

@doug-walker

Copy link
Copy Markdown
Contributor Author

Peter, yes, I'll add helper functions to convert between chromaticities and colorInteropID and vice versa. But I feel that adding color space conversion functions should be out of scope for this PR.

@peterhillman

Copy link
Copy Markdown
Collaborator

Peter, yes, I'll add helper functions to convert between chromaticities and colorInteropID and vice versa. But I feel that adding color space conversion functions should be out of scope for this PR.

The Chromaticities class has RGBtoXYZ and XYZtoRGB that return 4x4 matrices. With the colorInteropID to chromaticities addition, it will be possible to construct a matrix that converts between colorInteropID (or between a colorInteropID and arbitrary chromaticities) as long as white point adaptation isn't required.

A future "nice first issue" might be to move the adaptation code in ImfACESFile.cpp into ImfChromaticities, making it part of the API, and also adding a method that applies a matrix to the specified scanlines of a given FrameBuffer to do in-place color conversion

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
@doug-walker

Copy link
Copy Markdown
Contributor Author

@peterhillman , I've made some of the changes you requested:

  • Added the colorInteropID/chromaticity helper functions. (This required adding Python bindings.)
  • Made it so that it's possible to read and write illegal multi-part files with different colorInteropIDs in each part, when in non-strict mode.
  • Added functionality to exrcheck to emit warnings based on improper color metadata.
  • Added more description of chromaticities in TechnicalIntroduction.rst.

After further study of exr2aces and the ImfAcesFile, I noticed that it doesn't even write acesImageContainerFlag, so it is just totally broken. My recommendation is that we remove exr2aces and deprecate ImfAcesFile.

And I realized that acesImageContainerFlag is not even a standard attribute, so I added that.

When overrideSharedAttributes is on, I decided to continue to have it modify mismatched values. IMHO, that is simply obeying what that option is supposed to do (and it is opt-in).

I've requested time on the TSC meeting agenda this Thursday to get feedback from the group about some of the questions I have.

Comment thread src/lib/OpenEXR/ImfChromaticities.cpp Outdated
{0.6400f, 0.3300f},
{0.3000f, 0.6000f},
{0.1500f, 0.0600f},
{0.3127f, 0.3290f}},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to do something like#define D65_WHITE {0.3127f, 0.3290f} and #define ACES_WHITE {0.32168f, 0.33767f} and use those macros in the list for the white points to make it easier to read the code?

// lin_rec709_scene lin_ap0_scene lin_ap1_scene
// lin_p3d65_scene lin_rec2020_scene lin_adobergb_scene
//
// See <https://github.com/AcademySoftwareFoundation/ColorInterop/blob/main/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment could mention this list is merely the ones the library itself defines, and that other values are colorInteropIDs are legal and should be expected by software reading OpenEXR files.

Is it possible this list would ever expand? If future releases could add extra spaces, it might be nice to expose the list through the API, (e.g. int getNumKnownInteropIDS(), char* getKnownInteropID(int index) ) then tools that use this functionality can present the list to a user without having to hardcode it

(Also I'd mention OpenColorIO here too, as a more complete approach for handling colorInteropIDs)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment, but I'm hesitant to expose the list of IDs to the API. For example, the IDs themselves are not intended to be user-facing strings.

Comment thread src/lib/OpenEXRUtil/ImfCheckFile.h Outdated
//
// Any previous contents of warnings are cleared. Warnings are only
// collected when runCoreCheck is false; the OpenEXRCore (C) API path does
// not report them.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tool that checks the colorspaces is good to have except I think exrcheck is the wrong place to put it. The main purpose of exrcheck is to assist with searching for vulnerabilities in the OpenEXR library, e.g. with files generated in a fuzzing process. It is a very bad idea to run it on untrusted files. It is also only installed if OPENEXR_INSTALL_DEVELOPER_TOOLS is set, so won't be generally available.

Maybe exrinfo (or exrheader) would be better places to report the colorspace of a file and any warnings?

Comment thread website/TechnicalIntroduction.rst Outdated
Rec.709 chromaticities even if the image is not actually that. In other cases,
applications report that the image is linear Rec.709, even if the chromaticities
is not present. This situation is one of the main reasons why the colorInteropID
is now the recommended way of identifying the color space in OpenEXR files.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could mention the colorInteropID to Chromatcities conversion as a path for migration to the new way

Is some comment about linear images merited here? OpenEXR says that images should be scene linear, but colorInteropID allows specification of a space with a nonlinear encoding.
To avoid heated discussions, this might simply say "since OpenEXR images are supposed to be linear, the colorInteropID should refer to a linear space (e.g. one that starts lin_) but the library does not require that to be the case"

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
@doug-walker

Copy link
Copy Markdown
Contributor Author

I've updated the PR to move the color metadata validation from exrcheck to exrinfo, per the TSC discussion. There are separate functions added as well for client programs to call.

I updated the description at the top of the PR based on the recent commits.

Signed-off-by: Doug Walker <doug.walker@autodesk.com>
@doug-walker

Copy link
Copy Markdown
Contributor Author

@lgritz , @zachlewis -- Do you think the new functions for validating the color space header metadata would be useful in OpenImageIO?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants