diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index ec2a8bb871..313b9c6316 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -654,6 +654,9 @@ class OCIOEXPORT Config */ void setInactiveColorSpaces(const char * inactiveColorSpaces); const char * getInactiveColorSpaces() const; + + /// Return true if the color space name is present in the inactive_colorspaces list. + bool isInactiveColorSpace(const char * colorspace) const noexcept; /** * \brief Return true if the specified color space is linear. @@ -722,6 +725,12 @@ class OCIOEXPORT Config * Return empty string if index is out of range. */ const char * getRoleColorSpace(int index) const; + /** + * \brief Get the color space name used for the specified role. + * + * Return an empty string if the role is not present + */ + const char * getRoleColorSpace(const char * roleName) const noexcept; /** * \defgroup Methods related to displays and views. diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index 69a1dd6c72..dba7d916cf 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -2918,6 +2918,22 @@ const char * Config::getInactiveColorSpaces() const return getImpl()->m_inactiveColorSpaceNamesConf.c_str(); } +bool Config::isInactiveColorSpace(const char * colorspace) const noexcept +{ + StringUtils::StringVec svec; + pystring::split(getImpl()->m_inactiveColorSpaceNamesConf.c_str(), svec, ", "); + + for (size_t i = 0; i < svec.size(); i++) + { + if (StringUtils::Compare(colorspace, svec.at(i))) + { + // Colorspace is inactive. + return true; + } + } + return false; +} + void Config::addColorSpace(const ConstColorSpaceRcPtr & original) { const std::string name(original->getName()); @@ -3357,6 +3373,12 @@ const char * Config::getRoleColorSpace(int index) const return LookupRole(getImpl()->m_roles, getRoleName(index)); } +const char * Config::getRoleColorSpace(const char * roleName) const noexcept +{ + if (!roleName || !roleName[0]) return ""; + return LookupRole(getImpl()->m_roles, roleName); +} + /////////////////////////////////////////////////////////////////////////// // // Named Transforms diff --git a/src/bindings/python/PyColorSpaceSet.cpp b/src/bindings/python/PyColorSpaceSet.cpp index adab62a1ff..d6c4831e23 100644 --- a/src/bindings/python/PyColorSpaceSet.cpp +++ b/src/bindings/python/PyColorSpaceSet.cpp @@ -80,6 +80,8 @@ void bindPyColorSpaceSet(py::module & m) }) .def("getColorSpace", &ColorSpaceSet::getColorSpace, "name"_a, DOC(ColorSpaceSet, getColorSpace)) + .def("hasColorSpace", &ColorSpaceSet::hasColorSpace, "name"_a, + DOC(ColorSpaceSet, hasColorSpace)) .def("addColorSpace", &ColorSpaceSet::addColorSpace, "colorSpace"_a, DOC(ColorSpaceSet, addColorSpace)) .def("addColorSpaces", &ColorSpaceSet::addColorSpaces, "colorSpaces"_a, diff --git a/src/bindings/python/PyConfig.cpp b/src/bindings/python/PyConfig.cpp index b90d6e8b5d..43185622a3 100644 --- a/src/bindings/python/PyConfig.cpp +++ b/src/bindings/python/PyConfig.cpp @@ -334,6 +334,8 @@ void bindPyConfig(py::module & m) DOC(Config, setInactiveColorSpaces)) .def("getInactiveColorSpaces", &Config::getInactiveColorSpaces, DOC(Config, getInactiveColorSpaces)) + .def("isInactiveColorSpace", &Config::isInactiveColorSpace, "colorspace"_a, + DOC(Config, isInactiveColorSpace)) // Roles .def("setRole", &Config::setRole, "role"_a, "colorSpaceName"_a, @@ -348,6 +350,10 @@ void bindPyConfig(py::module & m) { return RoleColorSpaceIterator(self); }) + .def("getRoleColorSpace", + (const char * (Config::*)(const char *) const) &Config::getRoleColorSpace, + "roleName"_a, + DOC(Config, getRoleColorSpace)) // Display/View Registration .def("addSharedView", diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 695625d6d9..eb42a7201b 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -312,6 +312,16 @@ OCIO_ADD_TEST(Config, roles) OCIO_CHECK_EQUAL(std::string(config->getRoleName(-4)), ""); OCIO_CHECK_EQUAL(std::string(config->getRoleColorSpace(-4)), ""); + + // Test existing roles. + OCIO_CHECK_EQUAL(std::string(config->getRoleColorSpace("scene_linear")), std::string("lnh")); + OCIO_CHECK_EQUAL(std::string(config->getRoleColorSpace("compositing_log")), std::string("lgh")); + + // Test a unknown role. + OCIO_CHECK_EQUAL(std::string(config->getRoleColorSpace("wrong_role")), std::string("")); + + // Test an empty input. + OCIO_CHECK_EQUAL(std::string(config->getRoleColorSpace("")), std::string("")); } OCIO_ADD_TEST(Config, required_roles_for_version_2_2) @@ -5650,6 +5660,35 @@ OCIO_ADD_TEST(Config, inactive_color_space) OCIO::COLORSPACE_ALL, 1)); } +OCIO_ADD_TEST(Config, inactive_colorspaces) +{ + // Using Built-in config to test the getInactiveColorSpace method. + const std::string cgConfigName = "cg-config-v1.0.0_aces-v1.3_ocio-v2.1"; + OCIO::ConstConfigRcPtr config; + + OCIO_CHECK_NO_THROW( + config = OCIO::Config::CreateFromBuiltinConfig(cgConfigName.c_str()) + ); + OCIO_REQUIRE_ASSERT(config); + + OCIO_CHECK_NO_THROW(config->validate()); + + { + // Test various combinations of input. + + OCIO_CHECK_EQUAL(config->isInactiveColorSpace(""), false); + OCIO_CHECK_EQUAL(config->isInactiveColorSpace("fake-colorspace-name"), false); + + // Test existing colorspaces from cg-config-v1.0.0_aces-v1.3_ocio-v2.1. + + // Colorspace exists and is active. + OCIO_CHECK_EQUAL(config->isInactiveColorSpace("Linear P3-D65"), false); + + // Colorspace exists and is inactive. + OCIO_CHECK_EQUAL(config->isInactiveColorSpace("Rec.1886 Rec.2020 - Display"), true); + } +} + OCIO_ADD_TEST(Config, inactive_color_space_precedence) { // The test demonstrates that an API request supersedes the env. variable and the diff --git a/tests/python/ConfigTest.py b/tests/python/ConfigTest.py index a687a5f0e2..ebc170c3df 100644 --- a/tests/python/ConfigTest.py +++ b/tests/python/ConfigTest.py @@ -1209,6 +1209,87 @@ def lutExists(filepath): processor = config.getProcessor("c1", "c2") processor.getDefaultCPUProcessor() + + def test_inactive_colorspaces(self): + config = OCIO.Config.CreateFromBuiltinConfig("cg-config-v1.0.0_aces-v1.3_ocio-v2.1") + config.validate() + + # Test various combinations of input. + + self.assertFalse(config.isInactiveColorSpace("")) + self.assertFalse(config.isInactiveColorSpace("fake-colorspace-name")) + + # Test existing colorspaces from cg-config-v1.0.0_aces-v1.3_ocio-v2.1. + + # Colorspace exists and is active. + self.assertFalse(config.isInactiveColorSpace("Linear P3-D65")) + + # Colorspace exists and is inactive. + self.assertTrue(config.isInactiveColorSpace("Rec.1886 Rec.2020 - Display")) + + def test_roles(self): + config = OCIO.Config.CreateFromBuiltinConfig("cg-config-v1.0.0_aces-v1.3_ocio-v2.1") + config.validate() + + # ***************************** + # Test getRoleNames interface. + # ***************************** + + rolesNames = config.getRoleNames() + + # Test the numbers of elements. + self.assertEqual(len(rolesNames), 9) + + # Test that the first element is an actual role. + self.assertTrue(config.hasRole(rolesNames[0])) + + # ************************* + # Test getRoles interface. + # ************************* + rolesAndColorspaces = config.getRoles() + + # Test the numbers of elements + self.assertEqual(len(rolesAndColorspaces), 9) + + # Test the first element. + colorspaces = config.getColorSpaces(None) + + # Test that the first element has an existing role and an existing colorspace. + self.assertTrue(config.hasRole(rolesAndColorspaces[0][0])) + self.assertTrue(colorspaces.hasColorSpace(rolesAndColorspaces[0][1])) + + # ********************** + # Test role resolutions + # ********************** + + self.assertEqual(config.getRoleColorSpace("data"), "Raw") + self.assertEqual(config.getRoleColorSpace("cie_xyz_d65_interchange"), "CIE-XYZ-D65") + + # Test a unknown role. + self.assertEqual(config.getRoleColorSpace("wrong_role"), "") + + # Test an empty input. + self.assertEqual(config.getRoleColorSpace(""), "") + + # ********************** + # Test role assignation + # ********************** + + # Test that empty role name returns false. + self.assertFalse(config.hasRole("")) + + # Test if color_picking role is present. + self.assertTrue(config.hasRole("color_picking")) + + # Test the original value of the role color_picking. + self.assertEqual(config.getRoleColorSpace("color_picking"), "sRGB - Texture") + + # Change the color space assigned to the role color_picking. + config.setRole(OCIO.ROLE_COLOR_PICKING, "ACEScct") + + # Test the new value of the role color_picking. + self.assertEqual(config.getRoleColorSpace("color_picking"), "ACEScct") + class ConfigVirtualWithActiveDisplayTest(unittest.TestCase): def setUp(self): self.cfg_active_display = OCIO.Config.CreateFromStream(