From 193e33afe5732d5728b799e1279d9f8642e264bc Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Sun, 25 May 2025 21:17:32 -0700 Subject: [PATCH 01/16] - Added the getInteropID() field. Unit tests need cleanup Signed-off-by: cuneyt.ozdas --- include/OpenColorIO/OpenColorIO.h | 13 ++ src/OpenColorIO/ColorSpace.cpp | 12 ++ src/OpenColorIO/OCIOYaml.cpp | 15 ++- src/bindings/java/JNIColorSpace.cpp | 18 +++ .../java/org/OpenColorIO/ColorSpace.java | 2 + src/bindings/python/PyColorSpace.cpp | 4 + tests/cpu/ColorSpace_tests.cpp | 111 ++++++++++++++++++ 7 files changed, 174 insertions(+), 1 deletion(-) diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index b7183ce77f..04b090f611 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -1915,6 +1915,19 @@ class OCIOEXPORT ColorSpace const char * getDescription() const noexcept; void setDescription(const char * description); + /** + * \brief Get/Set the interop ID for the color space. + * + * The interop ID is a standardized identifier for commonly used color spaces, + * particularly for texture assets. These IDs enable consistent color space + * handling across different applications and pipelines. + * + * These IDs are defined by the Academy Software Foundation's ColorInterop project + * to standardize color space naming across the industry. + */ + const char * getInteropID() const noexcept; + void setInteropID(const char * interopID); + BitDepth getBitDepth() const noexcept; void setBitDepth(BitDepth bitDepth); diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index 4b7ecb25d0..bee4fef849 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -24,6 +24,7 @@ class ColorSpace::Impl std::string m_equalityGroup; std::string m_description; std::string m_encoding; + std::string m_interopID; StringUtils::StringVec m_aliases; BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN }; @@ -62,6 +63,7 @@ class ColorSpace::Impl m_equalityGroup = rhs.m_equalityGroup; m_description = rhs.m_description; m_encoding = rhs.m_encoding; + m_interopID = rhs.m_interopID; m_bitDepth = rhs.m_bitDepth; m_isData = rhs.m_isData; m_referenceSpaceType = rhs.m_referenceSpaceType; @@ -218,6 +220,16 @@ void ColorSpace::setDescription(const char * description) getImpl()->m_description = description; } +const char * ColorSpace::getInteropID() const noexcept +{ + return getImpl()->m_interopID.c_str(); +} + +void ColorSpace::setInteropID(const char * interopID) +{ + getImpl()->m_interopID = interopID; +} + BitDepth ColorSpace::getBitDepth() const noexcept { return getImpl()->m_bitDepth; diff --git a/src/OpenColorIO/OCIOYaml.cpp b/src/OpenColorIO/OCIOYaml.cpp index b1cee18982..bfd6c8405f 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -3193,7 +3193,12 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major load(iter->second, stringval); cs->setName(stringval.c_str()); } - else if (key == "aliases") + else if(key == "interop_id") + { + load(iter->second, stringval); + cs->setInteropID(stringval.c_str()); + } + else if(key == "aliases") { StringUtils::StringVec aliases; load(iter->second, aliases); @@ -3323,6 +3328,14 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int major } out << YAML::Flow << YAML::Value << aliases; } + + const std::string interopID{ cs->getInteropID() }; + if (!interopID.empty()) + { + out << YAML::Key << "interop_id"; + out << YAML::Value << interopID; + } + out << YAML::Key << "family" << YAML::Value << cs->getFamily(); out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup(); out << YAML::Key << "bitdepth" << YAML::Value; diff --git a/src/bindings/java/JNIColorSpace.cpp b/src/bindings/java/JNIColorSpace.cpp index 423da186cc..028792d0ab 100644 --- a/src/bindings/java/JNIColorSpace.cpp +++ b/src/bindings/java/JNIColorSpace.cpp @@ -109,6 +109,24 @@ Java_org_OpenColorIO_ColorSpace_setDescription(JNIEnv * env, jobject self, jstri OCIO_JNITRY_EXIT() } +JNIEXPORT jstring JNICALL +Java_org_OpenColorIO_ColorSpace_getInteropID(JNIEnv * env, jobject self) +{ + OCIO_JNITRY_ENTER() + ConstColorSpaceRcPtr col = GetConstJOCIO(env, self); + return env->NewStringUTF(col->getInteropID()); + OCIO_JNITRY_EXIT(NULL) +} + +JNIEXPORT void JNICALL +Java_org_OpenColorIO_ColorSpace_setInteropID(JNIEnv * env, jobject self, jstring interopID) +{ + OCIO_JNITRY_ENTER() + ColorSpaceRcPtr col = GetEditableJOCIO(env, self); + col->setInteropID(GetJStringValue(env, interopID)()); + OCIO_JNITRY_EXIT() +} + JNIEXPORT jobject JNICALL Java_org_OpenColorIO_ColorSpace_getBitDepth(JNIEnv * env, jobject self) { diff --git a/src/bindings/java/org/OpenColorIO/ColorSpace.java b/src/bindings/java/org/OpenColorIO/ColorSpace.java index 9950bee93d..cc370d911a 100644 --- a/src/bindings/java/org/OpenColorIO/ColorSpace.java +++ b/src/bindings/java/org/OpenColorIO/ColorSpace.java @@ -20,6 +20,8 @@ public class ColorSpace extends LoadLibrary public native void setEqualityGroup(String equalityGroup); public native String getDescription(); public native void setDescription(String description); + public native String getInteropID(); + public native void setInteropID(String interopID); public native BitDepth getBitDepth(); public native void setBitDepth(BitDepth bitDepth); public native boolean isData(); diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index 6827943bc0..933700bd99 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -193,6 +193,10 @@ void bindPyColorSpace(py::module & m) DOC(ColorSpace, getDescription)) .def("setDescription", &ColorSpace::setDescription, "description"_a, DOC(ColorSpace, setDescription)) + .def("getInteropID", &ColorSpace::getInteropID, + DOC(ColorSpace, getInteropID)) + .def("setInteropID", &ColorSpace::setInteropID, "interopID"_a, + DOC(ColorSpace, setInteropID)) .def("getBitDepth", &ColorSpace::getBitDepth, DOC(ColorSpace, getBitDepth)) .def("setBitDepth", &ColorSpace::setBitDepth, "bitDepth"_a, diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 54521be171..95db7f3924 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -619,6 +619,97 @@ active_views: [] OCIO_CHECK_EQUAL(cfgRes, os.str()); } +/* + { + constexpr char End[]{ R"(colorspaces: + - ! + name: raw + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + interop_id: srgb_texture + isdata: true + allocation: uniform + + - ! + name: raw2 + family: raw + equalitygroup: "" + bitdepth: 32f + description: | + One line. + + Other line. + interop_id: acescg_texture + isdata: true + allocation: uniform +)" }; + std::string cfgString{ Start }; + cfgString += End; + + // Load config. + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_REQUIRE_ASSERT(config); + OCIO_CHECK_NO_THROW(config->validate()); + + // Check colorspace. + + OCIO_CHECK_EQUAL(config->getNumColorSpaces(), 2); + OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(config->getColorSpaceNameByIndex(0)); + OCIO_REQUIRE_ASSERT(cs); + // Description has no trailing \n. + OCIO_CHECK_EQUAL(std::string(cs->getDescription()), "Some text."); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), "srgb_texture"); + + cs = config->getColorSpace(config->getColorSpaceNameByIndex(1)); + OCIO_REQUIRE_ASSERT(cs); + // Description has no trailing \n. + OCIO_CHECK_EQUAL(std::string(cs->getDescription()), "One line.\n\nOther line."); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), "acescg_texture"); + + // Save and compare output with input. + + std::ostringstream os; + os << *config; + + OCIO_CHECK_EQUAL(cfgString, os.str()); + } + + // Test the serialize/deserialize process using interop_id. + auto cfg = OCIO::Config::Create(); + auto cs = OCIO::ColorSpace::Create(); + cs->setName("testing"); + const std::string interopID{ "linear_srgb" }; + cs->setInteropID(interopID.c_str()); + cfg->addColorSpace(cs); + + // Serialize the Config. + std::ostringstream os; + cfg->serialize(os); + + // Deserialize and compare. + std::istringstream is; + is.str(os.str()); + auto cfg2 = OCIO::Config::CreateFromStream(is); + OCIO_CHECK_EQUAL(cfg2->getNumColorSpaces(), 1); + auto cs2 = cfg2->getColorSpace("testing"); + OCIO_CHECK_EQUAL(std::string(cs2->getInteropID()), interopID); + + // Test another valid interop ID. + cs->setInteropID("linear_display_p3"); + cfg->addColorSpace(cs); + os.str(""); + cfg->serialize(os); + is.str(os.str()); + cfg2 = OCIO::Config::CreateFromStream(is); + cs2 = cfg2->getColorSpace("testing"); + OCIO_CHECK_EQUAL(std::string(cs2->getInteropID()), "linear_display_p3"); + */ } OCIO_ADD_TEST(Config, use_alias) @@ -1702,3 +1793,23 @@ inactive_colorspaces: [scene-linear Rec.709-sRGB, ACES2065-1] ); } } + +/* +OCIO_ADD_TEST(ColorSpace, interop_id) +{ + auto cs = OCIO::ColorSpace::Create(); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); + + const std::string interopID{ "srgb_texture" }; + cs->setInteropID(interopID.c_str()); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), interopID); + + // Test another valid interop ID + const std::string interopID2{ "acescg_texture" }; + cs->setInteropID(interopID2.c_str()); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), interopID2); + + cs->setInteropID(nullptr); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); +} +*/ \ No newline at end of file From 89a41621c8123469360737bcf3258e9c3bf143b8 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Tue, 27 May 2025 21:57:39 -0700 Subject: [PATCH 02/16] - Adding AMF transform ID, phyton bindings, java bindings, unit test - adding python docs for AMF transform IDs and interop ID. - With the newly added unit tests discovered crasher issues some of the "char *" taking functions and fixed the crashers - Also hardened Platform::Strcasecmp() and Platoform::Strncasecmp() against nullptr. Signed-off-by: cuneyt.ozdas --- .../frozen/pyopencolorio_colorspace.rst | 26 +++++ include/OpenColorIO/OpenColorIO.h | 16 ++- src/OpenColorIO/Baker.cpp | 12 +-- src/OpenColorIO/ColorSpace.cpp | 22 ++++- src/OpenColorIO/Context.cpp | 2 +- src/OpenColorIO/Look.cpp | 6 +- src/OpenColorIO/OCIOYaml.cpp | 33 +++++-- src/OpenColorIO/Platform.cpp | 10 ++ src/OpenColorIO/ViewTransform.cpp | 6 +- src/bindings/java/JNIColorSpace.cpp | 18 ++++ .../java/org/OpenColorIO/ColorSpace.java | 2 + src/bindings/python/PyColorSpace.cpp | 4 + tests/cpu/ColorSpace_tests.cpp | 97 +++++++++++++++++-- 13 files changed, 214 insertions(+), 40 deletions(-) diff --git a/docs/api/python/frozen/pyopencolorio_colorspace.rst b/docs/api/python/frozen/pyopencolorio_colorspace.rst index 5a6adf8d99..13bc65538f 100644 --- a/docs/api/python/frozen/pyopencolorio_colorspace.rst +++ b/docs/api/python/frozen/pyopencolorio_colorspace.rst @@ -214,6 +214,32 @@ Specify the transform for the appropriate direction. Setting the transform to null will clear it. + .. py:method:: ColorSpace.getInteropID(self: PyOpenColorIO.ColorSpace) -> str + :module: PyOpenColorIO + + + .. py:method:: ColorSpace.setInteropID(self: PyOpenColorIO.ColorSpace, interopID: str) -> None + :module: PyOpenColorIO + + + .. py:method:: ColorSpace.getAmfTransformIDs(self: PyOpenColorIO.ColorSpace) -> str + :module: PyOpenColorIO + + Get the AMF transform IDs for the color space. + + The AMF transform IDs are used to identify specific transforms in the ACES Metadata File. + Multiple transform IDs can be specified in a newline-separated string. + + + .. py:method:: ColorSpace.setAmfTransformIDs(self: PyOpenColorIO.ColorSpace, amfTransformIDs: str) -> None + :module: PyOpenColorIO + + Set the AMF transform IDs for the color space. + + Args: + amfTransformIDs (str): A newline-separated string of AMF transform IDs. + + .. py:class:: ColorSpaceCategoryIterator :module: PyOpenColorIO.ColorSpace diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 04b090f611..86049a72eb 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -1916,18 +1916,24 @@ class OCIOEXPORT ColorSpace void setDescription(const char * description); /** - * \brief Get/Set the interop ID for the color space. - * - * The interop ID is a standardized identifier for commonly used color spaces, - * particularly for texture assets. These IDs enable consistent color space - * handling across different applications and pipelines. + * Get/Set the interop ID for the color space. * + * The interop ID is a standardized identifier for commonly used color spaces. * These IDs are defined by the Academy Software Foundation's ColorInterop project * to standardize color space naming across the industry. */ const char * getInteropID() const noexcept; void setInteropID(const char * interopID); + /** + * Get/Set the AMF transform IDs for the color space. + * + * The AMF transform IDs are used to identify specific transforms in the ACES Metadata File. + * Multiple transform IDs can be specified in a newline-separated string. + */ + const char * getAmfTransformIDs() const noexcept; + void setAmfTransformIDs(const char * amfTransformIDs); + BitDepth getBitDepth() const noexcept; void setBitDepth(BitDepth bitDepth); diff --git a/src/OpenColorIO/Baker.cpp b/src/OpenColorIO/Baker.cpp index b8a78a958c..e92a4f3d31 100755 --- a/src/OpenColorIO/Baker.cpp +++ b/src/OpenColorIO/Baker.cpp @@ -126,7 +126,7 @@ void Baker::setFormat(const char * formatName) { if (formatInfoVec[i].capabilities & FORMAT_CAPABILITY_BAKE) { - getImpl()->m_formatName = formatName; + getImpl()->m_formatName = formatName ? formatName : ""; return; } } @@ -155,7 +155,7 @@ FormatMetadata & Baker::getFormatMetadata() void Baker::setInputSpace(const char * inputSpace) { - getImpl()->m_inputSpace = inputSpace; + getImpl()->m_inputSpace = inputSpace ? inputSpace : ""; } const char * Baker::getInputSpace() const @@ -165,7 +165,7 @@ const char * Baker::getInputSpace() const void Baker::setShaperSpace(const char * shaperSpace) { - getImpl()->m_shaperSpace = shaperSpace; + getImpl()->m_shaperSpace = shaperSpace ? shaperSpace : ""; } const char * Baker::getShaperSpace() const @@ -175,7 +175,7 @@ const char * Baker::getShaperSpace() const void Baker::setLooks(const char * looks) { - getImpl()->m_looks = looks; + getImpl()->m_looks = looks ? looks : ""; } const char * Baker::getLooks() const @@ -185,7 +185,7 @@ const char * Baker::getLooks() const void Baker::setTargetSpace(const char * targetSpace) { - getImpl()->m_targetSpace = targetSpace; + getImpl()->m_targetSpace = targetSpace ? targetSpace : ""; } const char * Baker::getTargetSpace() const @@ -205,7 +205,7 @@ const char * Baker::getView() const void Baker::setDisplayView(const char * display, const char * view) { - if (!display ^ !view) + if (!display || !view) { throw Exception("Both display and view must be set."); } diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index bee4fef849..4809d6ba78 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -25,6 +25,7 @@ class ColorSpace::Impl std::string m_description; std::string m_encoding; std::string m_interopID; + std::string m_amfTransformIDs; StringUtils::StringVec m_aliases; BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN }; @@ -64,6 +65,7 @@ class ColorSpace::Impl m_description = rhs.m_description; m_encoding = rhs.m_encoding; m_interopID = rhs.m_interopID; + m_amfTransformIDs = rhs.m_amfTransformIDs; m_bitDepth = rhs.m_bitDepth; m_isData = rhs.m_isData; m_referenceSpaceType = rhs.m_referenceSpaceType; @@ -197,7 +199,7 @@ const char * ColorSpace::getFamily() const noexcept void ColorSpace::setFamily(const char * family) { - getImpl()->m_family = family; + getImpl()->m_family = family ? family : ""; } const char * ColorSpace::getEqualityGroup() const noexcept @@ -207,7 +209,7 @@ const char * ColorSpace::getEqualityGroup() const noexcept void ColorSpace::setEqualityGroup(const char * equalityGroup) { - getImpl()->m_equalityGroup = equalityGroup; + getImpl()->m_equalityGroup = equalityGroup ? equalityGroup : ""; } const char * ColorSpace::getDescription() const noexcept @@ -217,7 +219,7 @@ const char * ColorSpace::getDescription() const noexcept void ColorSpace::setDescription(const char * description) { - getImpl()->m_description = description; + getImpl()->m_description = description ? description : ""; } const char * ColorSpace::getInteropID() const noexcept @@ -227,7 +229,17 @@ const char * ColorSpace::getInteropID() const noexcept void ColorSpace::setInteropID(const char * interopID) { - getImpl()->m_interopID = interopID; + getImpl()->m_interopID = interopID ? interopID : ""; +} + +const char * ColorSpace::getAmfTransformIDs() const noexcept +{ + return getImpl()->m_amfTransformIDs.c_str(); +} + +void ColorSpace::setAmfTransformIDs(const char * amfTransformIDs) +{ + getImpl()->m_amfTransformIDs = amfTransformIDs ? amfTransformIDs : ""; } BitDepth ColorSpace::getBitDepth() const noexcept @@ -277,7 +289,7 @@ const char * ColorSpace::getEncoding() const noexcept void ColorSpace::setEncoding(const char * encoding) { - getImpl()->m_encoding = encoding; + getImpl()->m_encoding = encoding ? encoding : ""; } bool ColorSpace::isData() const noexcept diff --git a/src/OpenColorIO/Context.cpp b/src/OpenColorIO/Context.cpp index 3a1294be58..b7e71ae6e7 100644 --- a/src/OpenColorIO/Context.cpp +++ b/src/OpenColorIO/Context.cpp @@ -253,7 +253,7 @@ void Context::setWorkingDir(const char * dirname) { AutoMutex lock(getImpl()->m_resultsCacheMutex); - getImpl()->m_workingDir = dirname; + getImpl()->m_workingDir = dirname ? dirname : ""; getImpl()->clearCaches(); } diff --git a/src/OpenColorIO/Look.cpp b/src/OpenColorIO/Look.cpp index c0e7cbef13..9830d0a460 100644 --- a/src/OpenColorIO/Look.cpp +++ b/src/OpenColorIO/Look.cpp @@ -86,7 +86,7 @@ const char * Look::getName() const void Look::setName(const char * name) { - getImpl()->m_name = name; + getImpl()->m_name = name ? name : ""; } const char * Look::getProcessSpace() const @@ -96,7 +96,7 @@ const char * Look::getProcessSpace() const void Look::setProcessSpace(const char * processSpace) { - getImpl()->m_processSpace = processSpace; + getImpl()->m_processSpace = processSpace ? processSpace : ""; } ConstTransformRcPtr Look::getTransform() const @@ -126,7 +126,7 @@ const char * Look::getDescription() const void Look::setDescription(const char * description) { - getImpl()->m_description = description; + getImpl()->m_description = description ? description : ""; } bool CollectContextVariables(const Config & config, diff --git a/src/OpenColorIO/OCIOYaml.cpp b/src/OpenColorIO/OCIOYaml.cpp index bfd6c8405f..a2858bd70f 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -3193,11 +3193,6 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major load(iter->second, stringval); cs->setName(stringval.c_str()); } - else if(key == "interop_id") - { - load(iter->second, stringval); - cs->setInteropID(stringval.c_str()); - } else if(key == "aliases") { StringUtils::StringVec aliases; @@ -3221,6 +3216,16 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major { load(iter->second, stringval); cs->setEqualityGroup(stringval.c_str()); + } + else if (key == "interopid") + { + load(iter->second, stringval); + cs->setInteropID(stringval.c_str()); + } + else if (key == "amftransformids") + { + load(iter->second, stringval); + cs->setAmfTransformIDs(stringval.c_str()); } else if(key == "bitdepth") { @@ -3329,15 +3334,23 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int major out << YAML::Flow << YAML::Value << aliases; } - const std::string interopID{ cs->getInteropID() }; - if (!interopID.empty()) + out << YAML::Key << "family" << YAML::Value << cs->getFamily(); + out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup(); + + const std::string interopID{cs->getInteropID()}; + if (!interopID.empty()) { - out << YAML::Key << "interop_id"; + out << YAML::Key << "interopid"; out << YAML::Value << interopID; } - out << YAML::Key << "family" << YAML::Value << cs->getFamily(); - out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup(); + const std::string amfTransformIDs{cs->getAmfTransformIDs()}; + if (!amfTransformIDs.empty()) + { + out << YAML::Key << "amftransformids"; + out << YAML::Value << amfTransformIDs; + } + out << YAML::Key << "bitdepth" << YAML::Value; save(out, cs->getBitDepth()); saveDescription(out, cs->getDescription()); diff --git a/src/OpenColorIO/Platform.cpp b/src/OpenColorIO/Platform.cpp index 1dbd846f35..08491bb981 100644 --- a/src/OpenColorIO/Platform.cpp +++ b/src/OpenColorIO/Platform.cpp @@ -154,6 +154,11 @@ bool isEnvPresent(const char * name) int Strcasecmp(const char * str1, const char * str2) { + if (!str1 || !str2) + { + throw Exception("nullptr is passed."); + } + #ifdef _WIN32 return ::_stricmp(str1, str2); #else @@ -163,6 +168,11 @@ int Strcasecmp(const char * str1, const char * str2) int Strncasecmp(const char * str1, const char * str2, size_t n) { + if (!str1 || !str2) + { + throw Exception("nullptr is passed."); + } + #ifdef _WIN32 return ::_strnicmp(str1, str2, n); #else diff --git a/src/OpenColorIO/ViewTransform.cpp b/src/OpenColorIO/ViewTransform.cpp index 0a7ca21091..7fd8914a34 100644 --- a/src/OpenColorIO/ViewTransform.cpp +++ b/src/OpenColorIO/ViewTransform.cpp @@ -91,7 +91,7 @@ const char * ViewTransform::getName() const noexcept void ViewTransform::setName(const char * name) noexcept { - getImpl()->m_name = name; + getImpl()->m_name = name ? name : ""; } const char * ViewTransform::getFamily() const noexcept @@ -101,7 +101,7 @@ const char * ViewTransform::getFamily() const noexcept void ViewTransform::setFamily(const char * family) { - getImpl()->m_family = family; + getImpl()->m_family = family ? family : ""; } const char * ViewTransform::getDescription() const noexcept @@ -111,7 +111,7 @@ const char * ViewTransform::getDescription() const noexcept void ViewTransform::setDescription(const char * description) { - getImpl()->m_description = description; + getImpl()->m_description = description ? description : ""; } bool ViewTransform::hasCategory(const char * category) const diff --git a/src/bindings/java/JNIColorSpace.cpp b/src/bindings/java/JNIColorSpace.cpp index 028792d0ab..777d80a6f1 100644 --- a/src/bindings/java/JNIColorSpace.cpp +++ b/src/bindings/java/JNIColorSpace.cpp @@ -127,6 +127,24 @@ Java_org_OpenColorIO_ColorSpace_setInteropID(JNIEnv * env, jobject self, jstring OCIO_JNITRY_EXIT() } +JNIEXPORT jstring JNICALL +Java_org_OpenColorIO_ColorSpace_getAmfTransformIDs(JNIEnv * env, jobject self) +{ + OCIO_JNITRY_ENTER() + ConstColorSpaceRcPtr col = GetConstJOCIO(env, self); + return env->NewStringUTF(col->getAmfTransformIDs()); + OCIO_JNITRY_EXIT(NULL) +} + +JNIEXPORT void JNICALL +Java_org_OpenColorIO_ColorSpace_setAmfTransformIDs(JNIEnv * env, jobject self, jstring amfTransformIDs) +{ + OCIO_JNITRY_ENTER() + ColorSpaceRcPtr col = GetEditableJOCIO(env, self); + col->setAmfTransformIDs(GetJStringValue(env, amfTransformIDs)()); + OCIO_JNITRY_EXIT() +} + JNIEXPORT jobject JNICALL Java_org_OpenColorIO_ColorSpace_getBitDepth(JNIEnv * env, jobject self) { diff --git a/src/bindings/java/org/OpenColorIO/ColorSpace.java b/src/bindings/java/org/OpenColorIO/ColorSpace.java index cc370d911a..c875325e1a 100644 --- a/src/bindings/java/org/OpenColorIO/ColorSpace.java +++ b/src/bindings/java/org/OpenColorIO/ColorSpace.java @@ -22,6 +22,8 @@ public class ColorSpace extends LoadLibrary public native void setDescription(String description); public native String getInteropID(); public native void setInteropID(String interopID); + public native String getAmfTransformIDs(); + public native void setAmfTransformIDs(String amfTransformIDs); public native BitDepth getBitDepth(); public native void setBitDepth(BitDepth bitDepth); public native boolean isData(); diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index 933700bd99..5c8237bdb0 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -197,6 +197,10 @@ void bindPyColorSpace(py::module & m) DOC(ColorSpace, getInteropID)) .def("setInteropID", &ColorSpace::setInteropID, "interopID"_a, DOC(ColorSpace, setInteropID)) + .def("getAmfTransformIDs", &ColorSpace::getAmfTransformIDs, + DOC(ColorSpace, getAmfTransformIDs)) + .def("setAmfTransformIDs", &ColorSpace::setAmfTransformIDs, "amfTransformIDs"_a, + DOC(ColorSpace, setAmfTransformIDs)) .def("getBitDepth", &ColorSpace::getBitDepth, DOC(ColorSpace, getBitDepth)) .def("setBitDepth", &ColorSpace::setBitDepth, "bitDepth"_a, diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 95db7f3924..efeae9bb4a 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -39,7 +39,17 @@ OCIO_ADD_TEST(ColorSpace, basic) OCIO_CHECK_ASSERT(!cs->isData()); OCIO_CHECK_EQUAL(OCIO::ALLOCATION_UNIFORM, cs->getAllocation()); OCIO_CHECK_EQUAL(0, cs->getAllocationNumVars()); - + + // Check the nullptr assignment hardening. + OCIO_CHECK_NO_THROW(cs->setName(nullptr)); + OCIO_CHECK_NO_THROW(cs->setDescription(nullptr)); + OCIO_CHECK_NO_THROW(cs->setFamily(nullptr)); + OCIO_CHECK_NO_THROW(cs->setEqualityGroup(nullptr)); + OCIO_CHECK_NO_THROW(cs->setEncoding(nullptr)); + OCIO_CHECK_NO_THROW(cs->setAmfTransformIDs(nullptr)); + OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); + + // Test set/get roundtrip. cs->setName("name"); OCIO_CHECK_EQUAL(std::string("name"), cs->getName()); cs->setFamily("family"); @@ -619,29 +629,29 @@ active_views: [] OCIO_CHECK_EQUAL(cfgRes, os.str()); } -/* + { constexpr char End[]{ R"(colorspaces: - ! name: raw family: raw equalitygroup: "" + interopid: srgb_texture bitdepth: 32f description: Some text. - interop_id: srgb_texture isdata: true allocation: uniform - ! - name: raw2 + name: bar family: raw equalitygroup: "" + interopid: acescg_texture bitdepth: 32f description: | One line. Other line. - interop_id: acescg_texture isdata: true allocation: uniform )" }; @@ -709,7 +719,7 @@ active_views: [] cfg2 = OCIO::Config::CreateFromStream(is); cs2 = cfg2->getColorSpace("testing"); OCIO_CHECK_EQUAL(std::string(cs2->getInteropID()), "linear_display_p3"); - */ + } OCIO_ADD_TEST(Config, use_alias) @@ -1812,4 +1822,77 @@ OCIO_ADD_TEST(ColorSpace, interop_id) cs->setInteropID(nullptr); OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); } -*/ \ No newline at end of file +*/ + +OCIO_ADD_TEST(ColorSpace, amf_transform_ids) +{ + OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); + + // Test default value + OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), ""); + + // Test setting and getting single ID + const char * singleID = "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3"; + cs->setAmfTransformIDs(singleID); + OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), singleID); + + // Test setting and getting multiple IDs + const char * multipleIDs = + "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3\n" + "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3"; + cs->setAmfTransformIDs(multipleIDs); + OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), multipleIDs); + + // Test setting to empty string + cs->setAmfTransformIDs(""); + OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), ""); + + // Test setting to nullptr + cs->setDescription(nullptr); + cs->setAmfTransformIDs(nullptr); + OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), ""); + + // Test copy constructor preserves AMF transform IDs + cs->setAmfTransformIDs(singleID); + OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); + OCIO_CHECK_EQUAL(std::string(copy->getAmfTransformIDs()), singleID); +} + +OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) +{ + // Test YAML serialization and deserialization of AmfTransformIDs + auto cfg = OCIO::Config::Create(); + auto cs = OCIO::ColorSpace::Create(); + cs->setName("test_colorspace"); + + const std::string amfIDs = + "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3\n" + "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3"; + + cs->setAmfTransformIDs(amfIDs.c_str()); + cfg->addColorSpace(cs); + + // Serialize the Config + std::ostringstream os; + cfg->serialize(os); + + // Check that the YAML contains the amftransformids field + const std::string yamlStr = os.str(); + OCIO_CHECK_NE(yamlStr.find("amftransformids"), std::string::npos); + + // Deserialize and compare + std::istringstream is; + is.str(yamlStr); + auto cfg2 = OCIO::Config::CreateFromStream(is); + OCIO_CHECK_EQUAL(cfg2->getNumColorSpaces(), 1); + auto cs2 = cfg2->getColorSpace("test_colorspace"); + OCIO_CHECK_EQUAL(std::string(cs2->getAmfTransformIDs()), amfIDs); + + // Test with empty AmfTransformIDs (should not appear in YAML) + cs->setAmfTransformIDs(""); + cfg->addColorSpace(cs); // replace the existing CS + os.str(""); + cfg->serialize(os); + const std::string yamlStr2 = os.str(); + OCIO_CHECK_EQUAL(yamlStr2.find("amftransformids"), std::string::npos); +} \ No newline at end of file From 8bf083e9d541de35a0db47e73cfa6c2a0f75357a Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 28 May 2025 11:14:39 -0700 Subject: [PATCH 03/16] - Adding color space ICC profile name field. Signed-off-by: cuneyt.ozdas --- .../frozen/pyopencolorio_colorspace.rst | 20 +++- include/OpenColorIO/OpenColorIO.h | 10 ++ src/OpenColorIO/ColorSpace.cpp | 12 ++ src/OpenColorIO/OCIOYaml.cpp | 12 ++ src/bindings/java/JNIColorSpace.cpp | 18 +++ .../java/org/OpenColorIO/ColorSpace.java | 2 + src/bindings/python/PyColorSpace.cpp | 4 + tests/cpu/ColorSpace_tests.cpp | 106 +++++++++++++++--- 8 files changed, 167 insertions(+), 17 deletions(-) diff --git a/docs/api/python/frozen/pyopencolorio_colorspace.rst b/docs/api/python/frozen/pyopencolorio_colorspace.rst index 13bc65538f..4e82facc6c 100644 --- a/docs/api/python/frozen/pyopencolorio_colorspace.rst +++ b/docs/api/python/frozen/pyopencolorio_colorspace.rst @@ -235,9 +235,25 @@ :module: PyOpenColorIO Set the AMF transform IDs for the color space. + Multiple transform IDs can be specified in a newline-separated string. + + .. py:method:: ColorSpace.getIccProfileName(self: PyOpenColorIO.ColorSpace) -> str + :module: PyOpenColorIO + + Get the ICC profile name for the color space. + + The ICC profile name identifies the ICC color profile associated with this color space. + This can be used to link OCIO color spaces with corresponding ICC profiles for + applications that need to work with both color management systems. + + .. py:method:: ColorSpace.setIccProfileName(self: PyOpenColorIO.ColorSpace, iccProfileName: str) -> None + :module: PyOpenColorIO + + Set the ICC profile name for the color space. - Args: - amfTransformIDs (str): A newline-separated string of AMF transform IDs. + The ICC profile name identifies the ICC color profile associated with this color space. + This can be used to link OCIO color spaces with corresponding ICC profiles for + applications that need to work with both color management systems. .. py:class:: ColorSpaceCategoryIterator diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 86049a72eb..69d55225a5 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -1934,6 +1934,16 @@ class OCIOEXPORT ColorSpace const char * getAmfTransformIDs() const noexcept; void setAmfTransformIDs(const char * amfTransformIDs); + /** + * Get/Set the ICC profile name for the color space. + * + * The ICC profile name identifies the ICC color profile associated with this color space. + * This can be used to link OCIO color spaces with corresponding ICC profiles for + * applications that need to work with both color management systems. + */ + const char * getIccProfileName() const noexcept; + void setIccProfileName(const char * iccProfileName); + BitDepth getBitDepth() const noexcept; void setBitDepth(BitDepth bitDepth); diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index 4809d6ba78..d083dcc8af 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -26,6 +26,7 @@ class ColorSpace::Impl std::string m_encoding; std::string m_interopID; std::string m_amfTransformIDs; + std::string m_iccProfileName; StringUtils::StringVec m_aliases; BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN }; @@ -66,6 +67,7 @@ class ColorSpace::Impl m_encoding = rhs.m_encoding; m_interopID = rhs.m_interopID; m_amfTransformIDs = rhs.m_amfTransformIDs; + m_iccProfileName = rhs.m_iccProfileName; m_bitDepth = rhs.m_bitDepth; m_isData = rhs.m_isData; m_referenceSpaceType = rhs.m_referenceSpaceType; @@ -242,6 +244,16 @@ void ColorSpace::setAmfTransformIDs(const char * amfTransformIDs) getImpl()->m_amfTransformIDs = amfTransformIDs ? amfTransformIDs : ""; } +const char * ColorSpace::getIccProfileName() const noexcept +{ + return getImpl()->m_iccProfileName.c_str(); +} + +void ColorSpace::setIccProfileName(const char * iccProfileName) +{ + getImpl()->m_iccProfileName = iccProfileName ? iccProfileName : ""; +} + BitDepth ColorSpace::getBitDepth() const noexcept { return getImpl()->m_bitDepth; diff --git a/src/OpenColorIO/OCIOYaml.cpp b/src/OpenColorIO/OCIOYaml.cpp index a2858bd70f..63c4741e64 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -3227,6 +3227,11 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major load(iter->second, stringval); cs->setAmfTransformIDs(stringval.c_str()); } + else if (key == "iccprofilename") + { + load(iter->second, stringval); + cs->setIccProfileName(stringval.c_str()); + } else if(key == "bitdepth") { BitDepth ret; @@ -3351,6 +3356,13 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int major out << YAML::Value << amfTransformIDs; } + const std::string iccProfileName{cs->getIccProfileName()}; + if (!iccProfileName.empty()) + { + out << YAML::Key << "iccprofilename"; + out << YAML::Value << iccProfileName; + } + out << YAML::Key << "bitdepth" << YAML::Value; save(out, cs->getBitDepth()); saveDescription(out, cs->getDescription()); diff --git a/src/bindings/java/JNIColorSpace.cpp b/src/bindings/java/JNIColorSpace.cpp index 777d80a6f1..fde8690b6a 100644 --- a/src/bindings/java/JNIColorSpace.cpp +++ b/src/bindings/java/JNIColorSpace.cpp @@ -145,6 +145,24 @@ Java_org_OpenColorIO_ColorSpace_setAmfTransformIDs(JNIEnv * env, jobject self, j OCIO_JNITRY_EXIT() } +JNIEXPORT jstring JNICALL +Java_org_OpenColorIO_ColorSpace_getIccProfileName(JNIEnv * env, jobject self) +{ + OCIO_JNITRY_ENTER() + ConstColorSpaceRcPtr col = GetConstJOCIO(env, self); + return env->NewStringUTF(col->getIccProfileName()); + OCIO_JNITRY_EXIT(NULL) +} + +JNIEXPORT void JNICALL +Java_org_OpenColorIO_ColorSpace_setIccProfileName(JNIEnv * env, jobject self, jstring iccProfileName) +{ + OCIO_JNITRY_ENTER() + ColorSpaceRcPtr col = GetEditableJOCIO(env, self); + col->setIccProfileName(GetJStringValue(env, iccProfileName)()); + OCIO_JNITRY_EXIT() +} + JNIEXPORT jobject JNICALL Java_org_OpenColorIO_ColorSpace_getBitDepth(JNIEnv * env, jobject self) { diff --git a/src/bindings/java/org/OpenColorIO/ColorSpace.java b/src/bindings/java/org/OpenColorIO/ColorSpace.java index c875325e1a..783b15c558 100644 --- a/src/bindings/java/org/OpenColorIO/ColorSpace.java +++ b/src/bindings/java/org/OpenColorIO/ColorSpace.java @@ -24,6 +24,8 @@ public class ColorSpace extends LoadLibrary public native void setInteropID(String interopID); public native String getAmfTransformIDs(); public native void setAmfTransformIDs(String amfTransformIDs); + public native String getIccProfileName(); + public native void setIccProfileName(String iccProfileName); public native BitDepth getBitDepth(); public native void setBitDepth(BitDepth bitDepth); public native boolean isData(); diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index 5c8237bdb0..3cd6b538bc 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -201,6 +201,10 @@ void bindPyColorSpace(py::module & m) DOC(ColorSpace, getAmfTransformIDs)) .def("setAmfTransformIDs", &ColorSpace::setAmfTransformIDs, "amfTransformIDs"_a, DOC(ColorSpace, setAmfTransformIDs)) + .def("getIccProfileName", &ColorSpace::getIccProfileName, + DOC(ColorSpace, getIccProfileName)) + .def("setIccProfileName", &ColorSpace::setIccProfileName, "iccProfileName"_a, + DOC(ColorSpace, setIccProfileName)) .def("getBitDepth", &ColorSpace::getBitDepth, DOC(ColorSpace, getBitDepth)) .def("setBitDepth", &ColorSpace::setBitDepth, "bitDepth"_a, diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index efeae9bb4a..07e0566a44 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -1873,26 +1873,102 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) cfg->addColorSpace(cs); // Serialize the Config - std::ostringstream os; - cfg->serialize(os); - - // Check that the YAML contains the amftransformids field - const std::string yamlStr = os.str(); + std::stringstream ss; + cfg->serialize(ss); + std::string yamlStr = ss.str(); + + // Verify AmfTransformIDs appears in YAML OCIO_CHECK_NE(yamlStr.find("amftransformids"), std::string::npos); + OCIO_CHECK_NE(yamlStr.find("ACEScsc.Academy.ACEScc_to_ACES"), std::string::npos); - // Deserialize and compare - std::istringstream is; - is.str(yamlStr); - auto cfg2 = OCIO::Config::CreateFromStream(is); - OCIO_CHECK_EQUAL(cfg2->getNumColorSpaces(), 1); - auto cs2 = cfg2->getColorSpace("test_colorspace"); - OCIO_CHECK_EQUAL(std::string(cs2->getAmfTransformIDs()), amfIDs); + // Deserialize and verify + std::istringstream iss(yamlStr); + OCIO::ConstConfigRcPtr deserializedCfg; + OCIO_CHECK_NO_THROW(deserializedCfg = OCIO::Config::CreateFromStream(iss)); + + // Verify AmfTransformIDs is preserved + OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); + OCIO_CHECK_EQUAL(std::string(deserializedCs->getAmfTransformIDs()), amfIDs); // Test with empty AmfTransformIDs (should not appear in YAML) cs->setAmfTransformIDs(""); cfg->addColorSpace(cs); // replace the existing CS - os.str(""); - cfg->serialize(os); - const std::string yamlStr2 = os.str(); + ss.str(""); + cfg->serialize(ss); + std::string yamlStr2 = ss.str(); + + // Verify empty AmfTransformIDs does not appear in YAML OCIO_CHECK_EQUAL(yamlStr2.find("amftransformids"), std::string::npos); +} + +OCIO_ADD_TEST(ColorSpace, icc_profile_name) +{ + OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); + + // Test default value + OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), ""); + + // Test setting and getting single profile name + const char * profileName = "sRGB IEC61966-2.1"; + cs->setIccProfileName(profileName); + OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), profileName); + + // Test setting and getting another profile name + const char * anotherProfile = "Adobe RGB (1998)"; + cs->setIccProfileName(anotherProfile); + OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), anotherProfile); + + // Test setting empty string + cs->setIccProfileName(""); + OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), ""); + + // Test setting null pointer (should be safe) + OCIO_CHECK_NO_THROW(cs->setIccProfileName(nullptr)); + OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), ""); + + // Test copy constructor preserves ICC profile name + cs->setIccProfileName(profileName); + OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); + OCIO_CHECK_EQUAL(std::string(copy->getIccProfileName()), profileName); +} + +OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) +{ + // Test YAML serialization and deserialization of IccProfileName + auto cfg = OCIO::Config::Create(); + auto cs = OCIO::ColorSpace::Create(); + cs->setName("test_colorspace"); + + const std::string profileName = "sRGB IEC61966-2.1"; + + cs->setIccProfileName(profileName.c_str()); + cfg->addColorSpace(cs); + + // Serialize the Config + std::stringstream ss; + cfg->serialize(ss); + std::string yamlStr = ss.str(); + + // Verify IccProfileName appears in YAML + OCIO_CHECK_NE(yamlStr.find("iccprofilename"), std::string::npos); + OCIO_CHECK_NE(yamlStr.find(profileName), std::string::npos); + + // Deserialize and verify + std::istringstream iss(yamlStr); + OCIO::ConstConfigRcPtr deserializedCfg; + OCIO_CHECK_NO_THROW(deserializedCfg = OCIO::Config::CreateFromStream(iss)); + + // Verify IccProfileName is preserved + OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); + OCIO_CHECK_EQUAL(std::string(deserializedCs->getIccProfileName()), profileName); + + // Test with empty IccProfileName (should not appear in YAML) + cs->setIccProfileName(""); + cfg->addColorSpace(cs); // replace the existing CS + ss.str(""); + cfg->serialize(ss); + std::string yamlStr2 = ss.str(); + + // Verify empty IccProfileName does not appear in YAML + OCIO_CHECK_EQUAL(yamlStr2.find("iccprofilename"), std::string::npos); } \ No newline at end of file From 57f5b382d13ef9ab0769daf391fc751948b2e74f Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 4 Jun 2025 15:07:27 -0700 Subject: [PATCH 04/16] - reverting the java binding changes (not maintained) - Reverting the manual changes to python frozen docs - capitalizing the acronyms in the functions names, adding underscores to the yaml keywords - changing the new keyword's ordering in the yaml file - bumping the config minor version number for v2 to 5 - new fields are now restricted to v2.5 and higher (checkVersionConsistency() is updated to detect violations) - Fixing the version check logic error in Config::validate() - Added basic pyhton tests - fixed / extended the color space cpu tests Signed-off-by: cuneyt.ozdas --- .../frozen/pyopencolorio_colorspace.rst | 20 +- include/OpenColorIO/OpenColorIO.h | 8 +- src/OpenColorIO/ColorSpace.cpp | 24 +- src/OpenColorIO/Config.cpp | 47 ++- src/OpenColorIO/OCIOYaml.cpp | 63 ++-- src/OpenColorIO/Platform.cpp | 4 +- src/bindings/java/JNIColorSpace.cpp | 18 -- .../java/org/OpenColorIO/ColorSpace.java | 2 - src/bindings/python/PyColorSpace.cpp | 8 +- tests/cpu/ColorSpace_tests.cpp | 281 +++++++++++++----- tests/cpu/Config_tests.cpp | 4 +- tests/python/ColorSpaceTest.py | 141 ++++++++- 12 files changed, 439 insertions(+), 181 deletions(-) diff --git a/docs/api/python/frozen/pyopencolorio_colorspace.rst b/docs/api/python/frozen/pyopencolorio_colorspace.rst index 4e82facc6c..13bc65538f 100644 --- a/docs/api/python/frozen/pyopencolorio_colorspace.rst +++ b/docs/api/python/frozen/pyopencolorio_colorspace.rst @@ -235,25 +235,9 @@ :module: PyOpenColorIO Set the AMF transform IDs for the color space. - Multiple transform IDs can be specified in a newline-separated string. - - .. py:method:: ColorSpace.getIccProfileName(self: PyOpenColorIO.ColorSpace) -> str - :module: PyOpenColorIO - - Get the ICC profile name for the color space. - - The ICC profile name identifies the ICC color profile associated with this color space. - This can be used to link OCIO color spaces with corresponding ICC profiles for - applications that need to work with both color management systems. - - .. py:method:: ColorSpace.setIccProfileName(self: PyOpenColorIO.ColorSpace, iccProfileName: str) -> None - :module: PyOpenColorIO - - Set the ICC profile name for the color space. - The ICC profile name identifies the ICC color profile associated with this color space. - This can be used to link OCIO color spaces with corresponding ICC profiles for - applications that need to work with both color management systems. + Args: + amfTransformIDs (str): A newline-separated string of AMF transform IDs. .. py:class:: ColorSpaceCategoryIterator diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 69d55225a5..3a43e3b41e 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -1931,8 +1931,8 @@ class OCIOEXPORT ColorSpace * The AMF transform IDs are used to identify specific transforms in the ACES Metadata File. * Multiple transform IDs can be specified in a newline-separated string. */ - const char * getAmfTransformIDs() const noexcept; - void setAmfTransformIDs(const char * amfTransformIDs); + const char * getAMFTransformIDs() const noexcept; + void setAMFTransformIDs(const char * amfTransformIDs); /** * Get/Set the ICC profile name for the color space. @@ -1941,8 +1941,8 @@ class OCIOEXPORT ColorSpace * This can be used to link OCIO color spaces with corresponding ICC profiles for * applications that need to work with both color management systems. */ - const char * getIccProfileName() const noexcept; - void setIccProfileName(const char * iccProfileName); + const char * getICCProfileName() const noexcept; + void setICCProfileName(const char * iccProfileName); BitDepth getBitDepth() const noexcept; void setBitDepth(BitDepth bitDepth); diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index d083dcc8af..952146fc9c 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -25,8 +25,8 @@ class ColorSpace::Impl std::string m_description; std::string m_encoding; std::string m_interopID; - std::string m_amfTransformIDs; - std::string m_iccProfileName; + std::string m_AMFTransformIDs; + std::string m_ICCProfileName; StringUtils::StringVec m_aliases; BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN }; @@ -66,8 +66,8 @@ class ColorSpace::Impl m_description = rhs.m_description; m_encoding = rhs.m_encoding; m_interopID = rhs.m_interopID; - m_amfTransformIDs = rhs.m_amfTransformIDs; - m_iccProfileName = rhs.m_iccProfileName; + m_AMFTransformIDs = rhs.m_AMFTransformIDs; + m_ICCProfileName = rhs.m_ICCProfileName; m_bitDepth = rhs.m_bitDepth; m_isData = rhs.m_isData; m_referenceSpaceType = rhs.m_referenceSpaceType; @@ -234,24 +234,24 @@ void ColorSpace::setInteropID(const char * interopID) getImpl()->m_interopID = interopID ? interopID : ""; } -const char * ColorSpace::getAmfTransformIDs() const noexcept +const char * ColorSpace::getAMFTransformIDs() const noexcept { - return getImpl()->m_amfTransformIDs.c_str(); + return getImpl()->m_AMFTransformIDs.c_str(); } -void ColorSpace::setAmfTransformIDs(const char * amfTransformIDs) +void ColorSpace::setAMFTransformIDs(const char * amfTransformIDs) { - getImpl()->m_amfTransformIDs = amfTransformIDs ? amfTransformIDs : ""; + getImpl()->m_AMFTransformIDs = amfTransformIDs ? amfTransformIDs : ""; } -const char * ColorSpace::getIccProfileName() const noexcept +const char * ColorSpace::getICCProfileName() const noexcept { - return getImpl()->m_iccProfileName.c_str(); + return getImpl()->m_ICCProfileName.c_str(); } -void ColorSpace::setIccProfileName(const char * iccProfileName) +void ColorSpace::setICCProfileName(const char * iccProfileName) { - getImpl()->m_iccProfileName = iccProfileName ? iccProfileName : ""; + getImpl()->m_ICCProfileName = iccProfileName ? iccProfileName : ""; } BitDepth ColorSpace::getBitDepth() const noexcept diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index a4cf7c5fe4..3f368f123a 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -247,7 +247,7 @@ static constexpr unsigned LastSupportedMajorVersion = OCIO_VERSION_MAJOR; // For each major version keep the most recent minor. static const unsigned int LastSupportedMinorVersion[] = {0, // Version 1 - 4 // Version 2 + 5 // Version 2 }; } // namespace @@ -1185,7 +1185,7 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) // Check if it is an OCIOZ archive. if (magicNumber[0] == 'P' && magicNumber[1] == 'K') { - // Closing ifstream even though it should be close by ifstream deconstructor (RAII). + // Closing ifstream even though it should be closed by ifstream destructor (RAII). ifstream.close(); // The file should be an OCIOZ archive file. @@ -1499,7 +1499,8 @@ void Config::validate() const // Check for interchange roles requirements - scene-referred and display-referred. - if (getMajorVersion() >= 2 && getMinorVersion() >= 2) + unsigned int versionHex = (getMajorVersion() << 24) | (getMinorVersion() << 16); + if (versionHex >= 0x02020000u) // v2.2 or higher { bool hasRoleSceneLinear = false; bool hasRoleCompositingLog = false; @@ -5426,6 +5427,8 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons void Config::Impl::checkVersionConsistency() const { + unsigned int hexVersion = (m_majorVersion << 24) | (m_minorVersion << 16); + // Check for the Transforms. ConstTransformVec transforms; @@ -5495,18 +5498,44 @@ void Config::Impl::checkVersionConsistency() const } } - // Check for the DisplayColorSpaces. + // Check for the ColorSpaces. - if (m_majorVersion < 2) + const int nbCS = m_allColorSpaces->getNumColorSpaces(); + for (int i = 0; i < nbCS; ++i) { - const int nbCS = m_allColorSpaces->getNumColorSpaces(); - for (int i = 0; i < nbCS; ++i) + const auto & cs = m_allColorSpaces->getColorSpaceByIndex(i); + if (m_majorVersion < 2) { - const auto & cs = m_allColorSpaces->getColorSpaceByIndex(i); - if (MatchReferenceType(SEARCH_REFERENCE_SPACE_DISPLAY, cs->getReferenceSpaceType())) + if (MatchReferenceType(SEARCH_REFERENCE_SPACE_DISPLAY, cs->getReferenceSpaceType())) { throw Exception("Only version 2 (or higher) can have DisplayColorSpaces."); } + } + + if (hexVersion < 0x02050000) // Version 2.5 + { + const std::string interopID{cs->getInteropID()}; + if (*cs->getInteropID()) + { + std::ostringstream os; + os << "Config failed validation. The color space '" << cs->getName() << "' "; + os << "has non-empty InteropID and config version is less than 2.5."; + throw Exception(os.str().c_str()); + } + if (*cs->getAMFTransformIDs()) + { + std::ostringstream os; + os << "Config failed validation. The color space '" << cs->getName() << "' "; + os << "has non-empty AMFTransformIDs and config version is less than 2.5."; + throw Exception(os.str().c_str()); + } + if (*cs->getICCProfileName()) + { + std::ostringstream os; + os << "Config failed validation. The color space '" << cs->getName() << "' "; + os << "has non-empty ICCProfileName and config version is less than 2.5."; + throw Exception(os.str().c_str()); + } } } diff --git a/src/OpenColorIO/OCIOYaml.cpp b/src/OpenColorIO/OCIOYaml.cpp index 63c4741e64..473405d83b 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -3202,36 +3202,36 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major cs->addAlias(alias.c_str()); } } + else if (key == "interop_id") + { + load(iter->second, stringval); + cs->setInteropID(stringval.c_str()); + } else if(key == "description") { loadDescription(iter->second, stringval); cs->setDescription(stringval.c_str()); } - else if(key == "family") + else if (key == "amf_transform_ids") { load(iter->second, stringval); - cs->setFamily(stringval.c_str()); + cs->setAMFTransformIDs(stringval.c_str()); } - else if(key == "equalitygroup") + else if (key == "icc_profile_name") { load(iter->second, stringval); - cs->setEqualityGroup(stringval.c_str()); - } - else if (key == "interopid") - { - load(iter->second, stringval); - cs->setInteropID(stringval.c_str()); + cs->setICCProfileName(stringval.c_str()); } - else if (key == "amftransformids") + else if(key == "family") { load(iter->second, stringval); - cs->setAmfTransformIDs(stringval.c_str()); + cs->setFamily(stringval.c_str()); } - else if (key == "iccprofilename") + else if(key == "equalitygroup") { load(iter->second, stringval); - cs->setIccProfileName(stringval.c_str()); - } + cs->setEqualityGroup(stringval.c_str()); + } else if(key == "bitdepth") { BitDepth ret; @@ -3339,33 +3339,36 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int major out << YAML::Flow << YAML::Value << aliases; } - out << YAML::Key << "family" << YAML::Value << cs->getFamily(); - out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup(); - - const std::string interopID{cs->getInteropID()}; - if (!interopID.empty()) + const std::string interopID{ cs->getInteropID() }; + if (!interopID.empty()) { - out << YAML::Key << "interopid"; + out << YAML::Key << "interop_id"; out << YAML::Value << interopID; } - const std::string amfTransformIDs{cs->getAmfTransformIDs()}; + out << YAML::Key << "family" << YAML::Value << cs->getFamily(); + + out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup(); + + out << YAML::Key << "bitdepth" << YAML::Value; + save(out, cs->getBitDepth()); + + saveDescription(out, cs->getDescription()); + + const std::string amfTransformIDs{cs->getAMFTransformIDs()}; if (!amfTransformIDs.empty()) { - out << YAML::Key << "amftransformids"; + out << YAML::Key << "amf_transform_ids"; out << YAML::Value << amfTransformIDs; } - const std::string iccProfileName{cs->getIccProfileName()}; + const std::string iccProfileName{cs->getICCProfileName()}; if (!iccProfileName.empty()) { - out << YAML::Key << "iccprofilename"; + out << YAML::Key << "icc_profile_name"; out << YAML::Value << iccProfileName; } - out << YAML::Key << "bitdepth" << YAML::Value; - save(out, cs->getBitDepth()); - saveDescription(out, cs->getDescription()); out << YAML::Key << "isdata" << YAML::Value << cs->isData(); if(cs->getNumCategories() > 0) @@ -4792,10 +4795,12 @@ inline void save(YAML::Emitter & out, const Config & config) { std::stringstream ss; const unsigned configMajorVersion = config.getMajorVersion(); + const unsigned configMinorVersion = config.getMinorVersion(); + ss << configMajorVersion; - if(config.getMinorVersion()!=0) + if(configMinorVersion != 0) { - ss << "." << config.getMinorVersion(); + ss << "." << configMinorVersion; } out << YAML::Block; diff --git a/src/OpenColorIO/Platform.cpp b/src/OpenColorIO/Platform.cpp index 08491bb981..0e7fc68b2d 100644 --- a/src/OpenColorIO/Platform.cpp +++ b/src/OpenColorIO/Platform.cpp @@ -156,7 +156,7 @@ int Strcasecmp(const char * str1, const char * str2) { if (!str1 || !str2) { - throw Exception("nullptr is passed."); + throw Exception("String pointer for comparison must not be null."); } #ifdef _WIN32 @@ -170,7 +170,7 @@ int Strncasecmp(const char * str1, const char * str2, size_t n) { if (!str1 || !str2) { - throw Exception("nullptr is passed."); + throw Exception("String pointer for comparison must not be null."); } #ifdef _WIN32 diff --git a/src/bindings/java/JNIColorSpace.cpp b/src/bindings/java/JNIColorSpace.cpp index fde8690b6a..777d80a6f1 100644 --- a/src/bindings/java/JNIColorSpace.cpp +++ b/src/bindings/java/JNIColorSpace.cpp @@ -145,24 +145,6 @@ Java_org_OpenColorIO_ColorSpace_setAmfTransformIDs(JNIEnv * env, jobject self, j OCIO_JNITRY_EXIT() } -JNIEXPORT jstring JNICALL -Java_org_OpenColorIO_ColorSpace_getIccProfileName(JNIEnv * env, jobject self) -{ - OCIO_JNITRY_ENTER() - ConstColorSpaceRcPtr col = GetConstJOCIO(env, self); - return env->NewStringUTF(col->getIccProfileName()); - OCIO_JNITRY_EXIT(NULL) -} - -JNIEXPORT void JNICALL -Java_org_OpenColorIO_ColorSpace_setIccProfileName(JNIEnv * env, jobject self, jstring iccProfileName) -{ - OCIO_JNITRY_ENTER() - ColorSpaceRcPtr col = GetEditableJOCIO(env, self); - col->setIccProfileName(GetJStringValue(env, iccProfileName)()); - OCIO_JNITRY_EXIT() -} - JNIEXPORT jobject JNICALL Java_org_OpenColorIO_ColorSpace_getBitDepth(JNIEnv * env, jobject self) { diff --git a/src/bindings/java/org/OpenColorIO/ColorSpace.java b/src/bindings/java/org/OpenColorIO/ColorSpace.java index 783b15c558..c875325e1a 100644 --- a/src/bindings/java/org/OpenColorIO/ColorSpace.java +++ b/src/bindings/java/org/OpenColorIO/ColorSpace.java @@ -24,8 +24,6 @@ public class ColorSpace extends LoadLibrary public native void setInteropID(String interopID); public native String getAmfTransformIDs(); public native void setAmfTransformIDs(String amfTransformIDs); - public native String getIccProfileName(); - public native void setIccProfileName(String iccProfileName); public native BitDepth getBitDepth(); public native void setBitDepth(BitDepth bitDepth); public native boolean isData(); diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index 3cd6b538bc..a2981fdf93 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -197,13 +197,13 @@ void bindPyColorSpace(py::module & m) DOC(ColorSpace, getInteropID)) .def("setInteropID", &ColorSpace::setInteropID, "interopID"_a, DOC(ColorSpace, setInteropID)) - .def("getAmfTransformIDs", &ColorSpace::getAmfTransformIDs, + .def("getAMFTransformIDs", &ColorSpace::getAMFTransformIDs, DOC(ColorSpace, getAmfTransformIDs)) - .def("setAmfTransformIDs", &ColorSpace::setAmfTransformIDs, "amfTransformIDs"_a, + .def("setAMFTransformIDs", &ColorSpace::setAMFTransformIDs, "amfTransformIDs"_a, DOC(ColorSpace, setAmfTransformIDs)) - .def("getIccProfileName", &ColorSpace::getIccProfileName, + .def("getICCProfileName", &ColorSpace::getICCProfileName, DOC(ColorSpace, getIccProfileName)) - .def("setIccProfileName", &ColorSpace::setIccProfileName, "iccProfileName"_a, + .def("setICCProfileName", &ColorSpace::setICCProfileName, "iccProfileName"_a, DOC(ColorSpace, setIccProfileName)) .def("getBitDepth", &ColorSpace::getBitDepth, DOC(ColorSpace, getBitDepth)) diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 07e0566a44..dbaff1ecf5 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -46,8 +46,9 @@ OCIO_ADD_TEST(ColorSpace, basic) OCIO_CHECK_NO_THROW(cs->setFamily(nullptr)); OCIO_CHECK_NO_THROW(cs->setEqualityGroup(nullptr)); OCIO_CHECK_NO_THROW(cs->setEncoding(nullptr)); - OCIO_CHECK_NO_THROW(cs->setAmfTransformIDs(nullptr)); + OCIO_CHECK_NO_THROW(cs->setAMFTransformIDs(nullptr)); OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); + OCIO_CHECK_NO_THROW(cs->setICCProfileName(nullptr)); // Test set/get roundtrip. cs->setName("name"); @@ -636,7 +637,6 @@ active_views: [] name: raw family: raw equalitygroup: "" - interopid: srgb_texture bitdepth: 32f description: Some text. isdata: true @@ -646,7 +646,6 @@ active_views: [] name: bar family: raw equalitygroup: "" - interopid: acescg_texture bitdepth: 32f description: | One line. @@ -674,13 +673,11 @@ active_views: [] OCIO_REQUIRE_ASSERT(cs); // Description has no trailing \n. OCIO_CHECK_EQUAL(std::string(cs->getDescription()), "Some text."); - OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), "srgb_texture"); cs = config->getColorSpace(config->getColorSpaceNameByIndex(1)); OCIO_REQUIRE_ASSERT(cs); // Description has no trailing \n. OCIO_CHECK_EQUAL(std::string(cs->getDescription()), "One line.\n\nOther line."); - OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), "acescg_texture"); // Save and compare output with input. @@ -689,37 +686,87 @@ active_views: [] OCIO_CHECK_EQUAL(cfgString, os.str()); } + + // Test that the interop_id can't be used in v2.0 config + { + constexpr char End[]{R"(colorspaces: + - ! + name: raw + interop_id: data + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + std::string cfgString{Start}; + cfgString += End; - // Test the serialize/deserialize process using interop_id. - auto cfg = OCIO::Config::Create(); - auto cs = OCIO::ColorSpace::Create(); - cs->setName("testing"); - const std::string interopID{ "linear_srgb" }; - cs->setInteropID(interopID.c_str()); - cfg->addColorSpace(cs); - - // Serialize the Config. - std::ostringstream os; - cfg->serialize(os); + // Load config. - // Deserialize and compare. std::istringstream is; - is.str(os.str()); - auto cfg2 = OCIO::Config::CreateFromStream(is); - OCIO_CHECK_EQUAL(cfg2->getNumColorSpaces(), 1); - auto cs2 = cfg2->getColorSpace("testing"); - OCIO_CHECK_EQUAL(std::string(cs2->getInteropID()), interopID); - - // Test another valid interop ID. - cs->setInteropID("linear_display_p3"); - cfg->addColorSpace(cs); - os.str(""); - cfg->serialize(os); - is.str(os.str()); - cfg2 = OCIO::Config::CreateFromStream(is); - cs2 = cfg2->getColorSpace("testing"); - OCIO_CHECK_EQUAL(std::string(cs2->getInteropID()), "linear_display_p3"); - + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_THROW_WHAT( + config = OCIO::Config::CreateFromStream(is), + OCIO::Exception, + "Config failed validation. The color space 'raw' has non-empty InteropID and config version is less than 2.5."); + } + + // Test that the amf_transform_ids can't be used in v2.0 config + { + constexpr char End[]{R"(colorspaces: + - ! + name: raw + amf_transform_ids: this:shouldnt:be:here + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + std::string cfgString{Start}; + cfgString += End; + + // Load config. + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_THROW_WHAT( + config = OCIO::Config::CreateFromStream(is), OCIO::Exception, + "Config failed validation. The color space 'raw' has non-empty " + "AMFTransformIDs and config version is less than 2.5."); + } + + // Test that the icc_profile_name can't be used in v2.0 config + { + constexpr char End[]{R"(colorspaces: + - ! + name: raw + icc_profile_name: not valid in v2.0 config + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + std::string cfgString{Start}; + cfgString += End; + + // Load config. + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_THROW_WHAT( + config = OCIO::Config::CreateFromStream(is), OCIO::Exception, + "Config failed validation. The color space 'raw' has non-empty " + "ICCProfileName and config version is less than 2.5."); + } } OCIO_ADD_TEST(Config, use_alias) @@ -1804,58 +1851,119 @@ inactive_colorspaces: [scene-linear Rec.709-sRGB, ACES2065-1] } } -/* OCIO_ADD_TEST(ColorSpace, interop_id) { - auto cs = OCIO::ColorSpace::Create(); + OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); + + // Test default value OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); - const std::string interopID{ "srgb_texture" }; - cs->setInteropID(interopID.c_str()); - OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), interopID); + // Test setting and getting single profile name + const char * interop_id = "srgb_p3d65_scene"; + cs->setInteropID(interop_id); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), interop_id); + + // Test setting empty string + cs->setInteropID(""); + OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); - // Test another valid interop ID - const std::string interopID2{ "acescg_texture" }; - cs->setInteropID(interopID2.c_str()); - OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), interopID2); + // Test setting and getting another value + const char * anotherID= "lin_rec2020_scene"; + cs->setInteropID(anotherID); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), anotherID); - cs->setInteropID(nullptr); + // Test setting null pointer (should be safe) + OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); + + // Test copy constructor preserves ICC profile name + cs->setInteropID(interop_id); + OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); + OCIO_CHECK_EQUAL(std::string(copy->getInteropID()), interop_id); +} + +OCIO_ADD_TEST(ColorSpace, interop_id_serialization) +{ + // Test YAML serialization and deserialization of InteropID + auto cfg = OCIO::Config::Create(); + auto cs = OCIO::ColorSpace::Create(); + cs->setName("test_colorspace"); + + const std::string interop_id = "lin_rec709_scene"; + + cs->setInteropID(interop_id.c_str()); + cfg->addColorSpace(cs); + + // Serialize the Config + std::stringstream ss; + cfg->serialize(ss); + std::string yamlStr = ss.str(); + + // Verify interop_id appears in YAML + OCIO_CHECK_NE(yamlStr.find("interop_id"), std::string::npos); + OCIO_CHECK_NE(yamlStr.find(interop_id), std::string::npos); + + // Deserialize and verify + std::istringstream iss(yamlStr); + OCIO::ConstConfigRcPtr deserializedCfg; + OCIO_CHECK_NO_THROW(deserializedCfg = OCIO::Config::CreateFromStream(iss)); + + // Verify interop_id is preserved + OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); + OCIO_CHECK_EQUAL(std::string(deserializedCs->getInteropID()), interop_id); + + // verify that that earlier versions reject interop_id + OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); + cfgCopy->setVersion(2, 4); + OCIO_CHECK_THROW_WHAT( + cfgCopy->serialize(ss), + OCIO::Exception, + "Config failed validation. The color space 'test_colorspace' has non-empty " + "InteropID and config version is less than 2.5."); + + // Test with empty interop_id (should not appear in YAML) + cs->setInteropID(nullptr); + cfg->addColorSpace(cs); // replace the existing CS + ss.str(""); + cfg->serialize(ss); + std::string yamlStr2 = ss.str(); + + // Verify empty imterop_id does not appear in YAML + OCIO_CHECK_EQUAL(yamlStr2.find("interop_id"), std::string::npos); } -*/ OCIO_ADD_TEST(ColorSpace, amf_transform_ids) { OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); // Test default value - OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), ""); + OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), ""); // Test setting and getting single ID const char * singleID = "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3"; - cs->setAmfTransformIDs(singleID); - OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), singleID); + cs->setAMFTransformIDs(singleID); + OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), singleID); + // Test setting to empty string + cs->setAMFTransformIDs(""); + OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), ""); + // Test setting and getting multiple IDs const char * multipleIDs = "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3\n" "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3"; - cs->setAmfTransformIDs(multipleIDs); - OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), multipleIDs); - - // Test setting to empty string - cs->setAmfTransformIDs(""); - OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), ""); + cs->setAMFTransformIDs(multipleIDs); + OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), multipleIDs); // Test setting to nullptr cs->setDescription(nullptr); - cs->setAmfTransformIDs(nullptr); - OCIO_CHECK_EQUAL(std::string(cs->getAmfTransformIDs()), ""); + cs->setAMFTransformIDs(nullptr); + OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), ""); // Test copy constructor preserves AMF transform IDs - cs->setAmfTransformIDs(singleID); + cs->setAMFTransformIDs(singleID); OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); - OCIO_CHECK_EQUAL(std::string(copy->getAmfTransformIDs()), singleID); + OCIO_CHECK_EQUAL(std::string(copy->getAMFTransformIDs()), singleID); } OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) @@ -1869,7 +1977,7 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3\n" "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3"; - cs->setAmfTransformIDs(amfIDs.c_str()); + cs->setAMFTransformIDs(amfIDs.c_str()); cfg->addColorSpace(cs); // Serialize the Config @@ -1878,7 +1986,7 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) std::string yamlStr = ss.str(); // Verify AmfTransformIDs appears in YAML - OCIO_CHECK_NE(yamlStr.find("amftransformids"), std::string::npos); + OCIO_CHECK_NE(yamlStr.find("amf_transform_ids"), std::string::npos); OCIO_CHECK_NE(yamlStr.find("ACEScsc.Academy.ACEScc_to_ACES"), std::string::npos); // Deserialize and verify @@ -1888,17 +1996,25 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) // Verify AmfTransformIDs is preserved OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); - OCIO_CHECK_EQUAL(std::string(deserializedCs->getAmfTransformIDs()), amfIDs); + OCIO_CHECK_EQUAL(std::string(deserializedCs->getAMFTransformIDs()), amfIDs); + + // verify that that earlier versions reject amf_transform_ids + OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); + cfgCopy->setVersion(2,4); + OCIO_CHECK_THROW_WHAT(cfgCopy->serialize(ss), + OCIO::Exception, + "Config failed validation. The color space 'test_colorspace' has non-empty " + "AMFTransformIDs and config version is less than 2.5."); // Test with empty AmfTransformIDs (should not appear in YAML) - cs->setAmfTransformIDs(""); + cs->setAMFTransformIDs(nullptr); cfg->addColorSpace(cs); // replace the existing CS ss.str(""); cfg->serialize(ss); std::string yamlStr2 = ss.str(); // Verify empty AmfTransformIDs does not appear in YAML - OCIO_CHECK_EQUAL(yamlStr2.find("amftransformids"), std::string::npos); + OCIO_CHECK_EQUAL(yamlStr2.find("amf_transform_ids"), std::string::npos); } OCIO_ADD_TEST(ColorSpace, icc_profile_name) @@ -1906,30 +2022,30 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name) OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); // Test default value - OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), ""); + OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); // Test setting and getting single profile name const char * profileName = "sRGB IEC61966-2.1"; - cs->setIccProfileName(profileName); - OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), profileName); + cs->setICCProfileName(profileName); + OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), profileName); // Test setting and getting another profile name const char * anotherProfile = "Adobe RGB (1998)"; - cs->setIccProfileName(anotherProfile); - OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), anotherProfile); + cs->setICCProfileName(anotherProfile); + OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), anotherProfile); // Test setting empty string - cs->setIccProfileName(""); - OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), ""); + cs->setICCProfileName(""); + OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); // Test setting null pointer (should be safe) - OCIO_CHECK_NO_THROW(cs->setIccProfileName(nullptr)); - OCIO_CHECK_EQUAL(std::string(cs->getIccProfileName()), ""); + OCIO_CHECK_NO_THROW(cs->setICCProfileName(nullptr)); + OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); // Test copy constructor preserves ICC profile name - cs->setIccProfileName(profileName); + cs->setICCProfileName(profileName); OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); - OCIO_CHECK_EQUAL(std::string(copy->getIccProfileName()), profileName); + OCIO_CHECK_EQUAL(std::string(copy->getICCProfileName()), profileName); } OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) @@ -1941,7 +2057,7 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) const std::string profileName = "sRGB IEC61966-2.1"; - cs->setIccProfileName(profileName.c_str()); + cs->setICCProfileName(profileName.c_str()); cfg->addColorSpace(cs); // Serialize the Config @@ -1950,7 +2066,7 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) std::string yamlStr = ss.str(); // Verify IccProfileName appears in YAML - OCIO_CHECK_NE(yamlStr.find("iccprofilename"), std::string::npos); + OCIO_CHECK_NE(yamlStr.find("icc_profile_name"), std::string::npos); OCIO_CHECK_NE(yamlStr.find(profileName), std::string::npos); // Deserialize and verify @@ -1960,15 +2076,24 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) // Verify IccProfileName is preserved OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); - OCIO_CHECK_EQUAL(std::string(deserializedCs->getIccProfileName()), profileName); + OCIO_CHECK_EQUAL(std::string(deserializedCs->getICCProfileName()), profileName); + + // verify that that earlier versions reject amf_transform_ids + OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); + cfgCopy->setVersion(2, 4); + OCIO_CHECK_THROW_WHAT( + cfgCopy->serialize(ss), + OCIO::Exception, + "Config failed validation. The color space 'test_colorspace' has non-empty " + "ICCProfileName and config version is less than 2.5."); // Test with empty IccProfileName (should not appear in YAML) - cs->setIccProfileName(""); + cs->setICCProfileName(nullptr); cfg->addColorSpace(cs); // replace the existing CS ss.str(""); cfg->serialize(ss); std::string yamlStr2 = ss.str(); // Verify empty IccProfileName does not appear in YAML - OCIO_CHECK_EQUAL(yamlStr2.find("iccprofilename"), std::string::npos); + OCIO_CHECK_EQUAL(yamlStr2.find("icc_profile_name"), std::string::npos); } \ No newline at end of file diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 518b97275b..e3764a3906 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -2093,12 +2093,12 @@ OCIO_ADD_TEST(Config, version) { OCIO_CHECK_THROW_WHAT(config->setVersion(2, 9), OCIO::Exception, "The minor version 9 is not supported for major version 2. " - "Maximum minor version is 4"); + "Maximum minor version is 5"); OCIO_CHECK_NO_THROW(config->setMajorVersion(2)); OCIO_CHECK_THROW_WHAT(config->setMinorVersion(9), OCIO::Exception, "The minor version 9 is not supported for major version 2. " - "Maximum minor version is 4"); + "Maximum minor version is 5"); } { diff --git a/tests/python/ColorSpaceTest.py b/tests/python/ColorSpaceTest.py index 0860e7a3f0..3c595f1715 100644 --- a/tests/python/ColorSpaceTest.py +++ b/tests/python/ColorSpaceTest.py @@ -42,6 +42,9 @@ def test_copy(self): self.colorspace.setTransform(direction=OCIO.COLORSPACE_DIR_FROM_REFERENCE, transform=mat) self.colorspace.addAlias('alias') self.colorspace.addCategory('cat') + self.colorspace.setInteropID('ACEScg') + self.colorspace.setAMFTransformIDs('urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3') + self.colorspace.setICCProfileName('sRGB IEC61966-2.1') other = copy.deepcopy(self.colorspace) self.assertFalse(other is self.colorspace) @@ -59,6 +62,9 @@ def test_copy(self): self.assertTrue(other.getTransform(OCIO.COLORSPACE_DIR_FROM_REFERENCE).equals(self.colorspace.getTransform(OCIO.COLORSPACE_DIR_FROM_REFERENCE))) self.assertEqual(list(other.getAliases()), list(self.colorspace.getAliases())) self.assertEqual(list(other.getCategories()), list(self.colorspace.getCategories())) + self.assertEqual(other.getInteropID(), self.colorspace.getInteropID()) + self.assertEqual(other.getAMFTransformIDs(), self.colorspace.getAMFTransformIDs()) + self.assertEqual(other.getICCProfileName(), self.colorspace.getICCProfileName()) def test_allocation(self): """ @@ -279,6 +285,9 @@ def test_constructor_without_parameter(self): self.assertFalse(cs.isData()) self.assertEqual(cs.getAllocation(), OCIO.ALLOCATION_UNIFORM) self.assertEqual(cs.getAllocationVars(), []) + self.assertEqual(cs.getInteropID(), '') + self.assertEqual(cs.getAMFTransformIDs(), '') + self.assertEqual(cs.getICCProfileName(), '') def test_data(self): """ @@ -384,8 +393,6 @@ def test_aliases(self): cs.addAlias('Alias2') aliases = cs.getAliases() self.assertEqual(len(aliases), 2) - self.assertEqual(aliases[0], 'alias1') - self.assertEqual(aliases[1], 'alias2') # Name might remove an alias. @@ -632,9 +639,135 @@ def test_display_referred(self, cfg, cs_name, expected_value): test_display_referred(self, cfg, "scene_linear-trans-alias", False) test_display_referred(self, cfg, "scene_ref", False) + def test_interop_id(self): + """ + Test the setInteropID() and getInteropID() methods. + """ + + # Test default value (should be empty) + self.assertEqual(self.colorspace.getInteropID(), '') + + # Test setting and getting a simple interop ID + test_id = 'lin_ap0_scene' + self.colorspace.setInteropID(test_id) + self.assertEqual(self.colorspace.getInteropID(), test_id) + + # Test setting and getting a different interop ID + test_id2 = 'srgb_ap1_scene' + self.colorspace.setInteropID(test_id2) + self.assertEqual(self.colorspace.getInteropID(), test_id2) + + # Test setting empty string + self.colorspace.setInteropID('') + self.assertEqual(self.colorspace.getInteropID(), '') + + # Test setting None (should convert to empty string) + self.colorspace.setInteropID(None) + self.assertEqual(self.colorspace.getInteropID(), '') + + # Test wrong type (should raise TypeError) + with self.assertRaises(TypeError): + self.colorspace.setInteropID(123) + + with self.assertRaises(TypeError): + self.colorspace.setInteropID(['list']) + + def test_amf_transform_ids(self): + """ + Test the setAMFTransformIDs() and getAMFTransformIDs() methods. + """ + + # Test default value (should be empty) + self.assertEqual(self.colorspace.getAMFTransformIDs(), '') + + # Test setting and getting a single transform ID + single_id = 'urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3' + self.colorspace.setAMFTransformIDs(single_id) + self.assertEqual(self.colorspace.getAMFTransformIDs(), single_id) + + # Test setting and getting multiple transform IDs (newline-separated) + multiple_ids = ('urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3\n' + 'urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_CG.a1.0.3\n' + 'urn:ampas:aces:transformId:v1.5:RRT.a1.0.3') + self.colorspace.setAMFTransformIDs(multiple_ids) + self.assertEqual(self.colorspace.getAMFTransformIDs(), multiple_ids) + + # Test setting empty string + self.colorspace.setAMFTransformIDs('') + self.assertEqual(self.colorspace.getAMFTransformIDs(), '') + + # Test setting None (should convert to empty string) + self.colorspace.setAMFTransformIDs(None) + self.assertEqual(self.colorspace.getAMFTransformIDs(), '') + + # Test with different line endings + mixed_endings = 'id1\nid2\rid3\r\nid4' + self.colorspace.setAMFTransformIDs(mixed_endings) + self.assertEqual(self.colorspace.getAMFTransformIDs(), mixed_endings) + + # Test with leading/trailing whitespace + whitespace_ids = ' \n id1 \n id2 \n ' + self.colorspace.setAMFTransformIDs(whitespace_ids) + self.assertEqual(self.colorspace.getAMFTransformIDs(), whitespace_ids) + + # Test wrong type (should raise TypeError) + with self.assertRaises(TypeError): + self.colorspace.setAMFTransformIDs(123) + + with self.assertRaises(TypeError): + self.colorspace.setAMFTransformIDs(['list', 'of', 'ids']) + + def test_icc_profile_name(self): + """ + Test the setICCProfileName() and getICCProfileName() methods. + """ + + # Test default value (should be empty) + self.assertEqual(self.colorspace.getICCProfileName(), '') + + # Test setting and getting a simple profile name + profile_name = 'sRGB IEC61966-2.1' + self.colorspace.setICCProfileName(profile_name) + self.assertEqual(self.colorspace.getICCProfileName(), profile_name) + + # Test setting and getting a different profile name + profile_name2 = 'Adobe RGB (1998)' + self.colorspace.setICCProfileName(profile_name2) + self.assertEqual(self.colorspace.getICCProfileName(), profile_name2) + + # Test with a more complex profile name + complex_name = 'Display P3 - Apple Cinema Display (Calibrated 2023-01-15)' + self.colorspace.setICCProfileName(complex_name) + self.assertEqual(self.colorspace.getICCProfileName(), complex_name) + + # Test setting empty string + self.colorspace.setICCProfileName('') + self.assertEqual(self.colorspace.getICCProfileName(), '') + + # Test setting None (should convert to empty string) + self.colorspace.setICCProfileName(None) + self.assertEqual(self.colorspace.getICCProfileName(), '') + + # Test with special characters and numbers + special_name = 'ProPhoto RGB v2.0 (γ=1.8) [Custom Profile #123]' + self.colorspace.setICCProfileName(special_name) + self.assertEqual(self.colorspace.getICCProfileName(), special_name) + + # Test with Unicode characters + unicode_name = 'Профиль RGB γ=2.2' + self.colorspace.setICCProfileName(unicode_name) + self.assertEqual(self.colorspace.getICCProfileName(), unicode_name) + + # Test wrong type (should raise TypeError) + with self.assertRaises(TypeError): + self.colorspace.setICCProfileName(123) + + with self.assertRaises(TypeError): + self.colorspace.setICCProfileName(['profile', 'name']) + def test_processor_to_known_colorspace(self): - CONFIG = """ocio_profile_version: 2 + CONFIG = """ocio_profile_version: 2.5 roles: default: raw @@ -690,12 +823,14 @@ def test_processor_to_known_colorspace(self): - ! name: ACES cg description: An ACEScg space with an unusual spelling. + interop_id: lin_ap1_scene isdata: false to_scene_reference: ! {style: ACEScg_to_ACES2065-1} - ! name: Linear ITU-R BT.709 description: A linear Rec.709 space with an unusual spelling. + interop_id: lin_rec709_scene isdata: false from_scene_reference: ! name: AP0 to Linear Rec.709 (sRGB) From 295f965e3fce2253182cfcd7953bca02a223dc66 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 4 Jun 2025 15:33:39 -0700 Subject: [PATCH 05/16] updated the ColorSpace << operator and the unit test to have the newly added fields. Signed-off-by: cuneyt.ozdas --- src/OpenColorIO/ColorSpace.cpp | 20 +++++++++++++++++++- tests/cpu/ColorSpace_tests.cpp | 9 ++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/OpenColorIO/ColorSpace.cpp b/src/OpenColorIO/ColorSpace.cpp index 952146fc9c..7a57c0779f 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -407,7 +407,6 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) break; } os << "name=" << cs.getName() << ", "; - std::string str{ cs.getFamily() }; const auto numAliases = cs.getNumAliases(); if (numAliases == 1) { @@ -422,6 +421,15 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) } os << "], "; } + + std::string str; + + str = cs.getInteropID(); + if (!str.empty()) + { + os << "interop_id=" << str << ", "; + } + str = cs.getFamily(); if (!str.empty()) { os << "family=" << str << ", "; @@ -465,6 +473,16 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) { os << ", description=" << str; } + str = cs.getAMFTransformIDs(); + if (!str.empty()) + { + os << ", amf_transform_ids=" << str; + } + str = cs.getICCProfileName(); + if (!str.empty()) + { + os << ", icc_profile_name=" << str; + } if(cs.getTransform(COLORSPACE_DIR_TO_REFERENCE)) { os << ",\n " << cs.getName() << " --> Reference"; diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index dbaff1ecf5..4620c887c1 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -74,10 +74,17 @@ OCIO_ADD_TEST(ColorSpace, basic) cs->getAllocationVars(readVars); OCIO_CHECK_EQUAL(1.f, readVars[0]); OCIO_CHECK_EQUAL(2.f, readVars[1]); + cs->setInteropID("interop_id"); + OCIO_CHECK_EQUAL(std::string("interop_id"), cs->getInteropID()); + cs->setAMFTransformIDs("amf_transform_id1\namf_tranform_id2"); + OCIO_CHECK_EQUAL(std::string("amf_transform_id1\namf_tranform_id2"), + cs->getAMFTransformIDs()); + cs->setICCProfileName("icc_profile_name"); + OCIO_CHECK_EQUAL(std::string("icc_profile_name"), cs->getICCProfileName()); std::ostringstream oss; oss << *cs; - OCIO_CHECK_EQUAL(oss.str().size(), 193); + OCIO_CHECK_EQUAL(oss.str().size(), 305); } OCIO_ADD_TEST(ColorSpace, alias) From 1e08d6b890e275a024ea47fd6e37c0bce9b3dce9 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 4 Jun 2025 17:55:54 -0700 Subject: [PATCH 06/16] - unbreaking the doc builds by fixing the function name cases in the macros. Signed-off-by: cuneyt.ozdas --- src/bindings/python/PyColorSpace.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index a2981fdf93..eb8492fea5 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -198,13 +198,13 @@ void bindPyColorSpace(py::module & m) .def("setInteropID", &ColorSpace::setInteropID, "interopID"_a, DOC(ColorSpace, setInteropID)) .def("getAMFTransformIDs", &ColorSpace::getAMFTransformIDs, - DOC(ColorSpace, getAmfTransformIDs)) + DOC(ColorSpace, getAMFTransformIDs)) .def("setAMFTransformIDs", &ColorSpace::setAMFTransformIDs, "amfTransformIDs"_a, - DOC(ColorSpace, setAmfTransformIDs)) + DOC(ColorSpace, setAMFTransformIDs)) .def("getICCProfileName", &ColorSpace::getICCProfileName, - DOC(ColorSpace, getIccProfileName)) + DOC(ColorSpace, getICCProfileName)) .def("setICCProfileName", &ColorSpace::setICCProfileName, "iccProfileName"_a, - DOC(ColorSpace, setIccProfileName)) + DOC(ColorSpace, setICCProfileName)) .def("getBitDepth", &ColorSpace::getBitDepth, DOC(ColorSpace, getBitDepth)) .def("setBitDepth", &ColorSpace::setBitDepth, "bitDepth"_a, From 99af0008452f2d8867af7d8c7130d2d742d79112 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 4 Jun 2025 18:27:17 -0700 Subject: [PATCH 07/16] removing the rest of the changes in the frozen docs. Signed-off-by: cuneyt.ozdas --- .../frozen/pyopencolorio_colorspace.rst | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/docs/api/python/frozen/pyopencolorio_colorspace.rst b/docs/api/python/frozen/pyopencolorio_colorspace.rst index 13bc65538f..5a6adf8d99 100644 --- a/docs/api/python/frozen/pyopencolorio_colorspace.rst +++ b/docs/api/python/frozen/pyopencolorio_colorspace.rst @@ -214,32 +214,6 @@ Specify the transform for the appropriate direction. Setting the transform to null will clear it. - .. py:method:: ColorSpace.getInteropID(self: PyOpenColorIO.ColorSpace) -> str - :module: PyOpenColorIO - - - .. py:method:: ColorSpace.setInteropID(self: PyOpenColorIO.ColorSpace, interopID: str) -> None - :module: PyOpenColorIO - - - .. py:method:: ColorSpace.getAmfTransformIDs(self: PyOpenColorIO.ColorSpace) -> str - :module: PyOpenColorIO - - Get the AMF transform IDs for the color space. - - The AMF transform IDs are used to identify specific transforms in the ACES Metadata File. - Multiple transform IDs can be specified in a newline-separated string. - - - .. py:method:: ColorSpace.setAmfTransformIDs(self: PyOpenColorIO.ColorSpace, amfTransformIDs: str) -> None - :module: PyOpenColorIO - - Set the AMF transform IDs for the color space. - - Args: - amfTransformIDs (str): A newline-separated string of AMF transform IDs. - - .. py:class:: ColorSpaceCategoryIterator :module: PyOpenColorIO.ColorSpace From 0d3b302865b1816d27f5126b80a89a6de41ec8f8 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 4 Jun 2025 18:47:16 -0700 Subject: [PATCH 08/16] removing the leftover java changes Signed-off-by: cuneyt.ozdas --- src/bindings/java/JNIColorSpace.cpp | 36 ------------------- .../java/org/OpenColorIO/ColorSpace.java | 4 --- 2 files changed, 40 deletions(-) diff --git a/src/bindings/java/JNIColorSpace.cpp b/src/bindings/java/JNIColorSpace.cpp index 777d80a6f1..423da186cc 100644 --- a/src/bindings/java/JNIColorSpace.cpp +++ b/src/bindings/java/JNIColorSpace.cpp @@ -109,42 +109,6 @@ Java_org_OpenColorIO_ColorSpace_setDescription(JNIEnv * env, jobject self, jstri OCIO_JNITRY_EXIT() } -JNIEXPORT jstring JNICALL -Java_org_OpenColorIO_ColorSpace_getInteropID(JNIEnv * env, jobject self) -{ - OCIO_JNITRY_ENTER() - ConstColorSpaceRcPtr col = GetConstJOCIO(env, self); - return env->NewStringUTF(col->getInteropID()); - OCIO_JNITRY_EXIT(NULL) -} - -JNIEXPORT void JNICALL -Java_org_OpenColorIO_ColorSpace_setInteropID(JNIEnv * env, jobject self, jstring interopID) -{ - OCIO_JNITRY_ENTER() - ColorSpaceRcPtr col = GetEditableJOCIO(env, self); - col->setInteropID(GetJStringValue(env, interopID)()); - OCIO_JNITRY_EXIT() -} - -JNIEXPORT jstring JNICALL -Java_org_OpenColorIO_ColorSpace_getAmfTransformIDs(JNIEnv * env, jobject self) -{ - OCIO_JNITRY_ENTER() - ConstColorSpaceRcPtr col = GetConstJOCIO(env, self); - return env->NewStringUTF(col->getAmfTransformIDs()); - OCIO_JNITRY_EXIT(NULL) -} - -JNIEXPORT void JNICALL -Java_org_OpenColorIO_ColorSpace_setAmfTransformIDs(JNIEnv * env, jobject self, jstring amfTransformIDs) -{ - OCIO_JNITRY_ENTER() - ColorSpaceRcPtr col = GetEditableJOCIO(env, self); - col->setAmfTransformIDs(GetJStringValue(env, amfTransformIDs)()); - OCIO_JNITRY_EXIT() -} - JNIEXPORT jobject JNICALL Java_org_OpenColorIO_ColorSpace_getBitDepth(JNIEnv * env, jobject self) { diff --git a/src/bindings/java/org/OpenColorIO/ColorSpace.java b/src/bindings/java/org/OpenColorIO/ColorSpace.java index c875325e1a..9950bee93d 100644 --- a/src/bindings/java/org/OpenColorIO/ColorSpace.java +++ b/src/bindings/java/org/OpenColorIO/ColorSpace.java @@ -20,10 +20,6 @@ public class ColorSpace extends LoadLibrary public native void setEqualityGroup(String equalityGroup); public native String getDescription(); public native void setDescription(String description); - public native String getInteropID(); - public native void setInteropID(String interopID); - public native String getAmfTransformIDs(); - public native void setAmfTransformIDs(String amfTransformIDs); public native BitDepth getBitDepth(); public native void setBitDepth(BitDepth bitDepth); public native boolean isData(); From 4e24d3219f7e4cf83c73329f9ecf540dc14a933a Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Wed, 4 Jun 2025 21:28:52 -0700 Subject: [PATCH 09/16] Minor code and test cleanup Signed-off-by: cuneyt.ozdas --- src/OpenColorIO/Config.cpp | 1 - tests/cpu/ColorSpace_tests.cpp | 120 ++++++++------------------------- 2 files changed, 29 insertions(+), 92 deletions(-) diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index 3f368f123a..1e17b25eb5 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -5514,7 +5514,6 @@ void Config::Impl::checkVersionConsistency() const if (hexVersion < 0x02050000) // Version 2.5 { - const std::string interopID{cs->getInteropID()}; if (*cs->getInteropID()) { std::ostringstream os; diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 4620c887c1..9a6f55729c 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -638,92 +638,34 @@ active_views: [] OCIO_CHECK_EQUAL(cfgRes, os.str()); } + // Test that the interop_id can't be used in v2.0 config { - constexpr char End[]{ R"(colorspaces: + constexpr char End[]{R"(colorspaces: - ! name: raw + interop_id: data family: raw equalitygroup: "" bitdepth: 32f description: Some text. isdata: true allocation: uniform - - - ! - name: bar - family: raw - equalitygroup: "" - bitdepth: 32f - description: | - One line. - - Other line. - isdata: true - allocation: uniform -)" }; - std::string cfgString{ Start }; +)"}; + std::string cfgString{Start}; cfgString += End; - // Load config. - std::istringstream is; is.str(cfgString); OCIO::ConstConfigRcPtr config; - OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); - OCIO_REQUIRE_ASSERT(config); - OCIO_CHECK_NO_THROW(config->validate()); - - // Check colorspace. - - OCIO_CHECK_EQUAL(config->getNumColorSpaces(), 2); - OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(config->getColorSpaceNameByIndex(0)); - OCIO_REQUIRE_ASSERT(cs); - // Description has no trailing \n. - OCIO_CHECK_EQUAL(std::string(cs->getDescription()), "Some text."); - - cs = config->getColorSpace(config->getColorSpaceNameByIndex(1)); - OCIO_REQUIRE_ASSERT(cs); - // Description has no trailing \n. - OCIO_CHECK_EQUAL(std::string(cs->getDescription()), "One line.\n\nOther line."); - - // Save and compare output with input. - - std::ostringstream os; - os << *config; - - OCIO_CHECK_EQUAL(cfgString, os.str()); - } - - // Test that the interop_id can't be used in v2.0 config - { - constexpr char End[]{R"(colorspaces: - - ! - name: raw - interop_id: data - family: raw - equalitygroup: "" - bitdepth: 32f - description: Some text. - isdata: true - allocation: uniform -)"}; - std::string cfgString{Start}; - cfgString += End; - - // Load config. - - std::istringstream is; - is.str(cfgString); - OCIO::ConstConfigRcPtr config; - OCIO_CHECK_THROW_WHAT( - config = OCIO::Config::CreateFromStream(is), - OCIO::Exception, - "Config failed validation. The color space 'raw' has non-empty InteropID and config version is less than 2.5."); + OCIO_CHECK_THROW_WHAT( + config = OCIO::Config::CreateFromStream(is), + OCIO::Exception, + "Config failed validation. The color space 'raw' has non-empty InteropID and config version is less than 2.5."); } // Test that the amf_transform_ids can't be used in v2.0 config { - constexpr char End[]{R"(colorspaces: + constexpr char End[]{R"(colorspaces: - ! name: raw amf_transform_ids: this:shouldnt:be:here @@ -734,23 +676,21 @@ active_views: [] isdata: true allocation: uniform )"}; - std::string cfgString{Start}; - cfgString += End; - - // Load config. + std::string cfgString{Start}; + cfgString += End; - std::istringstream is; - is.str(cfgString); - OCIO::ConstConfigRcPtr config; - OCIO_CHECK_THROW_WHAT( - config = OCIO::Config::CreateFromStream(is), OCIO::Exception, - "Config failed validation. The color space 'raw' has non-empty " - "AMFTransformIDs and config version is less than 2.5."); + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_THROW_WHAT( + config = OCIO::Config::CreateFromStream(is), OCIO::Exception, + "Config failed validation. The color space 'raw' has non-empty " + "AMFTransformIDs and config version is less than 2.5."); } // Test that the icc_profile_name can't be used in v2.0 config { - constexpr char End[]{R"(colorspaces: + constexpr char End[]{R"(colorspaces: - ! name: raw icc_profile_name: not valid in v2.0 config @@ -761,18 +701,16 @@ active_views: [] isdata: true allocation: uniform )"}; - std::string cfgString{Start}; - cfgString += End; - - // Load config. + std::string cfgString{Start}; + cfgString += End; - std::istringstream is; - is.str(cfgString); - OCIO::ConstConfigRcPtr config; - OCIO_CHECK_THROW_WHAT( - config = OCIO::Config::CreateFromStream(is), OCIO::Exception, - "Config failed validation. The color space 'raw' has non-empty " - "ICCProfileName and config version is less than 2.5."); + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_THROW_WHAT( + config = OCIO::Config::CreateFromStream(is), OCIO::Exception, + "Config failed validation. The color space 'raw' has non-empty " + "ICCProfileName and config version is less than 2.5."); } } From 8b9b0e7d52a77ee2d02b9641254aebfe8a471642 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Thu, 5 Jun 2025 22:23:38 -0700 Subject: [PATCH 10/16] Addressing the code review requests. Signed-off-by: cuneyt.ozdas --- include/OpenColorIO/OpenColorIO.h | 10 ++- src/bindings/python/PyColorSpace.cpp | 21 +++-- tests/cpu/ColorSpace_tests.cpp | 115 ++++++++++++++++----------- 3 files changed, 89 insertions(+), 57 deletions(-) diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 3a43e3b41e..ea646f7455 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -1917,10 +1917,12 @@ class OCIOEXPORT ColorSpace /** * Get/Set the interop ID for the color space. - * - * The interop ID is a standardized identifier for commonly used color spaces. - * These IDs are defined by the Academy Software Foundation's ColorInterop project - * to standardize color space naming across the industry. + * + * The interop ID is a standardized identifier to uniquely identify commonly + * used color spaces. These IDs are defined by the Academy Software + * Foundation's Color Interop Forum project. If you create your own ID, you + * must prefix it with unique characters that will ensure it won't conflict + * with future Color Interop Forum IDs. */ const char * getInteropID() const noexcept; void setInteropID(const char * interopID); diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index eb8492fea5..b74c98c196 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -90,7 +90,10 @@ void bindPyColorSpace(py::module & m) const std::vector & allocationVars, const TransformRcPtr & toReference, const TransformRcPtr & fromReference, - const std::vector & categories) + const std::vector & categories, + const std::string & interopID, + const std::string& AMFTransformID, + const std::string& ICCProfileName) { ColorSpaceRcPtr p = ColorSpace::Create(referenceSpace); if (!aliases.empty()) @@ -102,11 +105,14 @@ void bindPyColorSpace(py::module & m) } } // Setting the name will remove alias named the same, so set name after. - if (!name.empty()) { p->setName(name.c_str()); } - if (!family.empty()) { p->setFamily(family.c_str()); } - if (!encoding.empty()) { p->setEncoding(encoding.c_str()); } - if (!equalityGroup.empty()) { p->setEqualityGroup(equalityGroup.c_str()); } - if (!description.empty()) { p->setDescription(description.c_str()); } + if (!name.empty()) { p->setName(name.c_str()); } + if (!family.empty()) { p->setFamily(family.c_str()); } + if (!encoding.empty()) { p->setEncoding(encoding.c_str()); } + if (!equalityGroup.empty()) { p->setEqualityGroup(equalityGroup.c_str()); } + if (!description.empty()) { p->setDescription(description.c_str()); } + if (!interopID.empty()) { p->setInteropID(interopID.c_str()); } + if (!AMFTransformID.empty()) { p->setAMFTransformIDs(AMFTransformID.c_str()); } + if (!ICCProfileName.empty()) { p->setICCProfileName(ICCProfileName.c_str()); } p->setBitDepth(bitDepth); p->setIsData(isData); p->setAllocation(allocation); @@ -150,6 +156,9 @@ void bindPyColorSpace(py::module & m) "toReference"_a = DEFAULT->getTransform(COLORSPACE_DIR_TO_REFERENCE), "fromReference"_a = DEFAULT->getTransform(COLORSPACE_DIR_FROM_REFERENCE), "categories"_a = getCategoriesStdVec(DEFAULT), + "interopID"_a = DEFAULT->getInteropID(), + "amfTransformIDs"_a = DEFAULT->getAMFTransformIDs(), + "iccProfileName"_a = DEFAULT->getICCProfileName(), DOC(ColorSpace, Create, 2)) .def("__deepcopy__", [](const ConstColorSpaceRcPtr & self, py::dict) diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 9a6f55729c..4e85e2cf32 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -41,6 +41,17 @@ OCIO_ADD_TEST(ColorSpace, basic) OCIO_CHECK_EQUAL(0, cs->getAllocationNumVars()); // Check the nullptr assignment hardening. + // First set the fields to non-empty values. + cs->setName("NAME"); + cs->setDescription("DESC"); + cs->setFamily("FAMILY"); + cs->setEqualityGroup("EQGRP"); + cs->setEncoding("ENC"); + cs->setAMFTransformIDs("AMF"); + cs->setInteropID("INTEROP"); + cs->setICCProfileName("ICC"); + + // Set to nullptr, this should erase the old values. OCIO_CHECK_NO_THROW(cs->setName(nullptr)); OCIO_CHECK_NO_THROW(cs->setDescription(nullptr)); OCIO_CHECK_NO_THROW(cs->setFamily(nullptr)); @@ -50,6 +61,16 @@ OCIO_ADD_TEST(ColorSpace, basic) OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); OCIO_CHECK_NO_THROW(cs->setICCProfileName(nullptr)); + // Check that the values are empty now. + OCIO_CHECK_ASSERT(!*cs->getName()); + OCIO_CHECK_ASSERT(!*cs->getDescription()); + OCIO_CHECK_ASSERT(!*cs->getFamily()); + OCIO_CHECK_ASSERT(!*cs->getEqualityGroup()); + OCIO_CHECK_ASSERT(!*cs->getEncoding()); + OCIO_CHECK_ASSERT(!*cs->getAMFTransformIDs()); + OCIO_CHECK_ASSERT(!*cs->getInteropID()); + OCIO_CHECK_ASSERT(!*cs->getICCProfileName()); + // Test set/get roundtrip. cs->setName("name"); OCIO_CHECK_EQUAL(std::string("name"), cs->getName()); @@ -638,7 +659,7 @@ active_views: [] OCIO_CHECK_EQUAL(cfgRes, os.str()); } - // Test that the interop_id can't be used in v2.0 config + // Test that the interop_id can't be used in v2.0 config. { constexpr char End[]{R"(colorspaces: - ! @@ -663,7 +684,7 @@ active_views: [] "Config failed validation. The color space 'raw' has non-empty InteropID and config version is less than 2.5."); } - // Test that the amf_transform_ids can't be used in v2.0 config + // Test that the amf_transform_ids can't be used in v2.0 config. { constexpr char End[]{R"(colorspaces: - ! @@ -688,7 +709,7 @@ active_views: [] "AMFTransformIDs and config version is less than 2.5."); } - // Test that the icc_profile_name can't be used in v2.0 config + // Test that the icc_profile_name can't be used in v2.0 config. { constexpr char End[]{R"(colorspaces: - ! @@ -1800,28 +1821,28 @@ OCIO_ADD_TEST(ColorSpace, interop_id) { OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); - // Test default value + // Test default value. OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); - // Test setting and getting single profile name + // Test setting and getting single profile name. const char * interop_id = "srgb_p3d65_scene"; cs->setInteropID(interop_id); OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), interop_id); - // Test setting empty string + // Test setting empty string. cs->setInteropID(""); OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); - // Test setting and getting another value + // Test setting and getting another value. const char * anotherID= "lin_rec2020_scene"; cs->setInteropID(anotherID); OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), anotherID); - // Test setting null pointer (should be safe) + // Test setting null pointer (should be safe). OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); - // Test copy constructor preserves ICC profile name + // Test copy constructor preserves ICC profile name. cs->setInteropID(interop_id); OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); OCIO_CHECK_EQUAL(std::string(copy->getInteropID()), interop_id); @@ -1829,7 +1850,7 @@ OCIO_ADD_TEST(ColorSpace, interop_id) OCIO_ADD_TEST(ColorSpace, interop_id_serialization) { - // Test YAML serialization and deserialization of InteropID + // Test YAML serialization and deserialization of InteropID. auto cfg = OCIO::Config::Create(); auto cs = OCIO::ColorSpace::Create(); cs->setName("test_colorspace"); @@ -1839,25 +1860,25 @@ OCIO_ADD_TEST(ColorSpace, interop_id_serialization) cs->setInteropID(interop_id.c_str()); cfg->addColorSpace(cs); - // Serialize the Config + // Serialize the Config. std::stringstream ss; cfg->serialize(ss); std::string yamlStr = ss.str(); - // Verify interop_id appears in YAML + // Verify interop_id appears in YAML. OCIO_CHECK_NE(yamlStr.find("interop_id"), std::string::npos); OCIO_CHECK_NE(yamlStr.find(interop_id), std::string::npos); - // Deserialize and verify + // Deserialize and verify. std::istringstream iss(yamlStr); OCIO::ConstConfigRcPtr deserializedCfg; OCIO_CHECK_NO_THROW(deserializedCfg = OCIO::Config::CreateFromStream(iss)); - // Verify interop_id is preserved + // Verify interop_id is preserved. OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); OCIO_CHECK_EQUAL(std::string(deserializedCs->getInteropID()), interop_id); - // verify that that earlier versions reject interop_id + // verify that that earlier versions reject interop_id. OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); cfgCopy->setVersion(2, 4); OCIO_CHECK_THROW_WHAT( @@ -1866,14 +1887,14 @@ OCIO_ADD_TEST(ColorSpace, interop_id_serialization) "Config failed validation. The color space 'test_colorspace' has non-empty " "InteropID and config version is less than 2.5."); - // Test with empty interop_id (should not appear in YAML) + // Test with empty interop_id (should not appear in YAML). cs->setInteropID(nullptr); - cfg->addColorSpace(cs); // replace the existing CS + cfg->addColorSpace(cs); // Replace the existing CS. ss.str(""); cfg->serialize(ss); std::string yamlStr2 = ss.str(); - // Verify empty imterop_id does not appear in YAML + // Verify empty imterop_id does not appear in YAML. OCIO_CHECK_EQUAL(yamlStr2.find("interop_id"), std::string::npos); } @@ -1881,31 +1902,31 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids) { OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); - // Test default value + // Test default value. OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), ""); - // Test setting and getting single ID + // Test setting and getting single ID. const char * singleID = "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3"; cs->setAMFTransformIDs(singleID); OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), singleID); - // Test setting to empty string + // Test setting to empty string. cs->setAMFTransformIDs(""); OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), ""); - // Test setting and getting multiple IDs + // Test setting and getting multiple IDs. const char * multipleIDs = "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3\n" "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3"; cs->setAMFTransformIDs(multipleIDs); OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), multipleIDs); - // Test setting to nullptr + // Test setting to nullptr. cs->setDescription(nullptr); cs->setAMFTransformIDs(nullptr); OCIO_CHECK_EQUAL(std::string(cs->getAMFTransformIDs()), ""); - // Test copy constructor preserves AMF transform IDs + // Test copy constructor preserves AMF transform IDs. cs->setAMFTransformIDs(singleID); OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); OCIO_CHECK_EQUAL(std::string(copy->getAMFTransformIDs()), singleID); @@ -1913,7 +1934,7 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids) OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) { - // Test YAML serialization and deserialization of AmfTransformIDs + // Test YAML serialization and deserialization of AmfTransformIDs. auto cfg = OCIO::Config::Create(); auto cs = OCIO::ColorSpace::Create(); cs->setName("test_colorspace"); @@ -1925,25 +1946,25 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) cs->setAMFTransformIDs(amfIDs.c_str()); cfg->addColorSpace(cs); - // Serialize the Config + // Serialize the Config. std::stringstream ss; cfg->serialize(ss); std::string yamlStr = ss.str(); - // Verify AmfTransformIDs appears in YAML + // Verify AmfTransformIDs appears in YAML. OCIO_CHECK_NE(yamlStr.find("amf_transform_ids"), std::string::npos); OCIO_CHECK_NE(yamlStr.find("ACEScsc.Academy.ACEScc_to_ACES"), std::string::npos); - // Deserialize and verify + // Deserialize and verify. std::istringstream iss(yamlStr); OCIO::ConstConfigRcPtr deserializedCfg; OCIO_CHECK_NO_THROW(deserializedCfg = OCIO::Config::CreateFromStream(iss)); - // Verify AmfTransformIDs is preserved + // Verify AmfTransformIDs is preserved. OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); OCIO_CHECK_EQUAL(std::string(deserializedCs->getAMFTransformIDs()), amfIDs); - // verify that that earlier versions reject amf_transform_ids + // Verify that that earlier versions reject amf_transform_ids. OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); cfgCopy->setVersion(2,4); OCIO_CHECK_THROW_WHAT(cfgCopy->serialize(ss), @@ -1951,14 +1972,14 @@ OCIO_ADD_TEST(ColorSpace, amf_transform_ids_serialization) "Config failed validation. The color space 'test_colorspace' has non-empty " "AMFTransformIDs and config version is less than 2.5."); - // Test with empty AmfTransformIDs (should not appear in YAML) + // Test with empty AmfTransformIDs (should not appear in YAML). cs->setAMFTransformIDs(nullptr); - cfg->addColorSpace(cs); // replace the existing CS + cfg->addColorSpace(cs); // Replace the existing CS. ss.str(""); cfg->serialize(ss); std::string yamlStr2 = ss.str(); - // Verify empty AmfTransformIDs does not appear in YAML + // Verify empty AmfTransformIDs does not appear in YAML. OCIO_CHECK_EQUAL(yamlStr2.find("amf_transform_ids"), std::string::npos); } @@ -1966,28 +1987,28 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name) { OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); - // Test default value + // Test default value. OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); - // Test setting and getting single profile name + // Test setting and getting single profile name. const char * profileName = "sRGB IEC61966-2.1"; cs->setICCProfileName(profileName); OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), profileName); - // Test setting and getting another profile name + // Test setting and getting another profile name. const char * anotherProfile = "Adobe RGB (1998)"; cs->setICCProfileName(anotherProfile); OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), anotherProfile); - // Test setting empty string + // Test setting empty string. cs->setICCProfileName(""); OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); - // Test setting null pointer (should be safe) + // Test setting null pointer (should be safe). OCIO_CHECK_NO_THROW(cs->setICCProfileName(nullptr)); OCIO_CHECK_EQUAL(std::string(cs->getICCProfileName()), ""); - // Test copy constructor preserves ICC profile name + // Test copy constructor preserves ICC profile name. cs->setICCProfileName(profileName); OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); OCIO_CHECK_EQUAL(std::string(copy->getICCProfileName()), profileName); @@ -1995,7 +2016,7 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name) OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) { - // Test YAML serialization and deserialization of IccProfileName + // Test YAML serialization and deserialization of IccProfileName. auto cfg = OCIO::Config::Create(); auto cs = OCIO::ColorSpace::Create(); cs->setName("test_colorspace"); @@ -2005,25 +2026,25 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) cs->setICCProfileName(profileName.c_str()); cfg->addColorSpace(cs); - // Serialize the Config + // Serialize the Config. std::stringstream ss; cfg->serialize(ss); std::string yamlStr = ss.str(); - // Verify IccProfileName appears in YAML + // Verify IccProfileName appears in YAML. OCIO_CHECK_NE(yamlStr.find("icc_profile_name"), std::string::npos); OCIO_CHECK_NE(yamlStr.find(profileName), std::string::npos); - // Deserialize and verify + // Deserialize and verify. std::istringstream iss(yamlStr); OCIO::ConstConfigRcPtr deserializedCfg; OCIO_CHECK_NO_THROW(deserializedCfg = OCIO::Config::CreateFromStream(iss)); - // Verify IccProfileName is preserved + // Verify IccProfileName is preserved. OCIO::ConstColorSpaceRcPtr deserializedCs = deserializedCfg->getColorSpace("test_colorspace"); OCIO_CHECK_EQUAL(std::string(deserializedCs->getICCProfileName()), profileName); - // verify that that earlier versions reject amf_transform_ids + // verify that that earlier versions reject amf_transform_ids. OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); cfgCopy->setVersion(2, 4); OCIO_CHECK_THROW_WHAT( @@ -2032,13 +2053,13 @@ OCIO_ADD_TEST(ColorSpace, icc_profile_name_serialization) "Config failed validation. The color space 'test_colorspace' has non-empty " "ICCProfileName and config version is less than 2.5."); - // Test with empty IccProfileName (should not appear in YAML) + // Test with empty IccProfileName (should not appear in YAML). cs->setICCProfileName(nullptr); cfg->addColorSpace(cs); // replace the existing CS ss.str(""); cfg->serialize(ss); std::string yamlStr2 = ss.str(); - // Verify empty IccProfileName does not appear in YAML + // Verify empty IccProfileName does not appear in YAML. OCIO_CHECK_EQUAL(yamlStr2.find("icc_profile_name"), std::string::npos); } \ No newline at end of file From b85a71cd227736ef4eab413c7d5d29819a10fe2b Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Thu, 5 Jun 2025 23:50:50 -0700 Subject: [PATCH 11/16] - testing CI artifact uploading. Signed-off-by: cuneyt.ozdas --- .github/workflows/ci_workflow.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index 07db553ea4..0b4ee4147a 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -61,7 +61,7 @@ jobs: strategy: fail-fast: true matrix: - build: [7, 8, 9, 10, 11, 12] + build: [8, 11] include: # ------------------------------------------------------------------- # VFX CY2024 (Python 3.11) @@ -186,6 +186,12 @@ jobs: -- -j$(nproc) echo "ocio_build_path=$(pwd)" >> $GITHUB_ENV working-directory: _build + - name: Upload Docs + uses: actions/upload-artifact@v4 + with: + name: built-documents + path: docs/api/python/frozen/ + if: matrix.build-docs == 'ON' - name: Test run: ctest -V -C ${{ matrix.build-type }} working-directory: _build @@ -257,7 +263,7 @@ jobs: strategy: fail-fast: true matrix: - build: [1, 2, 3, 4, 5, 6] + build: [5] include: # ------------------------------------------------------------------- # VFX CY2022 (Python 3.9) @@ -462,7 +468,7 @@ jobs: runs-on: macos-13 strategy: matrix: - build: [1, 2, 3, 4] + build: [3] include: - build: 5 arch-type: "x86_64" From 6b3c761a04ee39a4a22fb5303ab73827fc654161 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Fri, 6 Jun 2025 00:35:13 -0700 Subject: [PATCH 12/16] Another attempt for finding the correct frozen doc format. Signed-off-by: cuneyt.ozdas --- .github/workflows/ci_workflow.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index 0b4ee4147a..a672a52ac5 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -189,7 +189,7 @@ jobs: - name: Upload Docs uses: actions/upload-artifact@v4 with: - name: built-documents + name: docs-Linux_CY${{ matrix.vfx-cy }}_build${{ matrix.vfx-cy }} path: docs/api/python/frozen/ if: matrix.build-docs == 'ON' - name: Test @@ -404,6 +404,12 @@ jobs: -- -j$(nproc) echo "ocio_build_path=$(pwd)" >> $GITHUB_ENV working-directory: _build + - name: Upload Docs + uses: actions/upload-artifact@v4 + with: + name: docs-Linux_CY${{ matrix.vfx-cy }}_build${{ matrix.build }} + path: docs/api/python/frozen/ + if: matrix.build-docs == 'ON' - name: Test run: ctest -V -C ${{ matrix.build-type }} working-directory: _build @@ -562,6 +568,12 @@ jobs: -- -j$(sysctl -n hw.ncpu) echo "ocio_build_path=$(pwd)" >> $GITHUB_ENV working-directory: _build + - name: Upload Docs + uses: actions/upload-artifact@v4 + with: + name: docs-MacOS13_build${{ matrix.build }} + path: docs/api/python/frozen/ + if: matrix.build-docs == 'ON' - name: Test run: ctest -V -C ${{ matrix.build-type }} working-directory: _build @@ -623,7 +635,7 @@ jobs: runs-on: macos-14 strategy: matrix: - build: [1, 2] + build: [] include: - build: 1 arch-type: "arm64" @@ -758,7 +770,7 @@ jobs: runs-on: windows-2019 strategy: matrix: - build: [1, 2, 3, 4] + build: [] include: - build: 4 build-type: Release From f1f8920fb7020d60be18bc4d8371c5d99cdbe743 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Fri, 6 Jun 2025 00:40:47 -0700 Subject: [PATCH 13/16] something was not right. retry Signed-off-by: cuneyt.ozdas --- .github/workflows/ci_workflow.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index a672a52ac5..6f422e2050 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -189,7 +189,7 @@ jobs: - name: Upload Docs uses: actions/upload-artifact@v4 with: - name: docs-Linux_CY${{ matrix.vfx-cy }}_build${{ matrix.vfx-cy }} + name: docs-linux path: docs/api/python/frozen/ if: matrix.build-docs == 'ON' - name: Test @@ -407,7 +407,7 @@ jobs: - name: Upload Docs uses: actions/upload-artifact@v4 with: - name: docs-Linux_CY${{ matrix.vfx-cy }}_build${{ matrix.build }} + name: docs-linux-old path: docs/api/python/frozen/ if: matrix.build-docs == 'ON' - name: Test @@ -571,7 +571,7 @@ jobs: - name: Upload Docs uses: actions/upload-artifact@v4 with: - name: docs-MacOS13_build${{ matrix.build }} + name: docs-macOS13 path: docs/api/python/frozen/ if: matrix.build-docs == 'ON' - name: Test @@ -635,7 +635,7 @@ jobs: runs-on: macos-14 strategy: matrix: - build: [] + build: [1, 2] include: - build: 1 arch-type: "arm64" @@ -770,7 +770,7 @@ jobs: runs-on: windows-2019 strategy: matrix: - build: [] + build: [1, 2, 3, 4] include: - build: 4 build-type: Release From 945e494c578ced5f71337d345c7e76d0b6ba6c5b Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Fri, 6 Jun 2025 10:03:16 -0700 Subject: [PATCH 14/16] - reverting the ci_workflow.yml, I'll continue my experiments on another branch. Signed-off-by: cuneyt.ozdas --- .github/workflows/ci_workflow.yml | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index 6f422e2050..07db553ea4 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -61,7 +61,7 @@ jobs: strategy: fail-fast: true matrix: - build: [8, 11] + build: [7, 8, 9, 10, 11, 12] include: # ------------------------------------------------------------------- # VFX CY2024 (Python 3.11) @@ -186,12 +186,6 @@ jobs: -- -j$(nproc) echo "ocio_build_path=$(pwd)" >> $GITHUB_ENV working-directory: _build - - name: Upload Docs - uses: actions/upload-artifact@v4 - with: - name: docs-linux - path: docs/api/python/frozen/ - if: matrix.build-docs == 'ON' - name: Test run: ctest -V -C ${{ matrix.build-type }} working-directory: _build @@ -263,7 +257,7 @@ jobs: strategy: fail-fast: true matrix: - build: [5] + build: [1, 2, 3, 4, 5, 6] include: # ------------------------------------------------------------------- # VFX CY2022 (Python 3.9) @@ -404,12 +398,6 @@ jobs: -- -j$(nproc) echo "ocio_build_path=$(pwd)" >> $GITHUB_ENV working-directory: _build - - name: Upload Docs - uses: actions/upload-artifact@v4 - with: - name: docs-linux-old - path: docs/api/python/frozen/ - if: matrix.build-docs == 'ON' - name: Test run: ctest -V -C ${{ matrix.build-type }} working-directory: _build @@ -474,7 +462,7 @@ jobs: runs-on: macos-13 strategy: matrix: - build: [3] + build: [1, 2, 3, 4] include: - build: 5 arch-type: "x86_64" @@ -568,12 +556,6 @@ jobs: -- -j$(sysctl -n hw.ncpu) echo "ocio_build_path=$(pwd)" >> $GITHUB_ENV working-directory: _build - - name: Upload Docs - uses: actions/upload-artifact@v4 - with: - name: docs-macOS13 - path: docs/api/python/frozen/ - if: matrix.build-docs == 'ON' - name: Test run: ctest -V -C ${{ matrix.build-type }} working-directory: _build From a73c2309d4d018357b187e271548750441d46459 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Fri, 6 Jun 2025 21:28:45 -0700 Subject: [PATCH 15/16] Adding the python frozen docs for the ColorSpacde class. I was unable to build this locally so modified the CI workflow to upload the docs folder as an artifact in a separate branch. Even that was not readily consumable, I had to manually pick the differences and the remove the duplicate PyOpenColorIO in the entity names (i.e. PyOpenColorIO.PyOpenColorIO.ColorSpace) Signed-off-by: cuneyt.ozdas --- .../frozen/pyopencolorio_colorspace.rst | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/docs/api/python/frozen/pyopencolorio_colorspace.rst b/docs/api/python/frozen/pyopencolorio_colorspace.rst index 5a6adf8d99..0dedcbea43 100644 --- a/docs/api/python/frozen/pyopencolorio_colorspace.rst +++ b/docs/api/python/frozen/pyopencolorio_colorspace.rst @@ -20,7 +20,7 @@ 2. __init__(self: PyOpenColorIO.ColorSpace, referenceSpace: PyOpenColorIO.ReferenceSpaceType) -> None - 3. __init__(self: PyOpenColorIO.ColorSpace, referenceSpace: PyOpenColorIO.ReferenceSpaceType = , name: str = '', aliases: List[str] = [], family: str = '', encoding: str = '', equalityGroup: str = '', description: str = '', bitDepth: PyOpenColorIO.BitDepth = , isData: bool = False, allocation: PyOpenColorIO.Allocation = , allocationVars: List[float] = [], toReference: PyOpenColorIO.Transform = None, fromReference: PyOpenColorIO.Transform = None, categories: List[str] = []) -> None + 3. __init__(self: PyOpenColorIO.ColorSpace, referenceSpace: PyOpenColorIO.ReferenceSpaceType = , name: str = '', aliases: List[str] = [], family: str = '', encoding: str = '', equalityGroup: str = '', description: str = '', bitDepth: PyOpenColorIO.BitDepth = , isData: bool = False, allocation: PyOpenColorIO.Allocation = , allocationVars: List[float] = [], toReference: PyOpenColorIO.Transform = None, fromReference: PyOpenColorIO.Transform = None, categories: List[str] = [], interopID: str = '', amfTransformIDs: str = '', iccProfileName: str = '') -> None .. py:method:: ColorSpace.addAlias(self: PyOpenColorIO.ColorSpace, alias: str) -> None @@ -48,6 +48,14 @@ Clear all the categories. + .. py:method:: ColorSpace.getAMFTransformIDs(self: PyOpenColorIO.ColorSpace) -> str + :module: PyOpenColorIO + + Get/Set the AMF transform IDs for the color space. + + The AMF transform IDs are used to identify specific transforms in the ACES Metadata File. Multiple transform IDs can be specified in a newline-separated string. + + .. py:method:: ColorSpace.getAliases(self: PyOpenColorIO.ColorSpace) -> PyOpenColorIO.ColorSpace.ColorSpaceAliasIterator :module: PyOpenColorIO @@ -104,6 +112,21 @@ Get the family, for use in user interfaces (optional) The family string could use a '/' separator to indicate levels to be used by hierarchical menus. + .. py:method:: ColorSpace.getICCProfileName(self: PyOpenColorIO.ColorSpace) -> str + :module: PyOpenColorIO + + Get/Set the ICC profile name for the color space. + + The ICC profile name identifies the ICC color profile associated with this color space. This can be used to link OCIO color spaces with corresponding ICC profiles for applications that need to work with both color management systems. + + + .. py:method:: ColorSpace.getInteropID(self: PyOpenColorIO.ColorSpace) -> str + :module: PyOpenColorIO + + Get/Set the interop ID for the color space. + + The interop ID is a standardized identifier to uniquely identify commonly used color spaces. These IDs are defined by the Academy Software Foundation's Color Interop Forum project. If you create your own ID, you must prefix it with unique characters that will ensure it won't conflict with future Color Interop Forum IDs. + .. py:method:: ColorSpace.getName(self: PyOpenColorIO.ColorSpace) -> str :module: PyOpenColorIO @@ -122,6 +145,11 @@ If a transform in the specified direction has been specified, return it. Otherwise return a null ConstTransformRcPtr + .. py:method:: ColorSpace.hasAlias(self: PyOpenColorIO.ColorSpace, alias: str) -> bool + :module: PyOpenColorIO + + Return true if alias exists. + .. py:method:: ColorSpace.hasCategory(self: PyOpenColorIO.ColorSpace, category: str) -> bool :module: PyOpenColorIO @@ -168,6 +196,10 @@ Will do nothing if the category is missing. + .. py:method:: ColorSpace.setAMFTransformIDs(self: PyOpenColorIO.ColorSpace, amfTransformIDs: str) -> None + :module: PyOpenColorIO + + .. py:method:: ColorSpace.setAllocation(self: PyOpenColorIO.ColorSpace, allocation: PyOpenColorIO.Allocation) -> None :module: PyOpenColorIO @@ -198,6 +230,14 @@ Set the family, for use in user interfaces (optional) + .. py:method:: ColorSpace.setICCProfileName(self: PyOpenColorIO.ColorSpace, iccProfileName: str) -> None + :module: PyOpenColorIO + + + .. py:method:: ColorSpace.setInteropID(self: PyOpenColorIO.ColorSpace, interopID: str) -> None + :module: PyOpenColorIO + + .. py:method:: ColorSpace.setIsData(self: PyOpenColorIO.ColorSpace, isData: bool) -> None :module: PyOpenColorIO From c2f65f56f38a751013f251908c8550d435c5e47f Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Fri, 6 Jun 2025 21:39:14 -0700 Subject: [PATCH 16/16] Minor fixes to python tests. Signed-off-by: cuneyt.ozdas --- tests/python/ColorSpaceTest.py | 53 +++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/tests/python/ColorSpaceTest.py b/tests/python/ColorSpaceTest.py index 3c595f1715..f8f141194c 100644 --- a/tests/python/ColorSpaceTest.py +++ b/tests/python/ColorSpaceTest.py @@ -393,6 +393,8 @@ def test_aliases(self): cs.addAlias('Alias2') aliases = cs.getAliases() self.assertEqual(len(aliases), 2) + self.assertEqual(aliases[0], 'alias1') + self.assertEqual(aliases[1], 'alias2') # Name might remove an alias. @@ -644,28 +646,29 @@ def test_interop_id(self): Test the setInteropID() and getInteropID() methods. """ - # Test default value (should be empty) + # Test default value (should be empty). self.assertEqual(self.colorspace.getInteropID(), '') - # Test setting and getting a simple interop ID + # Test setting and getting a simple interop ID. test_id = 'lin_ap0_scene' self.colorspace.setInteropID(test_id) self.assertEqual(self.colorspace.getInteropID(), test_id) - # Test setting and getting a different interop ID + # Test setting and getting a different interop ID. test_id2 = 'srgb_ap1_scene' self.colorspace.setInteropID(test_id2) self.assertEqual(self.colorspace.getInteropID(), test_id2) - # Test setting empty string + # Test setting empty string. self.colorspace.setInteropID('') self.assertEqual(self.colorspace.getInteropID(), '') - # Test setting None (should convert to empty string) + # Test setting None (should convert to empty string). + self.colorspace.setInteropID('something') self.colorspace.setInteropID(None) self.assertEqual(self.colorspace.getInteropID(), '') - # Test wrong type (should raise TypeError) + # Test wrong type (should raise TypeError). with self.assertRaises(TypeError): self.colorspace.setInteropID(123) @@ -677,40 +680,41 @@ def test_amf_transform_ids(self): Test the setAMFTransformIDs() and getAMFTransformIDs() methods. """ - # Test default value (should be empty) + # Test default value (should be empty). self.assertEqual(self.colorspace.getAMFTransformIDs(), '') - # Test setting and getting a single transform ID + # Test setting and getting a single transform ID. single_id = 'urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3' self.colorspace.setAMFTransformIDs(single_id) self.assertEqual(self.colorspace.getAMFTransformIDs(), single_id) - # Test setting and getting multiple transform IDs (newline-separated) + # Test setting and getting multiple transform IDs (newline-separated). multiple_ids = ('urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3\n' 'urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_CG.a1.0.3\n' 'urn:ampas:aces:transformId:v1.5:RRT.a1.0.3') self.colorspace.setAMFTransformIDs(multiple_ids) self.assertEqual(self.colorspace.getAMFTransformIDs(), multiple_ids) - # Test setting empty string + # Test setting empty string. self.colorspace.setAMFTransformIDs('') self.assertEqual(self.colorspace.getAMFTransformIDs(), '') - # Test setting None (should convert to empty string) + # Test setting None (should convert to empty string). + self.colorspace.setAMFTransformIDs('something') self.colorspace.setAMFTransformIDs(None) self.assertEqual(self.colorspace.getAMFTransformIDs(), '') - # Test with different line endings + # Test with different line endings. mixed_endings = 'id1\nid2\rid3\r\nid4' self.colorspace.setAMFTransformIDs(mixed_endings) self.assertEqual(self.colorspace.getAMFTransformIDs(), mixed_endings) - # Test with leading/trailing whitespace + # Test with leading/trailing whitespace. whitespace_ids = ' \n id1 \n id2 \n ' self.colorspace.setAMFTransformIDs(whitespace_ids) self.assertEqual(self.colorspace.getAMFTransformIDs(), whitespace_ids) - # Test wrong type (should raise TypeError) + # Test wrong type (should raise TypeError). with self.assertRaises(TypeError): self.colorspace.setAMFTransformIDs(123) @@ -722,43 +726,44 @@ def test_icc_profile_name(self): Test the setICCProfileName() and getICCProfileName() methods. """ - # Test default value (should be empty) + # Test default value (should be empty). self.assertEqual(self.colorspace.getICCProfileName(), '') - # Test setting and getting a simple profile name + # Test setting and getting a simple profile name. profile_name = 'sRGB IEC61966-2.1' self.colorspace.setICCProfileName(profile_name) self.assertEqual(self.colorspace.getICCProfileName(), profile_name) - # Test setting and getting a different profile name + # Test setting and getting a different profile name. profile_name2 = 'Adobe RGB (1998)' self.colorspace.setICCProfileName(profile_name2) self.assertEqual(self.colorspace.getICCProfileName(), profile_name2) - # Test with a more complex profile name + # Test with a more complex profile name. complex_name = 'Display P3 - Apple Cinema Display (Calibrated 2023-01-15)' self.colorspace.setICCProfileName(complex_name) self.assertEqual(self.colorspace.getICCProfileName(), complex_name) - - # Test setting empty string + + # Test setting empty string. self.colorspace.setICCProfileName('') self.assertEqual(self.colorspace.getICCProfileName(), '') - # Test setting None (should convert to empty string) + # Test setting None (should convert to empty string). + self.colorspace.setICCProfileName('something') self.colorspace.setICCProfileName(None) self.assertEqual(self.colorspace.getICCProfileName(), '') - # Test with special characters and numbers + # Test with special characters and numbers. special_name = 'ProPhoto RGB v2.0 (γ=1.8) [Custom Profile #123]' self.colorspace.setICCProfileName(special_name) self.assertEqual(self.colorspace.getICCProfileName(), special_name) - # Test with Unicode characters + # Test with Unicode characters. unicode_name = 'Профиль RGB γ=2.2' self.colorspace.setICCProfileName(unicode_name) self.assertEqual(self.colorspace.getICCProfileName(), unicode_name) - # Test wrong type (should raise TypeError) + # Test wrong type (should raise TypeError). with self.assertRaises(TypeError): self.colorspace.setICCProfileName(123)