diff --git a/src/include/OpenImageIO/color.h b/src/include/OpenImageIO/color.h index 10dd04ac0e..8cdb85daf2 100644 --- a/src/include/OpenImageIO/color.h +++ b/src/include/OpenImageIO/color.h @@ -175,6 +175,9 @@ class OIIO_API ColorConfig { /// will return false if it's not sure. bool isColorSpaceLinear(string_view name) const; + /// Is the color space non-color-managed "data"? + bool isData(string_view name) const; + /// Retrieve the full list of aliases for the named color space. std::vector getAliases(string_view color_space) const; diff --git a/src/libOpenImageIO/color_ocio.cpp b/src/libOpenImageIO/color_ocio.cpp index badfb7c966..5ee91303ed 100644 --- a/src/libOpenImageIO/color_ocio.cpp +++ b/src/libOpenImageIO/color_ocio.cpp @@ -165,6 +165,7 @@ struct CSInfo { is_lin_srgb = 8, // sRGB/Rec709 primaries, linear response is_ACEScg = 16, // ACEScg is_Rec709 = 32, // Rec709 primaries and transfer function + is_data = 64, // Non-color-managed data is_known = is_srgb | is_lin_srgb | is_ACEScg | is_Rec709 }; int m_flags = 0; @@ -341,6 +342,8 @@ class ColorConfig::Impl { bool isColorSpaceLinear(string_view name) const; + bool isData(string_view name) const; + private: // Return the CSInfo flags for the given color space name int flags(string_view name) @@ -607,6 +610,9 @@ ColorConfig::Impl::classify_by_name(CSInfo& cs) ACEScg_alias); } else if (Strutil::iequals(cs.name, "Rec709")) { cs.setflag(CSInfo::is_Rec709, Rec709_alias); + } else if (config_ + && Strutil::iequals(cs.name, config_->getCanonicalName("data"))) { + cs.setflag(CSInfo::is_data); } #ifdef OIIO_SITE_spi // Ugly SPI-specific hacks, so sorry @@ -619,6 +625,9 @@ ColorConfig::Impl::classify_by_name(CSInfo& cs) } else if (cs.name == "srgblnf" || cs.name == "srgblnh" || cs.name == "srgbln16" || cs.name == "srgbln8") { cs.setflag(CSInfo::is_lin_srgb, lin_srgb_alias); + } else if (Strutil::starts_with(cs.name, "nc")) { + cs.setflag(CSInfo::is_data); + DBG("Classifying {} as data based on SPI name\n", cs.name); } #endif @@ -649,6 +658,10 @@ ColorConfig::Impl::classify_by_conversions(CSInfo& cs) if (isColorSpaceLinear(cs.name)) cs.setflag(CSInfo::is_linear_response); + if (cs.ocio_cs && cs.ocio_cs->isData()) { + cs.setflag(CSInfo::is_data); + DBG("Classifying {} as data isData() [1]\n", cs.name); + } // If the name didn't already tell us what it is, and we have a new enough // OCIO that has built-in configs, test whether this color space is @@ -683,7 +696,12 @@ ColorConfig::Impl::classify_by_conversions(CSInfo& cs) cs.setflag(CSInfo::is_ACEScg | CSInfo::is_linear_response, ACEScg_alias); } - } catch (...) { + if (cs.ocio_cs->isData()) { + cs.setflag(CSInfo::is_data); + DBG("Classifying {} as data isData() [2]\n", cs.name); + } + } catch (OCIO::Exception& e) { + DBG("OCIO exception in classify_by_conversions: {}", e.what()); } } @@ -1067,6 +1085,25 @@ ColorConfig::Impl::isColorSpaceLinear(string_view name) const +bool +ColorConfig::isData(string_view name) const +{ + return getImpl()->isData(name); +} + + + +bool +ColorConfig::Impl::isData(string_view name) const +{ + if (const CSInfo* cs = find(name)) { + return cs->flags() & CSInfo::is_data; + } + return false; +} + + + std::vector ColorConfig::getAliases(string_view color_space) const { diff --git a/src/python/py_colorconfig.cpp b/src/python/py_colorconfig.cpp index 35f8e304e8..075c1f3e84 100644 --- a/src/python/py_colorconfig.cpp +++ b/src/python/py_colorconfig.cpp @@ -123,6 +123,18 @@ declare_colorconfig(py::module& m) [](const ColorConfig& self, const std::string& named_transform) { return self.getNamedTransformAliases(named_transform); }) + .def( + "isColorSpaceLinear", + [](const ColorConfig& self, const std::string& name) { + return self.isColorSpaceLinear(name); + }, + "name"_a) + .def( + "isData", + [](const ColorConfig& self, const std::string& name) { + return self.isData(name); + }, + "name"_a) .def( "getColorSpaceFromFilepath", [](const ColorConfig& self, const std::string& filepath) { diff --git a/testsuite/python-colorconfig/ref/out-ocio23.txt b/testsuite/python-colorconfig/ref/out-ocio23.txt index 1badffcb7f..96211f623a 100644 --- a/testsuite/python-colorconfig/ref/out-ocio23.txt +++ b/testsuite/python-colorconfig/ref/out-ocio23.txt @@ -31,6 +31,10 @@ get_color_interop_id('lin_srgb') = lin_rec709_scene get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene get_cicp('pq_rec2020_display') = [9, 16, 9, 1] get_cicp('unknown_interop_id') = None +isColorSpaceLinear('scene_linear') = True +isColorSpaceLinear('srgb') = False +isData('scene_linear') = False +isData('Raw') = True Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/ref/out-ocio24.txt b/testsuite/python-colorconfig/ref/out-ocio24.txt index 2882859127..d962047b60 100644 --- a/testsuite/python-colorconfig/ref/out-ocio24.txt +++ b/testsuite/python-colorconfig/ref/out-ocio24.txt @@ -31,6 +31,10 @@ get_color_interop_id('lin_srgb') = lin_rec709_scene get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene get_cicp('pq_rec2020_display') = [9, 16, 9, 1] get_cicp('unknown_interop_id') = None +isColorSpaceLinear('scene_linear') = True +isColorSpaceLinear('srgb') = False +isData('scene_linear') = False +isData('Raw') = True Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/ref/out-ocio25.txt b/testsuite/python-colorconfig/ref/out-ocio25.txt index b12d8ce08d..72293a8d8b 100644 --- a/testsuite/python-colorconfig/ref/out-ocio25.txt +++ b/testsuite/python-colorconfig/ref/out-ocio25.txt @@ -31,6 +31,10 @@ get_color_interop_id('lin_srgb') = lin_rec709_scene get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene get_cicp('pq_rec2020_display') = [9, 16, 9, 1] get_cicp('unknown_interop_id') = None +isColorSpaceLinear('scene_linear') = True +isColorSpaceLinear('srgb') = False +isData('scene_linear') = False +isData('Raw') = True Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/ref/out.txt b/testsuite/python-colorconfig/ref/out.txt index cb9a3dddfc..25fb8279e5 100644 --- a/testsuite/python-colorconfig/ref/out.txt +++ b/testsuite/python-colorconfig/ref/out.txt @@ -31,6 +31,10 @@ get_color_interop_id('lin_srgb') = lin_rec709_scene get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene get_cicp('pq_rec2020_display') = [9, 16, 9, 1] get_cicp('unknown_interop_id') = None +isColorSpaceLinear('scene_linear') = True +isColorSpaceLinear('srgb') = False +isData('scene_linear') = False +isData('Raw') = True Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/src/test_colorconfig.py b/testsuite/python-colorconfig/src/test_colorconfig.py index 766e6a037b..c45881038c 100755 --- a/testsuite/python-colorconfig/src/test_colorconfig.py +++ b/testsuite/python-colorconfig/src/test_colorconfig.py @@ -53,6 +53,10 @@ print ("get_color_interop_id([1, 13, 1, 1]) = ", config.get_color_interop_id([1, 13, 1, 1])) print ("get_cicp('pq_rec2020_display') = ", config.get_cicp("pq_rec2020_display")) print ("get_cicp('unknown_interop_id') = ", config.get_cicp("unknown_interop_id")) + print ("isColorSpaceLinear('scene_linear') = ", config.isColorSpaceLinear('scene_linear')) + print ("isColorSpaceLinear('srgb') = ", config.isColorSpaceLinear('srgb')) + print ("isData('scene_linear') = ", config.isData('scene_linear')) + print ("isData('Raw') = ", config.isData('Raw')) print ("") config = oiio.ColorConfig(str(TEST_CONFIG_PATH))