Skip to content

Commit 5ef7af8

Browse files
lgritzzachlewis
authored andcommitted
exr: Don't assume unlabeled OpenEXR files are lin_rec709 (#4840)
New logic for reading OpenEXR files: 1. Recognize "acesImageContainerFlag" as always being lin_ap0_scene. 2. If the new colorInteropID is present in the metadata, that's the single source of truth about color space. 3. Otherwise, leave it blank, don't make any assumptions about color space. It was a mistake for OIIO 3.0 to assume that completely unlabeled openexr files are lin_rec709. --------- Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent ee77a1a commit 5ef7af8

27 files changed

Lines changed: 25 additions & 147 deletions

File tree

src/openexr.imageio/exr_pvt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#include <OpenImageIO/Imath.h>
9+
#include <OpenImageIO/color.h>
910
#include <OpenImageIO/filesystem.h>
1011
#include <OpenImageIO/imageio.h>
1112
#include <OpenImageIO/platform.h>
@@ -228,6 +229,7 @@ class OpenEXRInput final : public ImageInput {
228229
int m_nsubimages; ///< How many subimages are there?
229230
int m_miplevel; ///< What MIP level are we looking at?
230231
std::vector<float> m_missingcolor; ///< Color for missing tile/scanline
232+
std::string m_filename; // filename, if known
231233

232234
void init()
233235
{
@@ -243,6 +245,7 @@ class OpenEXRInput final : public ImageInput {
243245
m_io = nullptr;
244246
m_local_io.reset();
245247
m_missingcolor.clear();
248+
m_filename.clear();
246249
}
247250

248251
bool read_native_scanlines_individually(int subimage, int miplevel,

src/openexr.imageio/exrinput.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ OpenEXRInput::open(const std::string& name, ImageSpec& newspec,
240240

241241
// Check any other configuration hints
242242

243+
m_filename = name;
244+
243245
// "missingcolor" gives fill color for missing scanlines or tiles.
244246
if (const ParamValue* m = config.find_attribute("oiio:missingcolor")) {
245247
if (m->type().basetype == TypeDesc::STRING) {
@@ -392,14 +394,6 @@ OpenEXRInput::PartInfo::parse_header(OpenEXRInput* in,
392394

393395
spec.deep = Strutil::istarts_with(header->type(), "deep");
394396

395-
// Unless otherwise specified, exr files are assumed to be linear Rec709
396-
// if the channels appear to be R, G, B. I know this suspect, but I'm
397-
// betting that this heuristic will guess the right thing that users want
398-
// more often than if we pretending we have no idea what the color space
399-
// is.
400-
if (pvt::channels_are_rgb(spec))
401-
spec.set_colorspace("lin_rec709");
402-
403397
if (levelmode != Imf::ONE_LEVEL)
404398
spec.attribute("openexr:roundingmode", roundingmode);
405399

@@ -674,6 +668,13 @@ OpenEXRInput::PartInfo::parse_header(OpenEXRInput* in,
674668

675669
spec.attribute("oiio:subimages", in->m_nsubimages);
676670

671+
// Try to figure out the color space for some unambiguous cases
672+
if (spec.get_int_attribute("acesImageContainerFlag") == 1) {
673+
spec.set_colorspace("lin_ap0_scene");
674+
} else if (auto c = spec.find_attribute("colorInteropID", TypeString)) {
675+
spec.set_colorspace(c->get_ustring());
676+
}
677+
677678
// Squash some problematic texture metadata if we suspect it's wrong
678679
pvt::check_texture_metadata_sanity(spec);
679680

src/openexr.imageio/exrinput_c.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <OpenEXR/openexr.h>
2020

2121
#include "imageio_pvt.h"
22+
#include <OpenImageIO/color.h>
2223
#include <OpenImageIO/dassert.h>
2324
#include <OpenImageIO/deepdata.h>
2425
#include <OpenImageIO/filesystem.h>
@@ -208,6 +209,7 @@ class OpenEXRCoreInput final : public ImageInput {
208209
std::unique_ptr<Filesystem::IOProxy> m_local_io;
209210
int m_nsubimages; ///< How many subimages are there?
210211
std::vector<float> m_missingcolor; ///< Color for missing tile/scanline
212+
std::string m_filename; // filename, if known
211213

212214
void init()
213215
{
@@ -216,6 +218,7 @@ class OpenEXRCoreInput final : public ImageInput {
216218
m_userdata.m_io = nullptr;
217219
m_local_io.reset();
218220
m_missingcolor.clear();
221+
m_filename.clear();
219222
}
220223

221224
bool valid_file(const std::string& filename, Filesystem::IOProxy* io) const;
@@ -358,6 +361,8 @@ OpenEXRCoreInput::open(const std::string& name, ImageSpec& newspec,
358361

359362
// Check any other configuration hints
360363

364+
m_filename = name;
365+
361366
// "missingcolor" gives fill color for missing scanlines or tiles.
362367
if (const ParamValue* m = config.find_attribute("oiio:missingcolor")) {
363368
if (m->type().basetype == TypeDesc::STRING) {
@@ -527,14 +532,6 @@ OpenEXRCoreInput::PartInfo::parse_header(OpenEXRCoreInput* in,
527532
spec.deep = (storage == EXR_STORAGE_DEEP_TILED
528533
|| storage == EXR_STORAGE_DEEP_SCANLINE);
529534

530-
// Unless otherwise specified, exr files are assumed to be linear Rec709
531-
// if the channels appear to be R, G, B. I know this suspect, but I'm
532-
// betting that this heuristic will guess the right thing that users want
533-
// more often than if we pretending we have no idea what the color space
534-
// is.
535-
if (pvt::channels_are_rgb(spec))
536-
spec.set_colorspace("lin_rec709");
537-
538535
if (levelmode != EXR_TILE_ONE_LEVEL)
539536
spec.attribute("openexr:roundingmode", (int)roundingmode);
540537

@@ -776,6 +773,13 @@ OpenEXRCoreInput::PartInfo::parse_header(OpenEXRCoreInput* in,
776773

777774
spec.attribute("oiio:subimages", in->m_nsubimages);
778775

776+
// Try to figure out the color space for some unambiguous cases
777+
if (spec.get_int_attribute("acesImageContainerFlag") == 1) {
778+
spec.set_colorspace("lin_ap0_scene");
779+
} else if (auto c = spec.find_attribute("colorInteropID", TypeString)) {
780+
spec.set_colorspace(c->get_ustring());
781+
}
782+
779783
// Squash some problematic texture metadata if we suspect it's wrong
780784
pvt::check_texture_metadata_sanity(spec);
781785

testsuite/dup-channels/ref/out.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ out.exr : 64 x 64, 6 channel, half openexr
66
PixelAspectRatio: 1
77
screenWindowCenter: 0, 0
88
screenWindowWidth: 1
9-
oiio:ColorSpace: "lin_rec709"
109
oiio:subimages: 1
1110
openexr:lineOrder: "increasingY"
1211
Reading out2.exr
@@ -18,7 +17,6 @@ out2.exr : 64 x 64, 6 channel, half openexr
1817
PixelAspectRatio: 1
1918
screenWindowCenter: 0, 0
2019
screenWindowWidth: 1
21-
oiio:ColorSpace: "lin_rec709"
2220
oiio:subimagename: "Aimg"
2321
oiio:subimages: 1
2422
openexr:chunkCount: 4

testsuite/iinfo/ref/out-fmt6.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ src/tiny-az.exr : screenWindowCenter: 0, 0
147147
src/tiny-az.exr : screenWindowWidth: 1
148148
src/tiny-az.exr : Software: "OpenImageIO 2.5.0.0spi : oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
149149
src/tiny-az.exr : Exif:ImageHistory: "oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
150-
src/tiny-az.exr : oiio:ColorSpace: "lin_rec709"
151150
src/tiny-az.exr : oiio:subimages: 1
152151
src/tiny-az.exr : openexr:lineOrder: "increasingY"
153152
src/tiny-az.exr : Stats Min: 0.250000 0.500000 0.750000 (float)
@@ -175,7 +174,6 @@ src/tiny-az.exr : 4 x 4, 3 channel, float openexr
175174
screenWindowWidth: 1
176175
Software: "OpenImageIO 2.5.0.0spi : oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
177176
Exif:ImageHistory: "oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
178-
oiio:ColorSpace: "lin_rec709"
179177
oiio:subimages: 1
180178
openexr:lineOrder: "increasingY"
181179
Pixel (2, 2): 0.250000000 0.500000000 0.750000000

testsuite/iinfo/ref/out.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ src/tiny-az.exr : screenWindowCenter: 0, 0
147147
src/tiny-az.exr : screenWindowWidth: 1
148148
src/tiny-az.exr : Software: "OpenImageIO 2.5.0.0spi : oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
149149
src/tiny-az.exr : Exif:ImageHistory: "oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
150-
src/tiny-az.exr : oiio:ColorSpace: "lin_rec709"
151150
src/tiny-az.exr : oiio:subimages: 1
152151
src/tiny-az.exr : openexr:lineOrder: "increasingY"
153152
src/tiny-az.exr : Stats Min: 0.250000 0.500000 0.750000 (float)
@@ -175,7 +174,6 @@ src/tiny-az.exr : 4 x 4, 3 channel, float openexr
175174
screenWindowWidth: 1
176175
Software: "OpenImageIO 2.5.0.0spi : oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
177176
Exif:ImageHistory: "oiiotool -pattern constant:color=0.25,0.5,0.75 4x4 3 --origin +2+2 --fullsize 20x20+1+1 -o tiny-az.exr"
178-
oiio:ColorSpace: "lin_rec709"
179177
oiio:subimages: 1
180178
openexr:lineOrder: "increasingY"
181179
Pixel (2, 2): 0.250000000 0.500000000 0.750000000

testsuite/maketx/ref/out-macarm.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ nan.exr : 64 x 64, 3 channel, half openexr
337337
textureformat: "Plain Texture"
338338
wrapmodes: "black,black"
339339
oiio:AverageColor: "0.5,0.5,0.5"
340-
oiio:ColorSpace: "lin_rec709"
341340
oiio:SHA-1: "44B96A7C3AFBF8D7621E7C6453266E5DD1962D36"
342341
oiio:subimages: 1
343342
openexr:levelmode: 0
@@ -366,7 +365,6 @@ checker-exr.pdq : 128 x 128, 4 channel, half openexr
366365
textureformat: "Plain Texture"
367366
wrapmodes: "black,black"
368367
oiio:AverageColor: "0.5,0.5,0.5,1"
369-
oiio:ColorSpace: "lin_rec709"
370368
oiio:SHA-1: "D924CA144A02479D1507F5910F5FC8F51EF78765"
371369
oiio:subimages: 1
372370
openexr:lineOrder: "increasingY"

testsuite/maketx/ref/out.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ nan.exr : 64 x 64, 3 channel, half openexr
337337
textureformat: "Plain Texture"
338338
wrapmodes: "black,black"
339339
oiio:AverageColor: "0.5,0.5,0.5"
340-
oiio:ColorSpace: "lin_rec709"
341340
oiio:SHA-1: "44B96A7C3AFBF8D7621E7C6453266E5DD1962D36"
342341
oiio:subimages: 1
343342
openexr:levelmode: 0
@@ -366,7 +365,6 @@ checker-exr.pdq : 128 x 128, 4 channel, half openexr
366365
textureformat: "Plain Texture"
367366
wrapmodes: "black,black"
368367
oiio:AverageColor: "0.5,0.5,0.5,1"
369-
oiio:ColorSpace: "lin_rec709"
370368
oiio:SHA-1: "D924CA144A02479D1507F5910F5FC8F51EF78765"
371369
oiio:subimages: 1
372370
openexr:lineOrder: "increasingY"

testsuite/oiiotool-attribs/ref/out-jpeg9d.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ attrib2.exr : 64 x 64, 3 channel, half openexr
8686
PixelAspectRatio: 1
8787
screenWindowCenter: 0, 0
8888
screenWindowWidth: 1
89-
oiio:ColorSpace: "lin_rec709"
9089
oiio:subimagename: "subimage00"
9190
oiio:subimages: 2
9291
openexr:chunkCount: 4
@@ -100,7 +99,6 @@ attrib2.exr : 64 x 64, 3 channel, half openexr
10099
PixelAspectRatio: 1
101100
screenWindowCenter: 0, 0
102101
screenWindowWidth: 1
103-
oiio:ColorSpace: "lin_rec709"
104102
oiio:subimagename: "subimage01"
105103
oiio:subimages: 2
106104
openexr:chunkCount: 4
@@ -116,7 +114,6 @@ attrib0.exr : 64 x 64, 3 channel, half openexr
116114
PixelAspectRatio: 1
117115
screenWindowCenter: 0, 0
118116
screenWindowWidth: 1
119-
oiio:ColorSpace: "lin_rec709"
120117
oiio:subimagename: "subimage00"
121118
oiio:subimages: 2
122119
openexr:chunkCount: 4
@@ -129,7 +126,6 @@ attrib0.exr : 64 x 64, 3 channel, half openexr
129126
PixelAspectRatio: 1
130127
screenWindowCenter: 0, 0
131128
screenWindowWidth: 1
132-
oiio:ColorSpace: "lin_rec709"
133129
oiio:subimagename: "subimage01"
134130
oiio:subimages: 2
135131
openexr:chunkCount: 4

testsuite/oiiotool-attribs/ref/out.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ attrib2.exr : 64 x 64, 3 channel, half openexr
8686
PixelAspectRatio: 1
8787
screenWindowCenter: 0, 0
8888
screenWindowWidth: 1
89-
oiio:ColorSpace: "lin_rec709"
9089
oiio:subimagename: "subimage00"
9190
oiio:subimages: 2
9291
openexr:chunkCount: 4
@@ -100,7 +99,6 @@ attrib2.exr : 64 x 64, 3 channel, half openexr
10099
PixelAspectRatio: 1
101100
screenWindowCenter: 0, 0
102101
screenWindowWidth: 1
103-
oiio:ColorSpace: "lin_rec709"
104102
oiio:subimagename: "subimage01"
105103
oiio:subimages: 2
106104
openexr:chunkCount: 4
@@ -116,7 +114,6 @@ attrib0.exr : 64 x 64, 3 channel, half openexr
116114
PixelAspectRatio: 1
117115
screenWindowCenter: 0, 0
118116
screenWindowWidth: 1
119-
oiio:ColorSpace: "lin_rec709"
120117
oiio:subimagename: "subimage00"
121118
oiio:subimages: 2
122119
openexr:chunkCount: 4
@@ -129,7 +126,6 @@ attrib0.exr : 64 x 64, 3 channel, half openexr
129126
PixelAspectRatio: 1
130127
screenWindowCenter: 0, 0
131128
screenWindowWidth: 1
132-
oiio:ColorSpace: "lin_rec709"
133129
oiio:subimagename: "subimage01"
134130
oiio:subimages: 2
135131
openexr:chunkCount: 4

0 commit comments

Comments
 (0)