From 764f14a9e3582e9c03dcf695fdbac05ea46f7be5 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Tue, 16 Sep 2025 19:56:12 -0400 Subject: [PATCH 1/5] Fixes for the Wheel workflow (#2190) * Turn off failing stuff Signed-off-by: Doug Walker * Turn off ociolutimage Signed-off-by: Doug Walker * Uninstall the runner EXR Signed-off-by: Doug Walker * Bump EXR min version to 3.1.6 Signed-off-by: Doug Walker * Bump EXR recommended version to 3.1.6 Signed-off-by: Doug Walker * Minor clean up Signed-off-by: Doug Walker --------- Signed-off-by: Doug Walker --- .github/workflows/wheel_workflow.yml | 6 +++++- share/cmake/modules/FindExtPackages.cmake | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheel_workflow.yml b/.github/workflows/wheel_workflow.yml index 376b006c0..51fb225be 100644 --- a/.github/workflows/wheel_workflow.yml +++ b/.github/workflows/wheel_workflow.yml @@ -259,6 +259,10 @@ jobs: with: python-version: '3.9' + - name: Remove brew OpenEXR/Imath + run: | + brew uninstall --ignore-dependencies openexr imath || true + - name: Build wheels uses: pypa/cibuildwheel@v2.22.0 env: @@ -382,7 +386,7 @@ jobs: upload_pypi: - needs: [sdist, linux, macos, macos-arm, windows] + needs: [sdist, linux, linux-arm, macos, macos-arm, windows] runs-on: ubuntu-latest if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') steps: diff --git a/share/cmake/modules/FindExtPackages.cmake b/share/cmake/modules/FindExtPackages.cmake index aa2550ac7..7cdb17b4e 100644 --- a/share/cmake/modules/FindExtPackages.cmake +++ b/share/cmake/modules/FindExtPackages.cmake @@ -184,7 +184,7 @@ if(OCIO_BUILD_PYTHON OR OCIO_BUILD_DOCS) endif() # Set OpenEXR Minimum version as a variable since it it used at multiple places. -set(OpenEXR_MININUM_VERSION "3.0.5") +set(OpenEXR_MININUM_VERSION "3.1.6") if((OCIO_BUILD_APPS AND OCIO_USE_OIIO_FOR_APPS) OR OCIO_BUILD_TESTS) # OpenImageIO is required for OSL unit test and optional for apps. @@ -260,7 +260,7 @@ if(OCIO_BUILD_APPS) # Calling find_package in CONFIG mode using PREFER_CONFIG option. ocio_handle_dependency( OpenEXR PREFER_CONFIG ALLOW_INSTALL MIN_VERSION ${OpenEXR_MININUM_VERSION} - RECOMMENDED_VERSION 3.1.5 + RECOMMENDED_VERSION 3.1.6 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO" PROMOTE_TARGET OpenEXR::OpenEXR) From 1cec2abed44b14cbe596d8b177b57f2708752905 Mon Sep 17 00:00:00 2001 From: Cuneyt Ozdas Date: Wed, 17 Sep 2025 16:10:19 -0700 Subject: [PATCH 2/5] Adsk Contrib - Adding color space attribs: interop_id, amf_transform & icc_profile_name (#2165) * Adding 3 new attributes to the color space: interop_id, amf_transform_ids and icc_profile_name - Addressing the issues #1975, #2152 and #2153 - Bumped the config version to 2.5 - newly added attributes require v2.5 config both for serialization and de-serialization and will throw if they appear in older configs. - Hardened multiple existing functions against null parameters. Previously those functions were crashing if null is passed, as assigning null to std::string is undefined behavior. - Expanded tests to some affected functions' unit tests to include null passing. Setters will take null as empty string. compare functions will throw. Signed-off-by: cuneyt.ozdas * As discussed in the TSC meeting, adding a namespace field separator logic to the interop_id field. - only zero or one ":" is allowed in the interop_id name - ":" can not be the last character - added cpp and python unit tests. Signed-off-by: cuneyt.ozdas * Adding interop_id verification in ociocheck. Non-namespaced IDs are checked against the known CIF values and warning is issued if not found. Signed-off-by: cuneyt.ozdas * minor touches. Signed-off-by: cuneyt.ozdas * fix the failing test. Signed-off-by: cuneyt.ozdas * Disallow non-ASCII characters (outside of [0..127] range) in the interopID field. Signed-off-by: cuneyt.ozdas * Fixing the tests which were failing due to exception wording change. Signed-off-by: cuneyt.ozdas * - replacing getAMFTransformIDs and getICCProfileName with more generic getInterchangeAttribute function. Same with the setters - getInterchangeAttribute() and setInterchangeAttribute() functions currently knows and accepts "amf_transform_ids" and "icc_profile_name" keys. other keys will throw. - ColorSpace serializer will list all of the key/value pairs. - InteropID and interchangeAttributes are now allowed in earlier config versions down to 2.0 too. Config::checkVersionConsistency() will throw only for version smaller than 2.0. - YAML loader and saver now supports the "interchange" section. Any unknown keys under that section will be ignored upon load and will generate a warning but won't throw. - Generic str key/value loader/saver is extended for re usability (and fixed incorrect throw message). - since the amf keywords are separated by newline characters, the newline sanitizer that was used for the description is also generalized and applied to all of the current and possible future interchange fields. - ColorSpace_test.cpp file updated to test the current state and behavior of the API. - ComputeValues function in the CPUProcessor_tests.cpp was taking the linenumber as as template parameter. This was a very bad idea as that means each invocation of the function would create a separate copy of the function which was causing all sorts of issues in the debugger and failing to compile when the line numbers are not constants (happens in JIT debug sessions). Fixed by making the line number a normal parameter. - Python ColorSpace object no longer takes the amf of icc parameters in the constructor. User needs to set them explicitely later on. Signed-off-by: cuneyt.ozdas * - ocioconvert now writes the ColorIntropID attribute of of the output color space. - ociocheck now does extended validity check on the interopID string. - preliminary implementation of getColorSpaceFromInteropID(). Signed-off-by: cuneyt.ozdas * - Another cleanup pass. After some deliberation, we decided to remove getColorSpaceFromInteropID() which will be done in a later pass. Signed-off-by: cuneyt.ozdas * - Config::getColorSpaceFromInteropID() function is removed. - another round of cleanup. Signed-off-by: cuneyt.ozdas * minor comment fix Signed-off-by: cuneyt.ozdas * minor fixes to unknown interchange key warning and its unit test. Signed-off-by: cuneyt.ozdas * - Adding the missing interop_id validation check along with couple of unit-tests. Signed-off-by: cuneyt.ozdas * - typo fix and minor cleanup Signed-off-by: cuneyt.ozdas * - Looks like Doxygen doesn't like URLs in the doxygen comment section. Removing the url to see if this fixes the CI issue. Signed-off-by: cuneyt.ozdas * - minor typo fix Signed-off-by: cuneyt.ozdas * - deduplicating the newline sanitize code in OCIOYaml.cpp - exposing the interchange attributes as a standard python dictionary through the "interchangeAttributes" read-only property. - adding python tests on the new interchangeAttributes property. Signed-off-by: cuneyt.ozdas * - per code-review, converting the interchangeAttributes propery on python colorspace object to getInterchangeAttributes() function to stick with the existing conventions. Signed-off-by: cuneyt.ozdas --------- Signed-off-by: cuneyt.ozdas Co-authored-by: Doug Walker --- include/OpenColorIO/OpenColorIO.h | 35 ++ src/OpenColorIO/Baker.cpp | 12 +- src/OpenColorIO/ColorSpace.cpp | 152 +++++- src/OpenColorIO/Config.cpp | 63 ++- src/OpenColorIO/Context.cpp | 2 +- src/OpenColorIO/Look.cpp | 6 +- src/OpenColorIO/OCIOYaml.cpp | 199 +++++--- src/OpenColorIO/Platform.cpp | 10 + src/OpenColorIO/ViewTransform.cpp | 6 +- src/OpenColorIO/ViewingRules.cpp | 2 - src/apps/ociocheck/main.cpp | 87 ++++ src/apps/ocioconvert/main.cpp | 8 + src/bindings/python/PyColorSpace.cpp | 30 +- src/libutils/imageioapphelpers/imageio.cpp | 3 + tests/cpu/CPUProcessor_tests.cpp | 520 +++++++++---------- tests/cpu/ColorSpace_tests.cpp | 562 ++++++++++++++++++++- tests/cpu/Config_tests.cpp | 4 +- tests/python/ColorSpaceTest.py | 205 +++++++- 18 files changed, 1538 insertions(+), 368 deletions(-) diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 53ffa8315..05e66cac5 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "OpenColorABI.h" #include "OpenColorTypes.h" @@ -1984,6 +1985,40 @@ class OCIOEXPORT ColorSpace const char * getDescription() const noexcept; void setDescription(const char * description); + /** + * Get/Set the interop ID for the color space. The interop ID is a + * structured string defined by the Color Interop Forum. It is intended to + * identify color spaces in a way that is portable across different configs, + * making it suitable for use in various file formats. The Color Interop + * Forum publishes ID strings for common color spaces. If you create your + * own IDs, they must be preceded by a namespace string. The setter will + * throw if the string does not follow certain rules (run ociocheck for a + * more complete validation). + */ + const char * getInteropID() const noexcept; + void setInteropID(const char * interopID); + + /** + * Get/Set the interchange attributes. + * + * Currently supported attribute names are "amf_transform_ids" and + * "icc_profile_name". Using any other name will throw. If the attribute is + * not defined, it'll return an empty string. Setting the value to an empty + * string will effectively delete the attribute. + * + * 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. + * + * 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 *getInterchangeAttribute(const char *attrName) const; + void setInterchangeAttribute(const char* attrName, const char *value); + std::map getInterchangeAttributes() const noexcept; + BitDepth getBitDepth() const noexcept; void setBitDepth(BitDepth bitDepth); diff --git a/src/OpenColorIO/Baker.cpp b/src/OpenColorIO/Baker.cpp index b8a78a958..e92a4f3d3 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 4b7ecb25d..98f776fe1 100644 --- a/src/OpenColorIO/ColorSpace.cpp +++ b/src/OpenColorIO/ColorSpace.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -13,6 +14,13 @@ #include "utils/StringUtils.h" +namespace +{ +const std::array knownInterchangeNames = { + "amf_transform_ids", + "icc_profile_name" }; +} + namespace OCIO_NAMESPACE { @@ -24,7 +32,9 @@ class ColorSpace::Impl std::string m_equalityGroup; std::string m_description; std::string m_encoding; + std::string m_interopID; StringUtils::StringVec m_aliases; + std::map m_interchangeAttribs; BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN }; bool m_isData{ false }; @@ -62,6 +72,8 @@ class ColorSpace::Impl m_equalityGroup = rhs.m_equalityGroup; m_description = rhs.m_description; m_encoding = rhs.m_encoding; + m_interopID = rhs.m_interopID; + m_interchangeAttribs= rhs.m_interchangeAttribs; m_bitDepth = rhs.m_bitDepth; m_isData = rhs.m_isData; m_referenceSpaceType = rhs.m_referenceSpaceType; @@ -195,7 +207,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 @@ -205,7 +217,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 @@ -215,7 +227,125 @@ 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 +{ + return getImpl()->m_interopID.c_str(); +} + +void ColorSpace::setInteropID(const char * interopID) +{ + std::string id = interopID ? interopID : ""; + + if (!id.empty()) + { + // check if it only uses ASCII characters: 0-9, a-z, and the following characters (no spaces): + // . - _ ~ / * # % ^ + ( ) [ ] | + auto allowed = [](char c) + { + return (c >= '0' && c <= '9')|| + (c >= 'a' && c <= 'z')|| + c=='.'||c=='-'||c=='_'||c=='~'||c=='/'||c=='*'||c=='#'||c=='%'|| + c=='^'||c=='+'||c=='('||c==')'||c=='['||c==']'||c=='|'||c==':'; + }; + + if (!std::all_of(id.begin(), id.end(), allowed)) + { + std::ostringstream oss; + oss << "InteropID '" << id << "' contains invalid characters. " + "Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed." << + std::endl; + throw Exception(oss.str().c_str()); + } + + // Check if has a namespace. + size_t pos = id.find(':'); + if (pos != std::string::npos) + { + // Namespace found, split into namespace and color space. + std::string ns = id.substr(0, pos); + std::string cs = id.substr(pos+1); + + // both should be non-empty + if (ns.empty() || cs.empty()) + { + std::ostringstream oss; + oss << "InteropID '" << id << "' is not valid. " + "If ':' is used, both the namespace and the color space parts must be non-empty." << + std::endl; + throw Exception(oss.str().c_str()); + } + + // More than one ':' is an error. + if (cs.find(':') != std::string::npos) + { + std::ostringstream oss; + oss << "ERROR: InteropID '" << id << "' is not valid. " + "Only one ':' is allowed to separate the namespace and the color space." << + std::endl; + throw Exception(oss.str().c_str()); + } + } + } + + getImpl()->m_interopID = id; +} + +const char * ColorSpace::getInterchangeAttribute(const char* attrName) const +{ + std::string name = attrName ? attrName : ""; + + for (auto& key : knownInterchangeNames) + { + // do case-insensitive comparison. + if (StringUtils::Compare(key, name)) + { + auto it = m_impl->m_interchangeAttribs.find(key); + if (it != m_impl->m_interchangeAttribs.end()) + { + return it->second.c_str(); + } + return ""; + } + } + + std::ostringstream oss; + oss << "Unknown attribute name '" << name << "'."; + throw Exception(oss.str().c_str()); +} + +void ColorSpace::setInterchangeAttribute(const char* attrName, const char* value) +{ + std::string name = attrName ? attrName : ""; + + for (auto& key : knownInterchangeNames) + { + // Do case-insensitive comparison. + if (StringUtils::Compare(key, name)) + { + // use key instead of name for storing in correct capitalization. + if (!value || !*value) + { + m_impl->m_interchangeAttribs.erase(key); + } + else + { + m_impl->m_interchangeAttribs[key] = value; + } + return; + } + } + + std::ostringstream oss; + oss << "Unknown attribute name '" << name << "'."; + throw Exception(oss.str().c_str()); +} + +std::map ColorSpace::getInterchangeAttributes() const noexcept +{ + return m_impl->m_interchangeAttribs; } BitDepth ColorSpace::getBitDepth() const noexcept @@ -265,7 +395,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 @@ -371,7 +501,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) { @@ -386,6 +515,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 << ", "; @@ -429,6 +567,10 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs) { os << ", description=" << str; } + for (const auto& attr : cs.getInterchangeAttributes()) + { + os << ", " << attr.first << "=" << attr.second; + } if(cs.getTransform(COLORSPACE_DIR_TO_REFERENCE)) { os << ",\n " << cs.getName() << " --> Reference"; diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index ad19b39c7..550d23099 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. @@ -1450,6 +1450,22 @@ void Config::validate() const throw Exception(getImpl()->m_validationtext.c_str()); } + // Make sure that all used interopIDs are available in this config. + const char* interop = cs->getInteropID(); + if(interop && *interop) + { + if(!getColorSpace(interop)) + { + std::ostringstream os; + os << "Config failed color space validation. "; + os << "The color space '" << name << "' "; + os << "refers to an interop ID, '" << interop << "', "; + os << "which is not defined in this config."; + getImpl()->m_validationtext = os.str(); + throw Exception(getImpl()->m_validationtext.c_str()); + } + } + // AddColorSpace, addNamedTransform & setRole already check there is no name & alias // conflict. @@ -1499,7 +1515,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; @@ -5601,6 +5618,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; @@ -5670,18 +5689,44 @@ void Config::Impl::checkVersionConsistency() const } } - // Check for the DisplayColorSpaces. + // Check ColorSpace properties. - 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) + // Check for display color spaces. + + 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."); } + } + + // Check for new color space attributes. + + if (m_majorVersion < 2) + { + 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.0."; + throw Exception(os.str().c_str()); + } + } + + if (hexVersion < 0x02050000) + { + if (cs->getInterchangeAttributes().size()>0) + { + std::ostringstream os; + os << "Config failed validation. The color space '" << cs->getName() << "' "; + os << "has non-empty interchange attributes and config version is less than 2.5."; + throw Exception(os.str().c_str()); + } } } diff --git a/src/OpenColorIO/Context.cpp b/src/OpenColorIO/Context.cpp index 3a1294be5..b7e71ae6e 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 c0e7cbef1..9830d0a46 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 b1cee1898..b7d9172b9 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -33,6 +33,33 @@ namespace { typedef YAML::const_iterator Iterator; +std::string SanitizeNewlines(const std::string &input) +{ + if (input.empty()) + return input; + + // YAML is changing the trailing newlines when reading them: + // - Written as YAML::Literal (starts with a "|"), descriptions will be read back with a + // single newline. One is added if there was none, only one is kept if there were + // several. + // - Written as YAML::Value string (does not start with "|"), all trailing newlines ('\n') + // are preserved. + // Trailing newlines are inconsistently preserved, lets remove them in all cases. + std::string str = input; + auto last = str.back(); + while (last == '\n' && str.length()) + { + str.pop_back(); + last = str.back(); + } + + // Also, note that a \n is only interpreted as a newline if it is used in a string that is + // within double quotes. E.g., "A string \n with embedded \n newlines." Indeed, without the + // double quotes the backslash is generally not interpreted as an escape character in YAML. + + return str; +} + // Basic types inline void load(const YAML::Node& node, bool& x) @@ -185,25 +212,7 @@ inline void save(YAML::Emitter& out, Interpolation interp) inline void loadDescription(const YAML::Node& node, std::string& x) { load(node, x); - if (!x.empty()) - { - // YAML is changing the trailing newlines when reading them: - // - Written as YAML::Literal (starts with a "|"), descriptions will be read back with a - // single newline. One is added if there was none, only one is kept if there were - // several. - // - Written as YAML::Value string (does not start with "|"), all trailing newlines ('\n') - // are preserved. - // Trailing newlines are inconsistently preserved, lets remove them in all cases. - auto last = x.back(); - while (last == '\n' && x.length()) - { - x.pop_back(); - last = x.back(); - } - } - // Also, note that a \n is only interpreted as a newline if it is used in a string that is - // within double quotes. E.g., "A string \n with embedded \n newlines." Indeed, without the - // double quotes the backslash is generally not interpreted as an escape character in YAML. + x = SanitizeNewlines(x); } inline void saveDescription(YAML::Emitter & out, const char * desc) @@ -211,15 +220,7 @@ inline void saveDescription(YAML::Emitter & out, const char * desc) if (desc && *desc) { // Remove trailing newlines so that only one is saved because they won't be read back. - std::string descStr{ desc }; - { - auto last = descStr.back(); - while (last == '\n' && descStr.length()) - { - descStr.pop_back(); - last = descStr.back(); - } - } + std::string descStr = SanitizeNewlines(desc); out << YAML::Key << "description" << YAML::Value; if (descStr.find_first_of('\n') != std::string::npos) @@ -229,7 +230,6 @@ inline void saveDescription(YAML::Emitter & out, const char * desc) out << descStr; } } -// inline void LogUnknownKeyWarning(const YAML::Node & node, const YAML::Node & key) @@ -319,6 +319,31 @@ inline void CheckDuplicates(const YAML::Node & node) } } +// Custom Key Loader + +struct CustomKeysLoader +{ + using Type = std::vector>; + Type m_keyVals; +}; + +inline void loadCustomKeys(const YAML::Node& node, CustomKeysLoader & ck, const char* sectionName) +{ + if (node.Type() == YAML::NodeType::Map) + { + for (Iterator iter = node.begin(); iter != node.end(); ++iter) + { + ck.m_keyVals.push_back(std::make_pair(iter->first, iter->second)); + } + } + else + { + std::ostringstream ss; + ss << "Expected a YAML map in the " << sectionName << " section."; + throwError(node, ss.str().c_str()); + } +} + // View inline void load(const YAML::Node& node, View& v) @@ -3202,11 +3227,38 @@ 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 == "interchange") + { + CustomKeysLoader kv; + loadCustomKeys(iter->second, kv, "ColorSpace interchange"); + + for (const auto& keyval : kv.m_keyVals) + { + std::string keystr = keyval.first.as(); + std::string valstr = keyval.second.as(); + valstr = SanitizeNewlines(valstr); + + // OCIO exception means the key is not recognized. Convert that to a warning. + try + { + cs->setInterchangeAttribute(keystr.c_str(), valstr.c_str()); + } + catch (Exception &) + { + LogUnknownKeyWarning(key, keyval.first); + } + } + } else if(key == "family") { load(iter->second, stringval); @@ -3323,11 +3375,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 << "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; save(out, cs->getBitDepth()); + saveDescription(out, cs->getDescription()); + out << YAML::Key << "isdata" << YAML::Value << cs->isData(); if(cs->getNumCategories() > 0) @@ -3348,6 +3412,27 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int major out << YAML::Value << is; } + auto interchangemap = cs->getInterchangeAttributes(); + if (interchangemap.size()) + { + out << YAML::Key << "interchange"; + out << YAML::Value; + out << YAML::BeginMap; + for (const auto& keyval : interchangemap) + { + std::string valStr = SanitizeNewlines(keyval.second); + + out << YAML::Key << keyval.first << YAML::Value; + if (valStr.find_first_of('\n') != std::string::npos) + { + out << YAML::Literal; + } + out << valStr; + } + + out << YAML::EndMap; + } + out << YAML::Key << "allocation" << YAML::Value; save(out, cs->getAllocation()); if(cs->getAllocationNumVars() > 0) @@ -3778,30 +3863,6 @@ inline void save(YAML::Emitter & out, ConstNamedTransformRcPtr & nt, unsigned in // File rules -struct CustomKeysLoader -{ - StringUtils::StringVec m_keyVals; -}; - -inline void loadCustomKeys(const YAML::Node& node, CustomKeysLoader & ck) -{ - if (node.Type() == YAML::NodeType::Map) - { - for (Iterator iter = node.begin(); iter != node.end(); ++iter) - { - const std::string & key = iter->first.as(); - const std::string & val = iter->second.as(); - - ck.m_keyVals.push_back(key); - ck.m_keyVals.push_back(val); - } - } - else - { - throwError(node, "The 'file_rules' custom attributes need to be a YAML map."); - } -} - inline void load(const YAML::Node & node, FileRulesRcPtr & fr, bool & defaultRuleFound) { if (node.Tag() != "Rule") @@ -3811,7 +3872,7 @@ inline void load(const YAML::Node & node, FileRulesRcPtr & fr, bool & defaultRul std::string stringval; std::string name, colorspace, pattern, extension, regex; - StringUtils::StringVec keyVals; + CustomKeysLoader::Type keyVals; for (Iterator iter = node.begin(); iter != node.end(); ++iter) { @@ -3847,7 +3908,7 @@ inline void load(const YAML::Node & node, FileRulesRcPtr & fr, bool & defaultRul else if (key == FileRuleUtils::CustomKey) { CustomKeysLoader kv; - loadCustomKeys(iter->second, kv); + loadCustomKeys(iter->second, kv, "file_rules custom attribute"); keyVals = kv.m_keyVals; } else @@ -3918,11 +3979,15 @@ inline void load(const YAML::Node & node, FileRulesRcPtr & fr, bool & defaultRul fr->insertRule(pos, name.c_str(), colorspace.c_str(), regex.c_str()); } } - const auto numKeyVal = keyVals.size() / 2; - for (size_t i = 0; i < numKeyVal; ++i) + + for (const auto& keyval : keyVals) { - fr->setCustomKey(pos, keyVals[i * 2].c_str(), keyVals[i * 2 + 1].c_str()); + fr->setCustomKey( + pos, + keyval.first.as().c_str(), + keyval.second.as().c_str()); } + } catch (Exception & ex) { @@ -3985,7 +4050,7 @@ inline void load(const YAML::Node & node, ViewingRulesRcPtr & vr) std::string stringval; std::string name; StringUtils::StringVec colorspaces, encodings; - StringUtils::StringVec keyVals; + CustomKeysLoader::Type keyVals; for (Iterator iter = node.begin(); iter != node.end(); ++iter) { @@ -4027,7 +4092,7 @@ inline void load(const YAML::Node & node, ViewingRulesRcPtr & vr) else if (key == ViewingRuleUtils::CustomKey) { CustomKeysLoader kv; - loadCustomKeys(iter->second, kv); + loadCustomKeys(iter->second, kv, "viewing_rules custom attribute"); keyVals = kv.m_keyVals; } else @@ -4050,10 +4115,12 @@ inline void load(const YAML::Node & node, ViewingRulesRcPtr & vr) vr->addEncoding(pos, is.c_str()); } - const auto numKeyVal = keyVals.size() / 2; - for (size_t i = 0; i < numKeyVal; ++i) + for (const auto& keyval : keyVals) { - vr->setCustomKey(pos, keyVals[i * 2].c_str(), keyVals[i * 2 + 1].c_str()); + vr->setCustomKey( + pos, + keyval.first.as().c_str(), + keyval.second.as().c_str()); } } catch (Exception & ex) @@ -4754,10 +4821,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 1dbd846f3..0e7fc68b2 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("String pointer for comparison must not be null."); + } + #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("String pointer for comparison must not be null."); + } + #ifdef _WIN32 return ::_strnicmp(str1, str2, n); #else diff --git a/src/OpenColorIO/ViewTransform.cpp b/src/OpenColorIO/ViewTransform.cpp index 0a7ca2109..7fd8914a3 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/OpenColorIO/ViewingRules.cpp b/src/OpenColorIO/ViewingRules.cpp index be780c94e..bbe27172c 100644 --- a/src/OpenColorIO/ViewingRules.cpp +++ b/src/OpenColorIO/ViewingRules.cpp @@ -38,8 +38,6 @@ class ViewingRule { public: - using CustomKeys = std::map; - ViewingRule() = delete; ViewingRule(const ViewingRule &) = delete; ViewingRule & operator=(const ViewingRule &) = delete; diff --git a/src/apps/ociocheck/main.cpp b/src/apps/ociocheck/main.cpp index b3c8c3385..5c66a7eba 100644 --- a/src/apps/ociocheck/main.cpp +++ b/src/apps/ociocheck/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace OCIO = OCIO_NAMESPACE; @@ -26,6 +27,83 @@ const char * DESC_STRING = "\n\n" "Ociocheck can also be used to clean up formatting on an existing profile\n" "that has been manually edited, using the '-o' option.\n"; + +// returns true if the interopID is valid +bool isValidInteropID(const std::string& id) +{ + // See https://github.com/AcademySoftwareFoundation/ColorInterop for the details. + + static const std::set cifTextureIDs = { + "lin_ap1_scene", + "lin_ap0_scene", + "lin_rec709_scene", + "lin_p3d65_scene", + "lin_rec2020_scene", + "lin_adobergb_scene", + "lin_ciexyzd65_scene", + "srgb_rec709_scene", + "g22_rec709_scene", + "g18_rec709_scene", + "srgb_ap1_scene", + "g22_ap1_scene", + "srgb_p3d65_scene", + "g22_adobergb_scene", + "data", + "unknown" + }; + + static const std::set cifDisplayIDs = { + "srgb_rec709_display", + "g24_rec709_display", + "srgb_p3d65_display", + "srgbx_p3d65_display", + "pq_p3d65_display", + "pq_rec2020_display", + "hlg_rec2020_display", + "g22_rec709_display", + "g22_adobergb_display", + "g26_p3d65_display", + "g26_xyzd65_display", + "pq_xyzd65_display", + }; + + if (id.empty()) + return true; + + // Check if has a namespace. + size_t pos = id.find(':'); + if (pos == std::string::npos) + { + // No namespace, so id must be in the Color Interop Forum ID list. + if (cifTextureIDs.count(id) == 0 && cifDisplayIDs.count(id)==0) + { + std::cout << "ERROR: InteropID '" << id << "' is not valid. " + "It should either be one of Color Interop Forum standard IDs or " + "it must contain a namespace followed by ':', e.g. 'mycompany:mycolorspace'." << + std::endl; + return false; + } + } + else + { + // Namespace found, split into namespace and id. + std::string ns = id.substr(0, pos); + std::string cs = id.substr(pos+1); + + // Id should not be in the Color Interop Forum ID list. + if (cifTextureIDs.count(cs) > 0 || cifDisplayIDs.count(cs)> 0) + { + std::cout << "ERROR: InteropID '" << id << "' is not valid. " + "The ID part must not be one of the Color Interop Forum standard IDs when a namespace is used." << + std::endl; + return false; + } + } + + // all clear. + return true; +} + int main(int argc, const char **argv) { bool help = false; @@ -298,6 +376,15 @@ int main(int argc, const char **argv) OCIO::COLORSPACE_ALL, i)); + std::string interopID = cs->getInteropID(); + if (!interopID.empty()) + { + if (!isValidInteropID(interopID)) + { + errorcount += 1; + } + } + // Try to load the transform for the to_ref direction -- this will load any LUTs. bool toRefOK = true; std::string toRefErrorText; diff --git a/src/apps/ocioconvert/main.cpp b/src/apps/ocioconvert/main.cpp index e8071c76f..31a5ed354 100644 --- a/src/apps/ocioconvert/main.cpp +++ b/src/apps/ocioconvert/main.cpp @@ -658,6 +658,14 @@ int main(int argc, const char **argv) if (outputcolorspace) { imgOutput->attribute("oiio:ColorSpace", outputcolorspace); + + // Set the color space interopID if available. + auto cs = config->getColorSpace(outputcolorspace); + const char* interopID = cs ? cs->getInteropID() : nullptr; + if(interopID && *interopID) + { + imgOutput->attribute("colorInteropID", interopID); + } } imgOutput->write(outputimage, userOutputBitDepth); diff --git a/src/bindings/python/PyColorSpace.cpp b/src/bindings/python/PyColorSpace.cpp index 6827943bc..7007ac8b3 100644 --- a/src/bindings/python/PyColorSpace.cpp +++ b/src/bindings/python/PyColorSpace.cpp @@ -61,7 +61,7 @@ void bindPyColorSpace(py::module & m) py::class_( clsColorSpace, "ColorSpaceCategoryIterator"); - auto clsColorSpacAliasIterator = + auto clsColorSpaceAliasIterator = py::class_( clsColorSpace, "ColorSpaceAliasIterator"); @@ -90,7 +90,9 @@ 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 + ) { ColorSpaceRcPtr p = ColorSpace::Create(referenceSpace); if (!aliases.empty()) @@ -102,11 +104,12 @@ 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()); } p->setBitDepth(bitDepth); p->setIsData(isData); p->setAllocation(allocation); @@ -150,6 +153,7 @@ 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(), DOC(ColorSpace, Create, 2)) .def("__deepcopy__", [](const ConstColorSpaceRcPtr & self, py::dict) @@ -193,6 +197,16 @@ 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("getInterchangeAttribute", &ColorSpace::getInterchangeAttribute, "attrName"_a, + DOC(ColorSpace, getInterchangeAttribute)) + .def("setInterchangeAttribute", &ColorSpace::setInterchangeAttribute, "attrName"_a, "attrValue"_a, + DOC(ColorSpace, setInterchangeAttribute)) + .def("getInterchangeAttributes", &ColorSpace:: getInterchangeAttributes, + DOC(ColorSpace, getInterchangeAttributes)) .def("getBitDepth", &ColorSpace::getBitDepth, DOC(ColorSpace, getBitDepth)) .def("setBitDepth", &ColorSpace::setBitDepth, "bitDepth"_a, @@ -268,7 +282,7 @@ void bindPyColorSpace(py::module & m) return it.m_obj->getCategory(i); }); - clsColorSpacAliasIterator + clsColorSpaceAliasIterator .def("__len__", [](ColorSpaceAliasIterator & it) { return it.m_obj->getNumAliases(); diff --git a/src/libutils/imageioapphelpers/imageio.cpp b/src/libutils/imageioapphelpers/imageio.cpp index b1701f890..cda93b3e3 100644 --- a/src/libutils/imageioapphelpers/imageio.cpp +++ b/src/libutils/imageioapphelpers/imageio.cpp @@ -192,6 +192,9 @@ ptrdiff_t ImageIO::getImageBytes() const void ImageIO::init(const ImageIO & img, BitDepth bitDepth) { m_impl->init(*img.m_impl, bitDepth); + + // Do not propagate colorInteropID. + attribute("colorInteropID", "unknown"); } void ImageIO::init(long width, long height, ChannelOrdering chanOrder, BitDepth bitDepth) diff --git a/tests/cpu/CPUProcessor_tests.cpp b/tests/cpu/CPUProcessor_tests.cpp index c2fed3902..925a75397 100644 --- a/tests/cpu/CPUProcessor_tests.cpp +++ b/tests/cpu/CPUProcessor_tests.cpp @@ -57,8 +57,9 @@ OCIO_ADD_TEST(CPUProcessor, flag_composition) // a missing/partial optimization. -template -OCIO::ConstCPUProcessorRcPtr ComputeValues(OCIO::ConstProcessorRcPtr processor, +template +OCIO::ConstCPUProcessorRcPtr ComputeValues(unsigned line, + OCIO::ConstProcessorRcPtr processor, const void * inImg, OCIO::ChannelOrdering inChans, const void * resImg, @@ -147,12 +148,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.5025f, 0.9050f, 1.5896f, 1.5000f, 2.4002f, 1.6505f, 2.0707f, 0.5000f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, + 1e-5f); } { @@ -161,12 +162,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 0.182999f, 0.9050f, 2.9091f, 1.5000f, 1.0807f, 1.6505f, 3.3902f, 0.5000f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS, + 1e-5f); } { @@ -175,12 +176,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 0.602300f, 0.585199f, 1.909399f, 2.400200f, 1.500000f, 1.330700f, 2.390500f, 1.400200f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_ABGR, - &resImg[0], OCIO::CHANNEL_ORDERING_ABGR, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_ABGR, + &resImg[0], OCIO::CHANNEL_ORDERING_ABGR, + NB_PIXELS, + 1e-5f); } { @@ -189,12 +190,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.5896f, 0.9050f, 1.5025f, 1.5000f, 2.0707f, 1.6505f, 2.4002f, 0.5000f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS, + 1e-5f); } { @@ -203,12 +204,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.5000f, 1.5896f, 0.9050f, 1.5025f, 0.5000f, 2.0707f, 1.6505f, 2.4002f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_ABGR, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_ABGR, + NB_PIXELS, + 1e-5f); } { @@ -222,12 +223,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.5025f, 0.9050f, 1.5896f, 2.4002f, 1.6505f, 2.0707f }; - ComputeValues(processor, - &inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &resImg[0], OCIO::CHANNEL_ORDERING_RGB, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &resImg[0], OCIO::CHANNEL_ORDERING_RGB, + NB_PIXELS, + 1e-5f); } { @@ -241,12 +242,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 0.182999f, 0.905000f, 2.909100f, 1.080700f, 1.650500f, 3.390200f }; - ComputeValues(processor, - &inImg[0], OCIO::CHANNEL_ORDERING_BGR, - &resImg[0], OCIO::CHANNEL_ORDERING_BGR, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &inImg[0], OCIO::CHANNEL_ORDERING_BGR, + &resImg[0], OCIO::CHANNEL_ORDERING_BGR, + NB_PIXELS, + 1e-5f); } { @@ -260,12 +261,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.58960f, 0.9050f, 1.5025f, 2.070699f, 1.6505f, 2.4002f }; - ComputeValues(processor, - &inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &resImg[0], OCIO::CHANNEL_ORDERING_BGR, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &resImg[0], OCIO::CHANNEL_ORDERING_BGR, + NB_PIXELS, + 1e-5f); } { @@ -279,12 +280,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.58960f, 0.9050f, 1.5025f, 0.5f, 2.070699f, 1.6505f, 2.4002f, 0.5f }; - ComputeValues(processor, - &inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS, + 1e-5f); } { @@ -298,12 +299,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.58960f, 0.9050f, 1.5025f, 2.070699f, 1.6505f, 2.4002f }; - ComputeValues(processor, - &inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGR, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGR, + NB_PIXELS, + 1e-5f); } const std::vector ui16_inImg = @@ -317,12 +318,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1.40117657f, 0.40245315f, 0.08460631f, 0.5f, 1.47832620f, 0.70781672f, 1.08070004f, 0.5f }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, - 1e-5f); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, + 1e-5f); } { @@ -331,11 +332,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 65535, 26375, 5545, 32768, 65535, 46387, 65535, 32768 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -344,11 +345,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 5545, 26375, 65535, 32768, 65535, 46387, 65535, 32768 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } { @@ -357,11 +358,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 5545, 26375, 65535, 65535, 46387, 65535 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGR, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGR, + NB_PIXELS); } { @@ -370,11 +371,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 255, 103, 22, 128, 255, 180, 255, 128 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -383,11 +384,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 22, 103, 255, 255, 180, 255 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGR, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGR, + NB_PIXELS); } { @@ -396,11 +397,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 128, 22, 103, 255, 128, 255, 180, 255 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_ABGR, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_ABGR, + NB_PIXELS); } // Test OCIO::BIT_DEPTH_UINT10. @@ -411,11 +412,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 1023, 412, 87, 512, 1023, 724, 1023, 512 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &ui10_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &ui10_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); const std::vector ui10_inImg = { 0, 8, 12, 256, @@ -427,11 +428,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 65535, 27272, 9389, 65535, 65535, 28297, 11439, 65535 }; - ComputeValues(processor, - &ui10_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui10_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } // Test OCIO::BIT_DEPTH_UINT12. @@ -442,11 +443,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 4095, 1648, 346, 2048, 4095, 2899, 4095, 2048 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &ui12_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &ui12_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); const std::vector ui12_inImg = { 0, 8, 12, 1024, @@ -458,11 +459,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_matrix) 65535, 26503, 6313, 65535, 65535, 26759, 6825, 65535 }; - ComputeValues(processor, - &ui12_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui12_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } } @@ -499,12 +500,12 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 0.29089212f, 0.50935059f, 1.91091322f, 1, 64, 64, 64, 0 }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, - 1e-7f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, + 1e-7f); } { @@ -514,11 +515,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 19064, 33380, 65535, 65535, 65535, 65535, 65535, 0 }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } const std::vector ui16_inImg = @@ -534,11 +535,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 0.00601041f, 0.00912247f, 0.01456576f, 0.00097657f, 0.03030112f, 0.13105739f, 64, 0.00781261f }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, 1e-7f); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, 1e-7f); } { @@ -548,11 +549,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 394, 598, 955, 64, 1986, 8589, 65535, 512 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -562,11 +563,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 955, 598, 394, 64, 65535, 8589, 1986, 512 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -576,11 +577,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 955, 598, 394, 64, 65535, 8589, 1986, 512 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } { @@ -590,11 +591,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 955, 598, 394, 65535, 8589, 1986 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGR, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGR, + NB_PIXELS); } { @@ -604,11 +605,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 394, 598, 955, 64, 1986, 8589, 65535, 512 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } { @@ -624,11 +625,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 955, 598, 394, 0, 65535, 8589, 1986, 0 }; - ComputeValues(processor, - &my_i_inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &my_i_inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } // Test OCIO::BIT_DEPTH_UINT10. @@ -640,11 +641,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 6, 9, 15, 1, 31, 134, 1023, 8 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &ui10_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &ui10_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -660,11 +661,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 36, 106, 252, 0, 48, 1023, 384, 0 }; - ComputeValues(processor, - &ui10_inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &ui10_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui10_inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &ui10_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); const std::vector ui16_resImg = { 0, 394, 955, 0, @@ -672,11 +673,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 2301, 6794, 16162, 0, 3092, 65535, 24593, 0 }; - ComputeValues(processor, - &ui10_inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui10_inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } // Test OCIO::BIT_DEPTH_UINT12. @@ -688,11 +689,11 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 25, 37, 60, 4, 124, 537, 4095, 32 }; - ComputeValues(processor, - &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &ui12_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui16_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &ui12_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -708,22 +709,22 @@ OCIO_ADD_TEST(CPUProcessor, with_one_1d_lut) 49, 103, 193, 0, 424, 1009, 4095, 0 }; - ComputeValues(processor, - &ui12_inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &ui12_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui12_inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &ui12_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); const std::vector ui16_resImg = { 0, 178, 394, 0, 598, 955, 1655, 0, 779, 1655, 3089, 0, 6789, 16143, 65535, 0 }; - ComputeValues(processor, - &ui12_inImg[0], OCIO::CHANNEL_ORDERING_RGB, - &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &ui12_inImg[0], OCIO::CHANNEL_ORDERING_RGB, + &ui16_resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } } @@ -794,11 +795,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 0.15488569f, 1.69210147f, 1.90666747f, 1.0f, 0.81575858f, 64.0f, 64.0f, 0.0f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, 1e-7f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, 1e-7f); } { @@ -808,11 +809,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 10150, 65535, 65535, 65535, 53461, 65535, 65535, 0 }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } const std::vector i_inImg = @@ -828,12 +829,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 0.0f, 0.08474064f, 0.01450117f, 0.0f, 0.0f, 0.24826171f, 56.39490891f, 1.0f }; - auto cpuProcessor = ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, 1e-7f); + auto cpuProcessor = ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, 1e-7f); // SSE2/AVX/AVX2 generate a slightly different LUT1D // floating error below the absErrorThreshold, but cacheID hash will be different @@ -874,11 +874,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 0, 5553, 950, 0, 0, 16270, 65535, 65535 }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -888,11 +888,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 0, 5553, 388, 0, 53461, 16270, 1982, 65535 }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } { @@ -902,11 +902,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 950, 5553, 0, 0, 65535, 16270, 0, 65535 }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } { @@ -916,11 +916,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 388, 5553, 0, 0, 1982, 16270, 53461, 65535 }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } } @@ -960,11 +960,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 0.10089212f, 0.69935059f, 1.91072320f, 1.0f, 63.81000137f, 64.19000244f, 63.99980927f, 0.0f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, 1e-7f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, 1e-7f); } { @@ -974,11 +974,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 6612, 45832, 65535, 65535, 65535, 65535, 65535, 0 }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS); } const std::vector i_inImg = @@ -993,11 +993,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) -0.18398958f, 0.19912247f, 0.01437576f, 0.0f, -0.15969887f, 0.32105737f, 63.99980927f, 0.0f }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, 1e-7f); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, 1e-7f); } { @@ -1007,11 +1007,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 381, 13049, 0, 0, 1973, 21040, 65535, 0 }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } } @@ -1053,11 +1053,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) -0.23451784f, 0.92250210f, 3.26448941f, 1.0f, 3.43709063f, 3.43709063f, 3.43709063f, 0.0f }; - ComputeValues(processor, - &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, - &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, - NB_PIXELS, 1e-7f); + ComputeValues( + __LINE__, processor, + &f_inImg[0], OCIO::CHANNEL_ORDERING_RGBA, + &resImg[0], OCIO::CHANNEL_ORDERING_RGBA, + NB_PIXELS, 1e-7f); } const std::vector i_inImg = @@ -1073,11 +1073,11 @@ OCIO_ADD_TEST(CPUProcessor, with_several_ops) 0, 0, 0, 0, 0, 12526, 65535, 0 }; - ComputeValues(processor, - &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, - &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, - NB_PIXELS); + ComputeValues( + __LINE__, processor, + &i_inImg[0], OCIO::CHANNEL_ORDERING_BGRA, + &resImg[0], OCIO::CHANNEL_ORDERING_BGRA, + NB_PIXELS); } } } diff --git a/tests/cpu/ColorSpace_tests.cpp b/tests/cpu/ColorSpace_tests.cpp index 54521be17..1e47ef811 100644 --- a/tests/cpu/ColorSpace_tests.cpp +++ b/tests/cpu/ColorSpace_tests.cpp @@ -10,6 +10,7 @@ #include "testutils/UnitTest.h" #include "UnitTestUtils.h" +#include "UnitTestLogUtils.h" namespace OCIO = OCIO_NAMESPACE; @@ -39,7 +40,39 @@ 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. + // First set the fields to non-empty values. + cs->setName("NAME"); + cs->setDescription("DESC"); + cs->setFamily("FAMILY"); + cs->setEqualityGroup("EQGRP"); + cs->setEncoding("ENC"); + cs->setInteropID("interop"); + OCIO_CHECK_NO_THROW(cs->setInterchangeAttribute("amf_transform_ids", "AMF")); + OCIO_CHECK_NO_THROW(cs->setInterchangeAttribute("icc_profile_name", "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)); + OCIO_CHECK_NO_THROW(cs->setEqualityGroup(nullptr)); + OCIO_CHECK_NO_THROW(cs->setEncoding(nullptr)); + OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); + OCIO_CHECK_NO_THROW(cs->setInterchangeAttribute("amf_transform_ids", nullptr)); + OCIO_CHECK_NO_THROW(cs->setInterchangeAttribute("icc_profile_name", 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->getInteropID()); + OCIO_CHECK_ASSERT(!*cs->getInterchangeAttribute("amf_transform_ids")); + OCIO_CHECK_ASSERT(!*cs->getInterchangeAttribute("icc_profile_name")); + + // Test set/get roundtrip. cs->setName("name"); OCIO_CHECK_EQUAL(std::string("name"), cs->getName()); cs->setFamily("family"); @@ -63,10 +96,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->setInterchangeAttribute("amf_transform_ids", "amf_transform_id1\namf_transform_id2"); + OCIO_CHECK_EQUAL(std::string("amf_transform_id1\namf_transform_id2"), + cs->getInterchangeAttribute("amf_transform_ids")); + cs->setInterchangeAttribute("icc_profile_name","icc_profile_name"); + OCIO_CHECK_EQUAL(std::string("icc_profile_name"), cs->getInterchangeAttribute("icc_profile_name")); std::ostringstream oss; oss << *cs; - OCIO_CHECK_EQUAL(oss.str().size(), 193); + OCIO_CHECK_EQUAL(oss.str().size(), 306); } OCIO_ADD_TEST(ColorSpace, alias) @@ -256,7 +296,7 @@ active_views: [] OCIO_CHECK_EQUAL(cfgString, os.str()); } - // Adding a color space that uses all parameters. + // Adding a color space that uses all parameters (as of 2.0). { constexpr char End[]{ R"(colorspaces: - ! @@ -619,6 +659,207 @@ active_views: [] OCIO_CHECK_EQUAL(cfgRes, os.str()); } + + // Test that the interop_id is valid in v2.0 config too. + { + constexpr char End[]{R"(colorspaces: + - ! + name: raw + aliases: [ data ] + interop_id: data + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + std::string cfgString{Start}; + cfgString += End; + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + auto cs = config->getColorSpace("raw"); + OCIO_CHECK_ASSERT(cs); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), "data"); + + OCIO_CHECK_NO_THROW(config->validate()); + } + + // Test that the undefined interop_id does not pass validation + { + 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; + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + auto cs = config->getColorSpace("raw"); + OCIO_CHECK_ASSERT(cs); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), "data"); + + OCIO_CHECK_THROW_WHAT(config->validate(), + OCIO::Exception, + "Config failed color space validation. The color space 'raw' refers " + "to an interop ID, 'data', which is not defined in this config."); + } + + // Test that the interop id can be found in another color space. + { + constexpr char End[]{R"(colorspaces: + - ! + name: raw + interop_id: data + family: raw + equalitygroup: "" + bitdepth: 32f + description: one data color space. + isdata: true + allocation: uniform + - ! + name: data + interop_id: data + family: raw + equalitygroup: "" + bitdepth: 32f + description: another data color space. + isdata: true + allocation: uniform +)"}; + std::string cfgString{Start}; + cfgString += End; + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + + OCIO_CHECK_NO_THROW(config->validate()); + } + + // Test that the interchange is NOT valid in v2.0 config. + { + constexpr char End[]{R"(colorspaces: + - ! + name: raw + interchange: + amf_transform_ids: should NOT be valid in 2.0 config + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + 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 " + "interchange attributes and config version is less than 2.5."); + } + + // Interchange tests in 2.5 + constexpr char Start2_5[]{R"(ocio_profile_version: 2.5 + +environment: + {} +search_path: "" +strictparsing: false +luma: [0.2126, 0.7152, 0.0722] + +roles: + default: raw + +file_rules: + - ! {name: ColorSpaceNamePathSearch} + - ! {name: Default, colorspace: default} + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + +active_displays: [] +active_views: [] + +)"}; + + // Test that the interchange is valid in v2.5 config. + { + constexpr char End_amf[]{R"( +colorspaces: + - ! + name: raw + interchange: + amf_transform_ids: This is valid in 2.5 config + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + + std::string cfgString{Start2_5}; + cfgString += End_amf; + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_REQUIRE_EQUAL(!config, false); + auto attrMap = config->getColorSpace("raw")->getInterchangeAttributes(); + OCIO_CHECK_EQUAL(attrMap.size(), 1); + } + + // Test that the unknown interchange attrib will be ignored in 2.5. + { + constexpr char End_unkown[]{R"( +colorspaces: + - ! + name: raw + interchange: + my-attrib: will be ignored + family: raw + equalitygroup: "" + bitdepth: 32f + description: Some text. + isdata: true + allocation: uniform +)"}; + + std::string cfgString{Start2_5}; + cfgString += End_unkown; + + std::istringstream is; + is.str(cfgString); + OCIO::ConstConfigRcPtr config; + OCIO::LogGuard logGuard; + OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + OCIO_CHECK_EQUAL(logGuard.output(), "[OpenColorIO Warning]: Unknown key in interchange: 'my-attrib'.\n"); + OCIO_REQUIRE_EQUAL(!config, false); + auto attrMap = config->getColorSpace("raw")->getInterchangeAttributes(); + OCIO_CHECK_EQUAL(attrMap.size(), 0); + } } OCIO_ADD_TEST(Config, use_alias) @@ -734,6 +975,320 @@ active_views: [] "colorspace"); } +OCIO_ADD_TEST(ColorSpace, interop_id) +{ + OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); + + // Test default value. + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); + + // 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->getInteropID()), ""); + + // 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). + cs->setInteropID("something"); + OCIO_CHECK_NO_THROW(cs->setInteropID(nullptr)); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), ""); + + // Test copy constructor preserves InteropID. + cs->setInteropID(interop_id); + OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); + OCIO_CHECK_EQUAL(std::string(copy->getInteropID()), interop_id); + + // Test valid InteropID with colon in the middle. + const char * validColonMiddle = "namespace:colorspace_name"; + OCIO_CHECK_NO_THROW(cs->setInteropID(validColonMiddle)); + OCIO_CHECK_EQUAL(std::string(cs->getInteropID()), validColonMiddle); + + // Test invalid InteropID with multiple colons. + OCIO_CHECK_THROW_WHAT(cs->setInteropID("name:space:cs_name"), OCIO::Exception, + "Only one ':' is allowed to separate the namespace and the color space."); + + // Test invalid InteropID with colon at the end. + OCIO_CHECK_THROW_WHAT(cs->setInteropID("namespace:"), OCIO::Exception, + " If ':' is used, both the namespace and the color space parts must be non-empty."); + + // Test invalid InteropID with empty namespace or color space. + OCIO_CHECK_THROW_WHAT(cs->setInteropID(":cs_name"), OCIO::Exception, + "If ':' is used, both the namespace and the color space parts must be non-empty."); + + // Test invalid InteropID with illegal characters. + OCIO_CHECK_THROW_WHAT(cs->setInteropID("café_scene"), OCIO::Exception, + "Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed."); + + OCIO_CHECK_THROW_WHAT(cs->setInteropID("UPPERCASE"), OCIO::Exception, + "Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed."); + + OCIO_CHECK_THROW_WHAT(cs->setInteropID("{curly_bracket}"), OCIO::Exception, + "Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed."); + + OCIO_CHECK_THROW_WHAT(cs->setInteropID("\\backslash"), OCIO::Exception, + "Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed."); + + OCIO_CHECK_THROW_WHAT(cs->setInteropID(" space "), OCIO::Exception, + "Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed."); +} + +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 versions earlier than 2.0 reject interop_id. + OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); + cfgCopy->setVersion(2, 0); + OCIO_CHECK_NO_THROW(cfgCopy->serialize(ss)); + + cfgCopy->setVersion(1, 0); + 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.0."); + + // 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 interop_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->getInterchangeAttribute("amf_transform_ids")), ""); + + // Test setting and getting single ID. + const char * singleID = "urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3"; + cs->setInterchangeAttribute("amf_transform_ids", singleID); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("amf_transform_ids")), singleID); + + // Test setting to empty string. + cs->setInterchangeAttribute("amf_transform_ids", ""); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("amf_transform_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->setInterchangeAttribute("amf_transform_ids", multipleIDs); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("amf_transform_ids")), multipleIDs); + + // Test setting to null pointer (should be safe). + cs->setInterchangeAttribute("amf_transform_ids", "something"); + cs->setInterchangeAttribute("amf_transform_ids", nullptr); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("amf_transform_ids")), ""); + + // Test copy constructor preserves AMF transform IDs. + cs->setInterchangeAttribute("amf_transform_ids", singleID); + OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); + OCIO_CHECK_EQUAL(std::string(copy->getInterchangeAttribute("amf_transform_ids")), 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->setInterchangeAttribute("amf_transform_ids", amfIDs.c_str()); + cfg->addColorSpace(cs); + + // Serialize the Config. + std::stringstream ss; + cfg->serialize(ss); + std::string yamlStr = ss.str(); + + // 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. + 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"); + auto deserializedIDs = deserializedCs->getInterchangeAttribute("amf_transform_ids"); + OCIO_CHECK_EQUAL(deserializedIDs, 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, + "has non-empty interchange attributes and config version is less than 2.5."); + + // Test with empty AmfTransformIDs (should not appear in YAML). + cs->setInterchangeAttribute("amf_transform_ids", 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("amf_transform_ids"), 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->getInterchangeAttribute("icc_profile_name")), ""); + + // Test setting and getting single profile name. + const char * profileName = "sRGB IEC61966-2.1"; + cs->setInterchangeAttribute("icc_profile_name",profileName); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("icc_profile_name")), profileName); + + // Test setting and getting another profile name. + const char * anotherProfile = "Adobe RGB (1998)"; + cs->setInterchangeAttribute("icc_profile_name", anotherProfile); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("icc_profile_name")), anotherProfile); + + // Test setting empty string. + cs->setInterchangeAttribute("icc_profile_name", ""); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("icc_profile_name")), ""); + + // Test setting null pointer (should be safe). + cs->setInterchangeAttribute("icc_profile_name", "something"); + OCIO_CHECK_NO_THROW(cs->setInterchangeAttribute("icc_profile_name", nullptr)); + OCIO_CHECK_EQUAL(std::string(cs->getInterchangeAttribute("icc_profile_name")), ""); + + // Test copy constructor preserves ICC profile name. + cs->setInterchangeAttribute("icc_profile_name", profileName); + OCIO::ColorSpaceRcPtr copy = cs->createEditableCopy(); + OCIO_CHECK_EQUAL(std::string(copy->getInterchangeAttribute("icc_profile_name")), 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->setInterchangeAttribute("icc_profile_name", 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("icc_profile_name"), 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->getInterchangeAttribute("icc_profile_name")), profileName); + + // verify that that earlier versions reject icc_profile_name. + OCIO::ConfigRcPtr cfgCopy = cfg->createEditableCopy(); + cfgCopy->setVersion(2, 4); + OCIO_CHECK_THROW_WHAT(cfgCopy->serialize(ss), + OCIO::Exception, + "has non-empty interchange attributes and config version is less than 2.5."); + + // Test with empty IccProfileName (should not appear in YAML, and so won't invalidate a 2.4 config). + cs->setInterchangeAttribute("icc_profile_name", 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("icc_profile_name"), std::string::npos); +} + +OCIO_ADD_TEST(ColorSpace, unknown_interchange_attrib) +{ + OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create(); + + // Getting should throw. + OCIO_CHECK_THROW_WHAT(std::string(cs->getInterchangeAttribute("unknown_attrib")), + OCIO::Exception, + "Unknown attribute name"); + + // Empty name is not legal. + OCIO_CHECK_THROW_WHAT(std::string(cs->getInterchangeAttribute("")), OCIO::Exception, + "Unknown attribute name"); + OCIO_CHECK_THROW_WHAT(std::string(cs->getInterchangeAttribute(nullptr)), OCIO::Exception, + "Unknown attribute name"); + + // Setting should throw too. + OCIO_CHECK_THROW_WHAT(cs->setInterchangeAttribute("unknown_attribute1", "unknown"), + OCIO::Exception, + "Unknown attribute name"); + OCIO_CHECK_THROW_WHAT(cs->setInterchangeAttribute("unknown_attribute2", ""), + OCIO::Exception, + "Unknown attribute name"); + OCIO_CHECK_THROW_WHAT(cs->setInterchangeAttribute("unknown_attribute3", nullptr), + OCIO::Exception, + "Unknown attribute name"); + + // Make sure none of the above was stored. + auto attrMap = cs->getInterchangeAttributes(); + OCIO_CHECK_EQUAL(attrMap.size(), 0); +} + OCIO_ADD_TEST(Config, is_colorspace_linear) { @@ -1702,3 +2257,4 @@ inactive_colorspaces: [scene-linear Rec.709-sRGB, ACES2065-1] ); } } + diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index b2a272f0e..383e15aa7 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 0860e7a3f..6fae105b6 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('data') + self.colorspace.setInterchangeAttribute('amf_transform_ids', 'urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3') + self.colorspace.setInterchangeAttribute('icc_profile_name', 'sRGB IEC61966-2.1') other = copy.deepcopy(self.colorspace) self.assertFalse(other is self.colorspace) @@ -59,6 +62,11 @@ 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.getInterchangeAttribute('amf_transform_ids'), self.colorspace.getInterchangeAttribute('amf_transform_ids')) + self.assertEqual(other.getInterchangeAttribute('icc_profile_name'), self.colorspace.getInterchangeAttribute('icc_profile_name')) + self.assertEqual(other.getInterchangeAttributes(), self.colorspace.getInterchangeAttributes()) + self.assertListEqual(list(other.getInterchangeAttributes().items()), list(self.colorspace.getInterchangeAttributes().items())) def test_allocation(self): """ @@ -279,6 +287,10 @@ 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.getInterchangeAttribute("amf_transform_ids"), '') + self.assertEqual(cs.getInterchangeAttribute("icc_profile_name"), '') + self.assertEqual(len(cs.getInterchangeAttributes()), 0) def test_data(self): """ @@ -421,6 +433,195 @@ def test_aliases(self): self.assertEqual(len(aliases), 0) self.assertFalse(cs.hasAlias('alias1')) + 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('something') + 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']) + + # Test valid InteropID with one colon (not at the end). + valid_with_colon = 'namespace:cs_name' + self.colorspace.setInteropID(valid_with_colon) + self.assertEqual(self.colorspace.getInteropID(), valid_with_colon) + + # Test invalid InteropID with multiple colons. + with self.assertRaises(Exception) as context: + self.colorspace.setInteropID('name:space:cs_name') + self.assertIn("Only one ':' is allowed to separate the namespace and the color space.", + str(context.exception)) + + # Test invalid InteropID with colon at the end. + with self.assertRaises(Exception) as context: + self.colorspace.setInteropID('namespace:') + self.assertIn("If ':' is used, both the namespace and the color space parts must be non-empty.", + str(context.exception)) + + # Test invalid InteropID with non-ASCII characters. + with self.assertRaises(Exception) as context: + self.colorspace.setInteropID('café_scene') # Contains é (UTF-8) + self.assertIn("contains invalid characters.", str(context.exception)) + + with self.assertRaises(Exception) as context: + self.colorspace.setInteropID('space±_name') # Contains ± (ANSI 0xB1) + self.assertIn("contains invalid characters.", str(context.exception)) + + def test_interchange_attributes(self): + """ + Test the setInterchangeAttribute() and getInterchangeAttribute() methods. + """ + # amf_transform_ids + + # Test default value (should be empty). + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), '') + + # Test setting and getting a single amf transform ID. + single_id = 'urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CG_to_ACES.a1.0.3' + self.colorspace.setInterchangeAttribute('amf_transform_ids', single_id) + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), single_id) + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 1) + self.assertEqual(self.colorspace.getInterchangeAttributes()["amf_transform_ids"], 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.setInterchangeAttribute('amf_transform_ids', multiple_ids) + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), multiple_ids) + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 1) + self.assertEqual(self.colorspace.getInterchangeAttributes()["amf_transform_ids"], multiple_ids) + + # Test setting empty string. + self.colorspace.setInterchangeAttribute('amf_transform_ids', '') + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), '') + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 0) + + # Test setting None (should convert to empty string). + self.colorspace.setInterchangeAttribute('amf_transform_ids', 'something') + self.colorspace.setInterchangeAttribute('amf_transform_ids', None) + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), '') + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 0) + + # Test with different line endings. + mixed_endings = 'id1\nid2\rid3\r\nid4' + self.colorspace.setInterchangeAttribute('amf_transform_ids', mixed_endings) + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), mixed_endings) + + # Test with leading/trailing whitespace. + whitespace_ids = ' \n id1 \n id2 \n ' + self.colorspace.setInterchangeAttribute('amf_transform_ids', whitespace_ids) + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), whitespace_ids) + + # Test wrong type (should raise TypeError). + with self.assertRaises(TypeError): + self.colorspace.setInterchangeAttribute('amf_transform_ids', 123) + + with self.assertRaises(TypeError): + self.colorspace.setInterchangeAttribute('amf_transform_ids', ['list', 'of', 'ids']) + + # clear amf_transform_ids for the next test + self.colorspace.setInterchangeAttribute('amf_transform_ids', '') + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 0) + + # icc_profile_name + + # Test default value (should be empty). + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), '') + + # Test setting and getting a simple profile name. + profile_name = 'sRGB IEC61966-2.1' + self.colorspace.setInterchangeAttribute('icc_profile_name', profile_name) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), profile_name) + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 1) + self.assertEqual(self.colorspace.getInterchangeAttributes()["icc_profile_name"], profile_name) + + # Test setting and getting a different profile name. + profile_name2 = 'Adobe RGB (1998)' + self.colorspace.setInterchangeAttribute('icc_profile_name', profile_name2) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), profile_name2) + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 1) + self.assertEqual(self.colorspace.getInterchangeAttributes()["icc_profile_name"], profile_name2) + + # Test with a more complex profile name. + complex_name = 'Display P3 - Apple Cinema Display (Calibrated 2023-01-15)' + self.colorspace.setInterchangeAttribute('icc_profile_name', complex_name) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), complex_name) + + # Test setting empty string. + self.colorspace.setInterchangeAttribute('icc_profile_name', '') + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), '') + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 0) + + # Test setting None (should convert to empty string). + self.colorspace.setInterchangeAttribute('icc_profile_name', 'something') + self.colorspace.setInterchangeAttribute('icc_profile_name', None) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), '') + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 0) + + # Test with special characters and numbers. + special_name = 'ProPhoto RGB v2.0 (γ=1.8) [Custom Profile #123]' + self.colorspace.setInterchangeAttribute('icc_profile_name', special_name) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), special_name) + + # Test with Unicode characters. + unicode_name = 'Профиль RGB γ=2.2' + self.colorspace.setInterchangeAttribute('icc_profile_name', unicode_name) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), unicode_name) + + # Test wrong type (should raise TypeError). + with self.assertRaises(TypeError): + self.colorspace.setInterchangeAttribute('icc_profile_name', 123) + + with self.assertRaises(TypeError): + self.colorspace.setInterchangeAttribute('icc_profile_name', ['profile', 'name']) + + # test both interchange attributes together. + + self.colorspace.setInterchangeAttribute('icc_profile_name', 'icc_value') + self.colorspace.setInterchangeAttribute('amf_transform_ids', 'amf_value') + self.assertEqual(len(self.colorspace.getInterchangeAttributes()), 2) + self.assertEqual(self.colorspace.getInterchangeAttribute('icc_profile_name'), 'icc_value') + self.assertEqual(self.colorspace.getInterchangeAttribute('amf_transform_ids'), 'amf_value') + + # unsupported interchange key + + # test that setting an unsupported key raises. + with self.assertRaises(Exception) as context: + self.colorspace.setInterchangeAttribute('this_should_fail', 'foo42') + self.assertIn("Unknown attribute name 'this_should_fail'", str(context.exception)) + + # test that getting an unsupported key raises. + with self.assertRaises(Exception) as context: + self.colorspace.getInterchangeAttribute('this_should_fail') + self.assertIn("Unknown attribute name 'this_should_fail'", str(context.exception)) + def test_is_colorspace_linear(self): """ Test isColorSpaceLinear. @@ -634,7 +835,7 @@ def test_display_referred(self, cfg, cs_name, expected_value): def test_processor_to_known_colorspace(self): - CONFIG = """ocio_profile_version: 2 + CONFIG = """ocio_profile_version: 2.0 roles: default: raw @@ -690,12 +891,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: "mycompany:led_wall_1" isdata: false from_scene_reference: ! name: AP0 to Linear Rec.709 (sRGB) From 92ab718b83196091823250124aa724902c048680 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Thu, 18 Sep 2025 20:46:02 -0400 Subject: [PATCH 3/5] Adsk Contrib - Enhance active display/view list API (#2186) * Enhance active display/view list API Signed-off-by: Doug Walker * Update ocioview to use new API Signed-off-by: Doug Walker * Fix python arg name Signed-off-by: Doug Walker --------- Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorIO.h | 79 +++++++--- src/OpenColorIO/Config.cpp | 169 ++++++++++++++++++++- src/OpenColorIO/OCIOYaml.cpp | 21 ++- src/OpenColorIO/ParseUtils.cpp | 141 ++++++++++++++++- src/apps/ocioview/ocioview/config_cache.py | 19 +-- src/bindings/python/PyConfig.cpp | 69 ++++++++- tests/cpu/Config_tests.cpp | 114 ++++++++++++++ tests/cpu/ParseUtils_tests.cpp | 83 +++++++++- tests/python/ConfigTest.py | 66 ++++++++ 9 files changed, 707 insertions(+), 54 deletions(-) diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 05e66cac5..915737fa0 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -1096,37 +1096,78 @@ class OCIOEXPORT Config /** * \brief * - * $OCIO_ACTIVE_DISPLAYS envvar can, at runtime, optionally override the - * allowed displays. It is a comma or colon delimited list. Active displays - * that are not in the specified profile will be ignored, and the - * left-most defined display will be the default. - * - * Comma-delimited list of names to filter and order the active displays. + * The Active Displays list allows end users, config authors, and client apps to filter and + * reorder of the list of displays available in a user-interface. The list may be left empty + * to indicate all displays are active. + * + * The first active display is the config's Default Display. + * + * If the active list would remove all displays from a config, it is ignored (though the + * config won't validate). + * + * When serialized in the config, commas are used as separators. However, if a display name + * contains a comma, the name will be enclosed in quotes so its comma is not a separator. * - * \note - * The setter does not override the envvar. The getter does not take into - * account the envvar value and thus may not represent what the user is seeing. + * The OCIO_ACTIVE_DISPLAYS environment variable will override the active list specified in + * the config file as well as any modifications made by the client app. These functions + * only get and set what is in the config object and do not take into account the override + * and thus may not represent the actual user experience. */ + /// Set all active displays at once as a comma or colon delimited string. This replaces any + /// previous contents of the list. void setActiveDisplays(const char * displays); + /// Get a string with all active displays (as it would appear in a config file). + /// Commas are always used as the separator. const char * getActiveDisplays() const; + /// Get the number of active displays. + int getNumActiveDisplays() const; + /// Get a single active display, by index. Returns nullptr if the index is out of range. + const char * getActiveDisplay(int index) const; + /// Add a single active display to the end of the list. If the display is already present, + /// no action is taken. + void addActiveDisplay(const char * display); + /// Remove a single display. Will throw if the display is not present. + void removeActiveDisplay(const char * display); + /// Clear the active displays list. + void clearActiveDisplays(); /** * \brief * - * $OCIO_ACTIVE_VIEWS envvar can, at runtime, optionally override the allowed views. - * It is a comma or colon delimited list. - * Active views that are not in the specified profile will be ignored, and the - * left-most defined view will be the default. - * - * Comma-delimited list of names to filter and order the active views. + * The Active Views list allows end users, config authors, and client apps to filter and + * reorder of the list of views available in a user-interface. The list may be left empty + * to indicate all views are active. + * + * The first active view for a display is its Default View. + * + * If the active list would remove all views from a display, the list is ignored for that + * display and all views are shown for it. + * + * When serialized in the config, commas are used as separators. However, if a view name + * contains a comma, the name will be enclosed in quotes so its comma is not a separator. * - * \note - * The setter does not override the envvar. The getter does not take - * into account the envvar value and thus may not represent what the - * user is seeing. + * The OCIO_ACTIVE_VIEWS environment variable will override the active list specified in + * the config file as well as any modifications made by the client app. These functions + * only get and set what is in the config object and do not take into account the override + * and thus may not represent the actual user experience. */ + /// Set all active views at once as a comma or colon delimited string. This replaces any + /// previous contents of the list. void setActiveViews(const char * views); + /// Get a string with all active views (as it would appear in a config file). + /// Commas are always used as the separator. const char * getActiveViews() const; + /// Get the number of active views. + int getNumActiveViews() const; + /// Get a single active view, by index. Returns nullptr if the index is out of range. + const char * getActiveView(int index) const; + /// Add a single active view to the end of the list. If the view is already present, + /// no action is taken. + void addActiveView(const char * view); + /// Remove a single view. Will throw if the view is not present. + void removeActiveView(const char * view); + /// Clear the active views list. + void clearActiveViews(); /// Get all displays in the config, ignoring the active_displays list. int getNumDisplaysAll() const noexcept; diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index 550d23099..1a8f81959 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -1029,6 +1029,7 @@ class Config::Impl oss << "Profile description: " << monitorDescription; cs->setDescription(oss.str().c_str()); cs->setTransform(file, COLORSPACE_DIR_FROM_REFERENCE); + cs->setEncoding("sdr-video"); // Note that it adds it or updates the existing one. m_allColorSpaces->addColorSpace(cs); @@ -3386,7 +3387,7 @@ void Config::removeSharedView(const char * view) { std::ostringstream os; os << "Shared view could not be removed from config. A shared view named '" - << view << "' could be be found."; + << view << "' could not be found."; throw Exception(os.str().c_str()); } } @@ -4115,6 +4116,14 @@ void Config::setActiveDisplays(const char * displays) getImpl()->m_activeDisplays.clear(); getImpl()->m_activeDisplays = SplitStringEnvStyle(displays); + // SplitStringEnvStyle needs to always return a result, even if empty, for look parsing. + // However, this does not count as an active display, so delete it. + if( getImpl()->m_activeDisplays.size() == 1 && + getImpl()->m_activeDisplays[0].empty() ) + { + getImpl()->m_activeDisplays.clear(); + } + getImpl()->m_displayCache.clear(); AutoMutex lock(getImpl()->m_cacheidMutex); @@ -4127,11 +4136,94 @@ const char * Config::getActiveDisplays() const return getImpl()->m_activeDisplaysStr.c_str(); } +void Config::addActiveDisplay(const char * display) +{ + if( !display || !display[0] ) + { + throw Exception("Active display could not be added to config, display name was empty"); + } + + auto it = std::find(getImpl()->m_activeDisplays.begin(), + getImpl()->m_activeDisplays.end(), display); + + if( it != getImpl()->m_activeDisplays.end() ) + { + // Display is already present. + return; + } + + getImpl()->m_activeDisplays.push_back(display); + + getImpl()->m_displayCache.clear(); + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +void Config::removeActiveDisplay(const char * display) +{ + if( !display || !display[0] ) + { + throw Exception("Active display could not be removed from config, display name was empty."); + } + + auto it = std::find( getImpl()->m_activeDisplays.begin(), + getImpl()->m_activeDisplays.end(), display ); + + if( it != getImpl()->m_activeDisplays.end() ) + { + getImpl()->m_activeDisplays.erase(it); + } + else + { + std::ostringstream os; + os << "Active display could not be removed from config, display '" + << display << "' was not found."; + throw Exception(os.str().c_str()); + } + + getImpl()->m_displayCache.clear(); + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +void Config::clearActiveDisplays() +{ + getImpl()->m_activeDisplays.clear(); + + getImpl()->m_displayCache.clear(); + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +const char * Config::getActiveDisplay( int index ) const +{ + if( index<0 || + index >= static_cast(getImpl()->m_activeDisplays.size())) + { + return nullptr; + } + + return getImpl()->m_activeDisplays[index].c_str(); +} + +int Config::getNumActiveDisplays() const +{ + return static_cast(getImpl()->m_activeDisplays.size()); +} + void Config::setActiveViews(const char * views) { getImpl()->m_activeViews.clear(); getImpl()->m_activeViews = SplitStringEnvStyle(views); + // SplitStringEnvStyle needs to always return a result, even if empty, for look parsing. + // However, this does not count as an active view, so delete it. + if( getImpl()->m_activeViews.size() == 1 && + getImpl()->m_activeViews[0].empty() ) + { + getImpl()->m_activeViews.clear(); + } + getImpl()->m_displayCache.clear(); AutoMutex lock(getImpl()->m_cacheidMutex); @@ -4144,6 +4236,81 @@ const char * Config::getActiveViews() const return getImpl()->m_activeViewsStr.c_str(); } +void Config::addActiveView(const char * view) +{ + if( !view || !view[0] ) + { + throw Exception("Active view could not be added to config, view name was empty."); + } + + auto it = std::find(getImpl()->m_activeViews.begin(), + getImpl()->m_activeViews.end(), view); + + if( it != getImpl()->m_activeViews.end() ) + { + // View is already present. + return; + } + + getImpl()->m_activeViews.push_back(view); + + getImpl()->m_displayCache.clear(); + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +void Config::removeActiveView(const char * view) +{ + if( !view || !view[0] ) + { + throw Exception("Active view could not be removed from config, view name was empty."); + } + + auto it = std::find( getImpl()->m_activeViews.begin(), + getImpl()->m_activeViews.end(), view ); + + if(it!=getImpl()->m_activeViews.end()) + { + getImpl()->m_activeViews.erase(it); + } + else + { + std::ostringstream os; + os << "Active view could not be removed from config, view '" + << view << "' was not found."; + throw Exception(os.str().c_str()); + } + + getImpl()->m_displayCache.clear(); + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +void Config::clearActiveViews() +{ + getImpl()->m_activeViews.clear(); + + getImpl()->m_displayCache.clear(); + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); +} + +const char * Config::getActiveView( int index ) const +{ + if( index<0 || + index >= static_cast(getImpl()->m_activeViews.size())) + { + return nullptr; + } + + return getImpl()->m_activeViews[index].c_str(); +} + +int Config::getNumActiveViews() const +{ + return static_cast(getImpl()->m_activeViews.size()); +} + int Config::getNumDisplaysAll() const noexcept { return static_cast(getImpl()->m_displays.size()); diff --git a/src/OpenColorIO/OCIOYaml.cpp b/src/OpenColorIO/OCIOYaml.cpp index b7d9172b9..c6920c3de 100644 --- a/src/OpenColorIO/OCIOYaml.cpp +++ b/src/OpenColorIO/OCIOYaml.cpp @@ -5061,13 +5061,26 @@ inline void save(YAML::Emitter & out, const Config & config) out << YAML::Newline; out << YAML::Key << "active_displays"; StringUtils::StringVec active_displays; - if(config.getActiveDisplays() != NULL && strlen(config.getActiveDisplays()) > 0) - active_displays = SplitStringEnvStyle(config.getActiveDisplays()); + int nDisplays = config.getNumActiveDisplays(); + active_displays.reserve( nDisplays ); + for (int i = 0; i < nDisplays; i++) + { + active_displays.push_back(config.getActiveDisplay(i)); + } + + // The YAML library will wrap names that use a comma in quotes. out << YAML::Value << YAML::Flow << active_displays; + out << YAML::Key << "active_views"; StringUtils::StringVec active_views; - if(config.getActiveViews() != NULL && strlen(config.getActiveViews()) > 0) - active_views = SplitStringEnvStyle(config.getActiveViews()); + int nViews = config.getNumActiveViews(); + active_views.reserve( nViews ); + for (int i = 0; i < nViews; i++) + { + active_views.push_back(config.getActiveView(i)); + } + + // The YAML library will wrap names that use a comma in quotes. out << YAML::Value << YAML::Flow << active_views; const std::string inactiveCSs = config.getInactiveColorSpaces(); diff --git a/src/OpenColorIO/ParseUtils.cpp b/src/OpenColorIO/ParseUtils.cpp index c8b77c5f3..6e3f056f3 100644 --- a/src/OpenColorIO/ParseUtils.cpp +++ b/src/OpenColorIO/ParseUtils.cpp @@ -687,33 +687,158 @@ bool StrEqualsCaseIgnore(const std::string & a, const std::string & b) return 0 == Platform::Strcasecmp(a.c_str(), b.c_str()); } +// Find the end of a name from a list contained in a string. +// The elements of the list are separated by the character defined by the sep argument. +// A name can be surrounded by quotes to enable names including the sep symbol, in +// other words, to prevent it from being used as a separator. +static int FindEndOfName(const std::string & s, size_t start, char sep) +{ + int currentPos = static_cast(start); + int nameEndPos = currentPos; + bool isEndFound = false; + + std::string symbols = "\""; + symbols += sep; + + while ( !isEndFound ) + { + nameEndPos = static_cast( s.find_first_of( symbols, currentPos ) ); + if ( nameEndPos == static_cast(std::string::npos) ) + { + // Reached the end of the list. + nameEndPos = static_cast( s.size() ); + isEndFound = true; + } + else if ( s[nameEndPos] == '"' ) + { + // Found a quote, need to find the next one. + nameEndPos = static_cast( s.find_first_of("\"", nameEndPos + 1) ); + if ( nameEndPos == (int)std::string::npos ) + { + // Reached the end of the list instead. + std::ostringstream os; + os << "The string '" << s << "' is not correctly formatted. " << + "It is missing a closing quote."; + throw Exception(os.str().c_str()); + } + else + { + // Found the second quote, need to continue the search for a symbol + // separating the elements (: or ,). + currentPos = nameEndPos + 1; + } + } + else if( s[nameEndPos] == sep ) + { + // Found a symbol separating the elements, stop here. + isEndFound = true; + } + } + + return nameEndPos; +} + StringUtils::StringVec SplitStringEnvStyle(const std::string & str) { - StringUtils::StringVec outputvec; const std::string s = StringUtils::Trim(str); - if (StringUtils::Find(s, ",") != std::string::npos) + if( s.size() == 0 ) { - outputvec = StringUtils::Split(s, ','); + // Look parsing always wants a result, even if an empty string. + return { "" }; } - else if (StringUtils::Find(s, ":") != std::string::npos) + + StringUtils::StringVec outputvec; + auto foundComma = s.find_first_of(","); + auto foundColon = s.find_first_of(":"); + + if( foundComma != std::string::npos || + foundColon != std::string::npos ) { - outputvec = StringUtils::Split(s, ':'); + int currentPos = 0; + while( s.size() > 0 && + currentPos <= (int)s.size() ) + { + int nameEndPos = FindEndOfName( s, + currentPos, + foundComma != std::string::npos ? ',' : ':' ); + if(nameEndPos > currentPos) + { + outputvec.push_back(s.substr(currentPos, nameEndPos - currentPos)); + currentPos = nameEndPos + 1; + } + else + { + outputvec.push_back(""); + currentPos += 1; + } + } } else { + // If there is no comma or colon, consider the string as a single element. outputvec.push_back(s); } - for (auto & val : outputvec) + for ( auto & val : outputvec ) { - val = StringUtils::Trim(val); + const std::string trimmedValue = StringUtils::Trim(val); + + // If the trimmed value is surrounded by quotes, remove them. + if( trimmedValue.size() > 1 && + trimmedValue[0] == '"' && + trimmedValue[trimmedValue.size() - 1] == '"' ) + { + val = trimmedValue.substr(1, trimmedValue.size() - 2); + } + else + { + val = trimmedValue; + } } + return outputvec; } std::string JoinStringEnvStyle(const StringUtils::StringVec & outputvec) { - return StringUtils::Join(outputvec, ','); + std::string result; + const int nElement = static_cast(outputvec.size()); + if( nElement == 0 ) + { + return ""; + } + + // Check if the value contains a symbol that could be interpreted as a separator + // and if it is not already surrounded by quotes. + const std::string& firstValue = outputvec[0]; + if( firstValue.find_first_of(",:") != std::string::npos && + firstValue.size() > 1 && + firstValue[0] != '"' && + firstValue[firstValue.size() - 1] != '"' ) + { + result += "\"" + firstValue + "\""; + } + else + { + result += firstValue; + } + + for( int i = 1; i < nElement; ++i ) + { + if( outputvec[i].find_first_of(",:") != std::string::npos && + outputvec[i].size() > 1 && + outputvec[i][0] != '"' && + outputvec[i][outputvec[i].size() - 1] != '"' ) + { + result += ", \"" + outputvec[i] + "\""; + } + else + { + result += ", " + outputvec[i]; + } + } + + return result; } // Return a vector of strings that are both in vec1 and vec2. diff --git a/src/apps/ocioview/ocioview/config_cache.py b/src/apps/ocioview/ocioview/config_cache.py index 280442ca9..eb25d3d35 100644 --- a/src/apps/ocioview/ocioview/config_cache.py +++ b/src/apps/ocioview/ocioview/config_cache.py @@ -117,15 +117,7 @@ def get_active_displays(cls) -> list[str]: :return: List of active displays from the current config """ if not cls.validate() or cls._active_displays is None: - cls._active_displays = list( - filter( - None, - re.split( - r" *[,:] *", - ocio.GetCurrentConfig().getActiveDisplays(), - ), - ) - ) + cls._active_displays = list(ocio.GetCurrentConfig().getActiveDisplays()) return cls._active_displays @@ -135,14 +127,7 @@ def get_active_views(cls) -> list[str]: :return: List of active views from the current config """ if not cls.validate() or cls._active_views is None: - cls._active_views = list( - filter( - None, - re.split( - r" *[,:] *", ocio.GetCurrentConfig().getActiveViews() - ), - ) - ) + cls._active_views = list(ocio.GetCurrentConfig().getActiveViews()) return cls._active_views diff --git a/src/bindings/python/PyConfig.cpp b/src/bindings/python/PyConfig.cpp index 58f3f52fc..6e7971844 100644 --- a/src/bindings/python/PyConfig.cpp +++ b/src/bindings/python/PyConfig.cpp @@ -26,6 +26,8 @@ enum ConfigIterator IT_SHARED_VIEW, IT_DISPLAY_VIEW, IT_DISPLAY_VIEW_COLORSPACE, + IT_ACTIVE_DISPLAYS_LIST, + IT_ACTIVE_VIEWS_LIST, IT_LOOK_NAME, IT_LOOK, IT_VIEW_TRANSFORM_NAME, @@ -63,6 +65,8 @@ using ViewForColorSpaceIterator = PyIterator; using ViewForViewTypeIterator = PyIterator; +using ActiveDisplaysListIterator = PyIterator; +using ActiveViewsListIterator = PyIterator; using LookNameIterator = PyIterator; using LookIterator = PyIterator; using ViewTransformNameIterator = PyIterator; @@ -142,6 +146,14 @@ void bindPyConfig(py::module & m) py::class_( clsConfig, "ViewForViewTypeIterator"); + auto clsActiveDisplaysListIterator = + py::class_( + clsConfig, "ActiveDisplaysListIterator"); + + auto clsActiveViewsListIterator = + py::class_( + clsConfig, "ActiveViewsListIterator"); + auto clsLookNameIterator = py::class_( clsConfig, "LookNameIterator"); @@ -576,12 +588,33 @@ void bindPyConfig(py::module & m) // Active Displays and Views .def("setActiveDisplays", &Config::setActiveDisplays, "displays"_a, DOC(Config, setActiveDisplays)) - .def("getActiveDisplays", &Config::getActiveDisplays, - DOC(Config, getActiveDisplays)) + .def("getActiveDisplays", [](ConfigRcPtr & self) + { + return ActiveDisplaysListIterator(self); + }) + .def("addActiveDisplay", &Config::addActiveDisplay, "display"_a, + DOC(Config, addActiveDisplay)) + .def("removeActiveDisplay", &Config::removeActiveDisplay, "display"_a, + DOC(Config, removeActiveDisplay)) + .def("clearActiveDisplays", &Config::clearActiveDisplays, + DOC(Config, clearActiveDisplays)) + .def("getNumActiveDisplays", &Config::getNumActiveDisplays, + DOC(Config, getNumActiveDisplays)) + .def("setActiveViews", &Config::setActiveViews, "views"_a, DOC(Config, setActiveViews)) - .def("getActiveViews", &Config::getActiveViews, - DOC(Config, getActiveViews)) + .def("getActiveViews", [](ConfigRcPtr & self) + { + return ActiveViewsListIterator(self); + }) + .def("addActiveView", &Config::addActiveView, "view"_a, + DOC(Config, addActiveView)) + .def("removeActiveView", &Config::removeActiveView, "view"_a, + DOC(Config, removeActiveView)) + .def("clearActiveViews", &Config::clearActiveViews, + DOC(Config, clearActiveViews)) + .def("getNumActiveViews", &Config::getNumActiveViews, + DOC(Config, getNumActiveViews)) // Luma .def("getDefaultLumaCoefs", [](ConfigRcPtr & self) @@ -1261,6 +1294,34 @@ void bindPyConfig(py::module & m) std::get<1>(it.m_args).c_str(), i); }); + clsActiveDisplaysListIterator + .def("__len__", [](ActiveDisplaysListIterator & it) { return it.m_obj->getNumActiveDisplays(); }) + .def("__getitem__", [](ActiveDisplaysListIterator & it, int i) + { + it.checkIndex(i, it.m_obj->getNumActiveDisplays()); + return it.m_obj->getActiveDisplay(i); + }) + .def("__iter__", [](ActiveDisplaysListIterator & it) -> ActiveDisplaysListIterator & { return it; }) + .def("__next__", [](ActiveDisplaysListIterator & it) + { + int i = it.nextIndex(it.m_obj->getNumActiveDisplays()); + return it.m_obj->getActiveDisplay(i); + }); + + clsActiveViewsListIterator + .def("__len__", [](ActiveViewsListIterator & it) { return it.m_obj->getNumActiveViews(); }) + .def("__getitem__", [](ActiveViewsListIterator & it, int i) + { + it.checkIndex(i, it.m_obj->getNumActiveViews()); + return it.m_obj->getActiveView(i); + }) + .def("__iter__", [](ActiveViewsListIterator & it) -> ActiveViewsListIterator & { return it; }) + .def("__next__", [](ActiveViewsListIterator & it) + { + int i = it.nextIndex(it.m_obj->getNumActiveViews()); + return it.m_obj->getActiveView(i); + }); + clsLookNameIterator .def("__len__", [](LookNameIterator & it) { return it.m_obj->getNumLooks(); }) .def("__getitem__", [](LookNameIterator & it, int i) diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 383e15aa7..06ac3d743 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -3444,6 +3444,13 @@ OCIO_ADD_TEST(Config, display) std::istringstream is(myProfile); OCIO::ConstConfigRcPtr config; OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); + + // The active displays list is ignored if it would remove all displays. + OCIO_REQUIRE_EQUAL(config->getNumDisplays(), 6); + OCIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_2")); + OCIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_F")); + OCIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_2"); + OCIO_CHECK_THROW_WHAT(config->validate(), OCIO::Exception, "The list of active displays [ABCDEF] from the config file is invalid."); @@ -3562,6 +3569,7 @@ OCIO_ADD_TEST(Config, view) OCIO::ConstConfigRcPtr config; OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is)); OCIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_1"); + // The active views list is ignored, for a display, if it would remove all views. OCIO_REQUIRE_EQUAL(config->getNumViews("sRGB_1"), 2); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1"); OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2"); @@ -3749,6 +3757,112 @@ OCIO_ADD_TEST(Config, display_view_order) OCIO_CHECK_EQUAL(std::string(config->getView("sRGB_B", 1)), "View_1"); } +OCIO_ADD_TEST(Config, active_displayview_lists) +{ + OCIO::ConfigRcPtr config = OCIO::Config::CreateRaw()->createEditableCopy(); + + // Test add. + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 0); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 0); + config->addActiveDisplay("sRGB"); + config->addActiveDisplay("Display P3"); + config->addActiveView("v1"); + config->addActiveView("v2"); + + // Test getter. + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 2); + OCIO_CHECK_EQUAL(std::string(config->getActiveDisplay(0)), "sRGB"); + OCIO_CHECK_EQUAL(std::string(config->getActiveDisplay(1)), "Display P3"); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 2); + OCIO_CHECK_EQUAL(std::string(config->getActiveView(0)), "v1"); + OCIO_CHECK_EQUAL(std::string(config->getActiveView(1)), "v2"); + + // Trying to add one that is already present doesn't add one, but does not throw. + OCIO_CHECK_NO_THROW(config->addActiveDisplay("sRGB")); + OCIO_CHECK_NO_THROW(config->addActiveView("v1")); + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 2); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 2); + + // Test commas may be used. + config->setActiveDisplays("sRGB:01, \"Name, with comma\", \"Quoted name\""); + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 3); + OCIO_CHECK_EQUAL(std::string(config->getActiveDisplay(0)), "sRGB:01"); + OCIO_CHECK_EQUAL(std::string(config->getActiveDisplay(1)), "Name, with comma"); + config->setActiveViews("v:01, \"View, with comma\", \"Quoted view\""); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 3); + OCIO_CHECK_EQUAL(std::string(config->getActiveView(0)), "v:01"); + OCIO_CHECK_EQUAL(std::string(config->getActiveView(1)), "View, with comma"); + + // Test remove. + config->removeActiveDisplay("Name, with comma"); + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 2); + OCIO_CHECK_EQUAL(std::string(config->getActiveDisplay(1)), "Quoted name"); + config->removeActiveView("View, with comma"); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 2); + OCIO_CHECK_EQUAL(std::string(config->getActiveView(1)), "Quoted view"); + + // Test clear. + config->clearActiveDisplays(); + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 0); + config->clearActiveViews(); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 0); + + // Trying to remove one that doesn't exist throws. + OCIO_CHECK_THROW_WHAT(config->removeActiveDisplay("not found"), + OCIO::Exception, + "Active display could not be removed from config"); + OCIO_CHECK_THROW_WHAT(config->removeActiveView("not found"), + OCIO::Exception, + "Active view could not be removed from config"); + + // Test setting an empty string behaves as expected. + config->setActiveDisplays(""); + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 0); + config->addActiveDisplay("sRGB"); + OCIO_CHECK_EQUAL(config->getNumActiveDisplays(), 1); + config->setActiveViews(""); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 0); + config->addActiveView("v1"); + OCIO_CHECK_EQUAL(config->getNumActiveViews(), 1); + + // Test commas may be serialized and restored. + { + config->setActiveDisplays("sRGB:01, \"Name, with comma\", \"Quoted name\""); + config->setActiveViews("v:01, \"View, with comma\", \"Quoted view\""); + std::ostringstream oss; + config->serialize(oss); + std::istringstream iss; + iss.str(oss.str()); + OCIO::ConstConfigRcPtr config2 = OCIO::Config::CreateFromStream(iss); + OCIO_CHECK_EQUAL(config2->getNumActiveDisplays(), 3); + OCIO_CHECK_EQUAL(std::string(config2->getActiveDisplay(0)), "sRGB:01"); + OCIO_CHECK_EQUAL(std::string(config2->getActiveDisplay(1)), "Name, with comma"); + OCIO_CHECK_EQUAL(std::string(config2->getActiveDisplay(2)), "Quoted name"); + OCIO_CHECK_EQUAL(config2->getNumActiveViews(), 3); + OCIO_CHECK_EQUAL(std::string(config2->getActiveView(0)), "v:01"); + OCIO_CHECK_EQUAL(std::string(config2->getActiveView(1)), "View, with comma"); + OCIO_CHECK_EQUAL(std::string(config2->getActiveView(2)), "Quoted view"); + } + + // Check how an active list that uses colons as the separator is serialized. + // Turns out these are serialized as commas, so this was never a viable method to + // set an active list to handle use of commas in names. (It would be ok for use in + // the env. var., but not in the config itself.) + { + config->setActiveDisplays("sRGB01 : Name : \"Quoted name\""); + config->setActiveViews("v01:View: \"Quoted view\""); + std::ostringstream oss; + config->serialize(oss); + std::istringstream iss; + iss.str(oss.str()); + OCIO::ConstConfigRcPtr config2 = OCIO::Config::CreateFromStream(iss); + OCIO_CHECK_EQUAL(config2->getNumActiveDisplays(), 3); + OCIO_CHECK_EQUAL(std::string(config2->getActiveDisplays()), "sRGB01, Name, Quoted name"); + OCIO_CHECK_EQUAL(config2->getNumActiveViews(), 3); + OCIO_CHECK_EQUAL(std::string(config2->getActiveViews()), "v01, View, Quoted view"); + } +} + OCIO_ADD_TEST(Config, log_serialization) { { diff --git a/tests/cpu/ParseUtils_tests.cpp b/tests/cpu/ParseUtils_tests.cpp index 42f20360c..246fc92fc 100644 --- a/tests/cpu/ParseUtils_tests.cpp +++ b/tests/cpu/ParseUtils_tests.cpp @@ -387,7 +387,12 @@ OCIO_ADD_TEST(ParseUtils, string_vec_to_int_vec) OCIO_ADD_TEST(ParseUtils, split_string_env_style) { + // For look parsing, the split needs to always return a result, even if empty. StringUtils::StringVec outputvec; + outputvec = OCIO::SplitStringEnvStyle(""); + OCIO_CHECK_EQUAL(1, outputvec.size()); + outputvec.clear(); + outputvec = OCIO::SplitStringEnvStyle("This:is:a:test"); OCIO_CHECK_EQUAL(4, outputvec.size()); OCIO_CHECK_EQUAL("This", outputvec[0]); @@ -395,13 +400,15 @@ OCIO_ADD_TEST(ParseUtils, split_string_env_style) OCIO_CHECK_EQUAL("a", outputvec[2]); OCIO_CHECK_EQUAL("test", outputvec[3]); outputvec.clear(); - outputvec = OCIO::SplitStringEnvStyle(" This : is : a: test "); + + outputvec = OCIO::SplitStringEnvStyle(" \"This\" : is : a: test "); OCIO_CHECK_EQUAL(4, outputvec.size()); OCIO_CHECK_EQUAL("This", outputvec[0]); OCIO_CHECK_EQUAL("is", outputvec[1]); OCIO_CHECK_EQUAL("a", outputvec[2]); OCIO_CHECK_EQUAL("test", outputvec[3]); outputvec.clear(); + outputvec = OCIO::SplitStringEnvStyle(" This , is , a, test "); OCIO_CHECK_EQUAL(4, outputvec.size()); OCIO_CHECK_EQUAL("This", outputvec[0]); @@ -409,16 +416,90 @@ OCIO_ADD_TEST(ParseUtils, split_string_env_style) OCIO_CHECK_EQUAL("a", outputvec[2]); OCIO_CHECK_EQUAL("test", outputvec[3]); outputvec.clear(); + outputvec = OCIO::SplitStringEnvStyle("This:is , a:test "); OCIO_CHECK_EQUAL(2, outputvec.size()); OCIO_CHECK_EQUAL("This:is", outputvec[0]); OCIO_CHECK_EQUAL("a:test", outputvec[1]); outputvec.clear(); + outputvec = OCIO::SplitStringEnvStyle(",,"); OCIO_CHECK_EQUAL(3, outputvec.size()); OCIO_CHECK_EQUAL("", outputvec[0]); OCIO_CHECK_EQUAL("", outputvec[1]); OCIO_CHECK_EQUAL("", outputvec[2]); + + outputvec = OCIO::SplitStringEnvStyle(" \"This : is \": a: test "); + OCIO_CHECK_EQUAL(3, outputvec.size()); + OCIO_CHECK_EQUAL("This : is ", outputvec[0]); + OCIO_CHECK_EQUAL("a", outputvec[1]); + OCIO_CHECK_EQUAL("test", outputvec[2]); + + OCIO_CHECK_THROW_WHAT( OCIO::SplitStringEnvStyle(" This : is \": a: test "), + OCIO::Exception, + "The string 'This : is \": a: test' is not correctly formatted. " + "It is missing a closing quote."); + + OCIO_CHECK_THROW_WHAT( OCIO::SplitStringEnvStyle(" This : is : a: test \""), + OCIO::Exception, + "The string 'This : is : a: test \"' is not correctly formatted. " + "It is missing a closing quote."); + + outputvec = OCIO::SplitStringEnvStyle(" This : is \": a: test \""); + OCIO_CHECK_EQUAL(2, outputvec.size()); + OCIO_CHECK_EQUAL("This", outputvec[0]); + OCIO_CHECK_EQUAL("is \": a: test \"" , outputvec[1]); + + outputvec = OCIO::SplitStringEnvStyle(" \"This : is \", a, test "); + OCIO_CHECK_EQUAL(3, outputvec.size()); + OCIO_CHECK_EQUAL("This : is ", outputvec[0]); + OCIO_CHECK_EQUAL("a", outputvec[1]); + OCIO_CHECK_EQUAL("test", outputvec[2]); + + // If the string contains a comma, it is chosen as the separator character rather than + // the colon (even if it is within quotes and therefore not used as such). + outputvec = OCIO::SplitStringEnvStyle(" \"This , is \": a: test "); + OCIO_CHECK_EQUAL(1, outputvec.size()); + OCIO_CHECK_EQUAL("\"This , is \": a: test", outputvec[0]); + + outputvec = OCIO::SplitStringEnvStyle(" \"This , is \": a, test "); + OCIO_CHECK_EQUAL(2, outputvec.size()); + OCIO_CHECK_EQUAL("\"This , is \": a", outputvec[0]); + OCIO_CHECK_EQUAL("test", outputvec[1]); +} + +OCIO_ADD_TEST(ParseUtils, join_string_env_style) +{ + StringUtils::StringVec outputvec {"This", "is", "a", "test"}; + + OCIO_CHECK_EQUAL( "This, is, a, test", OCIO::JoinStringEnvStyle(outputvec) ); + outputvec.clear(); + + OCIO_CHECK_EQUAL( "", OCIO::JoinStringEnvStyle(outputvec) ); + outputvec.clear(); + + outputvec = { "This:is", "a:test" }; + OCIO_CHECK_EQUAL( "\"This:is\", \"a:test\"", OCIO::JoinStringEnvStyle(outputvec) ); + outputvec.clear(); + + outputvec = { "", "", "" }; + OCIO_CHECK_EQUAL( ", , ", OCIO::JoinStringEnvStyle(outputvec) ); + outputvec.clear(); + + outputvec = { "This : is", "a: test" }; + OCIO_CHECK_EQUAL( "\"This : is\", \"a: test\"", OCIO::JoinStringEnvStyle(outputvec) ); + outputvec.clear(); + + outputvec = { "This", "is \": a: test" }; + OCIO_CHECK_EQUAL( "This, \"is \": a: test\"", OCIO::JoinStringEnvStyle(outputvec) ); + + outputvec = { "\"This, is, a, string\"", "this, one, too" }; + OCIO_CHECK_EQUAL( "\"This, is, a, string\", \"this, one, too\"" , + OCIO::JoinStringEnvStyle(outputvec) ); + + outputvec = { "This", "is: ", "\"a very good,\"", " fine, helpful, and useful ", "test" }; + OCIO_CHECK_EQUAL( "This, \"is: \", \"a very good,\", \" fine, helpful, and useful \", test", + OCIO::JoinStringEnvStyle(outputvec) ); } OCIO_ADD_TEST(ParseUtils, intersect_string_vecs_case_ignore) diff --git a/tests/python/ConfigTest.py b/tests/python/ConfigTest.py index 78327a582..57b12b7d7 100644 --- a/tests/python/ConfigTest.py +++ b/tests/python/ConfigTest.py @@ -1381,6 +1381,72 @@ def test_roles(self): # Test the new value of the role color_picking. self.assertEqual(config.getRoleColorSpace("color_picking"), "ACEScct") + def test_active__displayview_lists(self): + config = OCIO.Config.CreateRaw() + + # Test add. + self.assertEqual(len(config.getActiveDisplays()), 0) + self.assertEqual(len(config.getActiveViews()), 0) + config.addActiveDisplay("sRGB") + config.addActiveDisplay("Display P3") + config.addActiveView("v1") + config.addActiveView("v2") + + # Test getters. + self.assertEqual(len(config.getActiveDisplays()), 2) + self.assertEqual(config.getActiveDisplays()[0], "sRGB") + self.assertEqual(config.getActiveDisplays()[1], "Display P3") + self.assertEqual(len(config.getActiveViews()), 2) + self.assertEqual(config.getActiveViews()[0], "v1") + self.assertEqual(config.getActiveViews()[1], "v2") + + # Test that add doesn't throw on dupes. + config.addActiveDisplay("sRGB") + self.assertEqual(config.getNumActiveDisplays(), 2) + config.addActiveView("v1") + self.assertEqual(config.getNumActiveViews(), 2) + + # Test commas may be used. + config.setActiveDisplays(displays='sRGB:01, "Name, with comma", "Quoted name"') + self.assertEqual(config.getNumActiveDisplays(), 3) + self.assertEqual(config.getActiveDisplays()[0], "sRGB:01") + self.assertEqual(config.getActiveDisplays()[1], "Name, with comma") + config.setActiveViews(views='v:01, "View, with comma", "Quoted view"') + self.assertEqual(config.getNumActiveViews(), 3) + self.assertEqual(config.getActiveViews()[0], "v:01") + self.assertEqual(config.getActiveViews()[1], "View, with comma") + + # Test remove. + config.removeActiveDisplay(display="Name, with comma") + self.assertEqual(config.getActiveDisplays()[1], "Quoted name") + self.assertEqual(config.getNumActiveDisplays(), 2) + config.removeActiveView(view="View, with comma") + self.assertEqual(config.getActiveViews()[1], "Quoted view") + self.assertEqual(config.getNumActiveViews(), 2) + + # Test clear. + config.clearActiveDisplays() + self.assertEqual(config.getNumActiveDisplays(), 0) + config.clearActiveViews() + self.assertEqual(config.getNumActiveViews(), 0) + + # Trying to remove one that doesn't exist throws. + with self.assertRaises(OCIO.Exception): + config.removeActiveDisplay("not found") + with self.assertRaises(OCIO.Exception): + config.removeActiveView("not found") + + # Test setting an empty string behaves as expected. + config.setActiveDisplays("") + self.assertEqual(config.getNumActiveDisplays(), 0) + config.addActiveDisplay(display="sRGB") + self.assertEqual(config.getNumActiveDisplays(), 1) + config.setActiveViews("") + self.assertEqual(config.getNumActiveViews(), 0) + config.addActiveView(view="v1") + self.assertEqual(config.getNumActiveViews(), 1) + + class ConfigVirtualWithActiveDisplayTest(unittest.TestCase): def setUp(self): self.cfg_active_display = OCIO.Config.CreateFromStream( From a4a113af3fc5961739688e2d27bb9bf5d6e02af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Achard?= Date: Fri, 19 Sep 2025 12:12:13 +0100 Subject: [PATCH 4/5] Bump dependencies and update CI workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Achard --- .github/workflows/analysis_workflow.yml | 2 +- .github/workflows/ci_workflow.yml | 158 +++++++++--------- .github/workflows/dependencies_latest.yml | 116 +++++-------- .github/workflows/platform_latest.yml | 18 +- .github/workflows/wheel_workflow.yml | 62 +++---- CMakeLists.txt | 2 +- docs/quick_start/installation.rst | 16 +- pyproject.toml | 4 +- setup.cfg | 5 +- share/ci/scripts/multi/install_yaml-cpp.sh | 4 +- share/cmake/macros/GetPythonPreCommand.cmake | 12 +- share/cmake/modules/FindExtPackages.cmake | 43 +++-- share/cmake/modules/Findyaml-cpp.cmake | 11 -- .../modules/install/InstallOpenEXR.cmake | 15 +- .../modules/install/Installminizip-ng.cmake | 12 +- .../cmake/modules/install/Installopenfx.cmake | 6 +- .../modules/install/Installpybind11.cmake | 8 + .../modules/install/Installyaml-cpp.cmake | 15 +- share/cmake/utils/CompilerFlags.cmake | 13 +- share/cmake/utils/CppVersion.cmake | 43 +++-- src/OpenColorIO/CMakeLists.txt | 2 +- src/OpenColorIO/SystemMonitor_macos.cpp | 6 +- tests/cpu/CMakeLists.txt | 2 +- tests/cpu/fileformats/FileFormatCTF_tests.cpp | 2 +- .../context_test1/context_test1_windows.ocioz | Bin 3938 -> 3966 bytes 25 files changed, 278 insertions(+), 299 deletions(-) diff --git a/.github/workflows/analysis_workflow.yml b/.github/workflows/analysis_workflow.yml index f465b5109..d72223212 100644 --- a/.github/workflows/analysis_workflow.yml +++ b/.github/workflows/analysis_workflow.yml @@ -59,7 +59,7 @@ jobs: cmake ../. \ -DCMAKE_INSTALL_PREFIX=../_install \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_CXX_STANDARD=14 \ + -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_CXX_FLAGS="-g -O0 -fprofile-arcs -ftest-coverage" \ -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON \ -DCMAKE_EXE_LINKER_FLAGS="-lgcov" \ diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index ffb0c4c10..f76a61205 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -61,9 +61,51 @@ jobs: strategy: fail-fast: true matrix: - build: [7, 8, 9, 10, 11, 12] + build: [7, 8, 9, 10, 11, 12, 13, 14, 15] include: # ------------------------------------------------------------------- + # VFX CY2025 (Python 3.11) + # ------------------------------------------------------------------- + - build: 15 + build-type: Debug + build-shared: 'ON' + build-docs: 'OFF' + build-openfx: 'ON' + use-simd: 'ON' + use-oiio: 'ON' + cxx-standard: 20 + cxx-compiler: clang++ + cc-compiler: clang + compiler-desc: Clang + vfx-cy: 2025 + install-ext-packages: MISSING + - build: 14 + build-type: Release + build-shared: 'ON' + build-docs: 'ON' + build-openfx: 'ON' + use-simd: 'OFF' + use-oiio: 'OFF' + cxx-standard: 17 + cxx-compiler: g++ + cc-compiler: gcc + compiler-desc: GCC + vfx-cy: 2025 + install-ext-packages: ALL + - build: 13 + build-type: Release + build-shared: 'OFF' + build-docs: 'OFF' + build-openfx: 'OFF' + use-simd: 'ON' + use-oiio: 'OFF' + cxx-standard: 17 + cxx-compiler: g++ + cc-compiler: gcc + compiler-desc: GCC + vfx-cy: 2025 + install-ext-packages: ALL + # ------------------------------------------------------------------- # VFX CY2024 (Python 3.11) # ------------------------------------------------------------------- - build: 12 @@ -73,7 +115,7 @@ jobs: build-openfx: 'ON' use-simd: 'ON' use-oiio: 'ON' - cxx-standard: 17 + cxx-standard: 20 cxx-compiler: clang++ cc-compiler: clang compiler-desc: Clang @@ -99,7 +141,7 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 + cxx-standard: 17 cxx-compiler: g++ cc-compiler: gcc compiler-desc: GCC @@ -115,7 +157,7 @@ jobs: build-openfx: 'ON' use-simd: 'ON' use-oiio: 'ON' - cxx-standard: 17 + cxx-standard: 20 cxx-compiler: clang++ cc-compiler: clang compiler-desc: Clang @@ -141,7 +183,7 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 + cxx-standard: 17 cxx-compiler: g++ cc-compiler: gcc compiler-desc: GCC @@ -218,7 +260,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -257,12 +299,12 @@ jobs: strategy: fail-fast: true matrix: - build: [1, 2, 3, 4, 5, 6] + build: [1, 2, 3] include: # ------------------------------------------------------------------- # VFX CY2022 (Python 3.9) # ------------------------------------------------------------------- - - build: 6 + - build: 1 build-type: Debug build-shared: 'ON' build-docs: 'OFF' @@ -275,7 +317,7 @@ jobs: compiler-desc: Clang vfx-cy: 2022 install-ext-packages: ALL - - build: 5 + - build: 2 build-type: Release build-shared: 'ON' build-docs: 'ON' @@ -288,60 +330,18 @@ jobs: compiler-desc: GCC vfx-cy: 2022 install-ext-packages: MISSING - - build: 4 - build-type: Release - build-shared: 'OFF' - build-docs: 'OFF' - build-openfx: 'OFF' - use-simd: 'ON' - use-oiio: 'OFF' - cxx-standard: 11 - cxx-compiler: g++ - cc-compiler: gcc - compiler-desc: GCC - vfx-cy: 2022 - install-ext-packages: ALL - # ------------------------------------------------------------------- - # VFX CY2021 (Python 3.7) - # ------------------------------------------------------------------- - build: 3 - build-type: Release - build-shared: 'ON' - build-docs: 'OFF' - build-openfx: 'OFF' - use-simd: 'ON' - use-oiio: 'ON' - cxx-standard: 17 - cxx-compiler: clang++ - cc-compiler: clang - compiler-desc: Clang - vfx-cy: 2021 - install-ext-packages: MISSING - - build: 2 build-type: Release build-shared: 'OFF' build-docs: 'OFF' - build-openfx: 'ON' - use-simd: 'OFF' - use-oiio: 'OFF' - cxx-standard: 14 - cxx-compiler: clang++ - cc-compiler: clang - compiler-desc: Clang - vfx-cy: 2021 - install-ext-packages: ALL - - build: 1 - build-type: Debug - build-shared: 'ON' - build-docs: 'OFF' build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 + cxx-standard: 17 cxx-compiler: g++ cc-compiler: gcc compiler-desc: GCC - vfx-cy: 2021 + vfx-cy: 2022 install-ext-packages: ALL env: CXX: ${{ matrix.cxx-compiler }} @@ -430,7 +430,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -472,8 +472,8 @@ jobs: build-openfx: 'ON' use-simd: 'ON' use-oiio: 'ON' - cxx-standard: 17 - python-version: '3.11' + cxx-standard: 20 + python-version: '3.13' # Keeping one universal build - build: 4 arch-type: "x86_64;arm64" @@ -483,8 +483,8 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.10' + cxx-standard: 20 + python-version: '3.12' - build: 3 arch-type: "x86_64" build-type: Release @@ -493,8 +493,8 @@ jobs: build-openfx: 'OFF' use-simd: 'OFF' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.10' + cxx-standard: 17 + python-version: '3.11' - build: 2 arch-type: "x86_64" build-type: Debug @@ -503,8 +503,8 @@ jobs: build-openfx: 'ON' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.9' + cxx-standard: 17 + python-version: '3.10' - build: 1 arch-type: "x86_64" build-type: Release @@ -513,8 +513,8 @@ jobs: build-openfx: 'ON' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 14 - python-version: '3.7' + cxx-standard: 17 + python-version: '3.9' steps: - name: Setup Python uses: actions/setup-python@v5 @@ -588,7 +588,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -628,8 +628,8 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.11' + cxx-standard: 20 + python-version: '3.13' - build: 2 arch-type: "x86_64;arm64" test-rosetta: "ON" @@ -639,8 +639,8 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.11' + cxx-standard: 17 + python-version: '3.12' steps: - name: Setup Python uses: actions/setup-python@v5 @@ -719,7 +719,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -761,8 +761,8 @@ jobs: build-openfx: 'ON' use-simd: 'OFF' use-oiio: 'ON' - cxx-standard: 17 - python-version: '3.11' + cxx-standard: 20 + python-version: '3.13' - build: 3 build-type: Release build-shared: 'OFF' @@ -770,8 +770,8 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.9' + cxx-standard: 17 + python-version: '3.12' - build: 2 build-type: Debug build-shared: 'ON' @@ -779,8 +779,8 @@ jobs: build-openfx: 'OFF' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 11 - python-version: '3.8' + cxx-standard: 17 + python-version: '3.11' # C++14, OpenEXR, OpenFX - build: 1 build-type: Release @@ -789,8 +789,8 @@ jobs: build-openfx: 'ON' use-simd: 'ON' use-oiio: 'OFF' - cxx-standard: 14 - python-version: '3.7' + cxx-standard: 17 + python-version: '3.9' steps: - name: Setup Python uses: actions/setup-python@v5 @@ -874,7 +874,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ diff --git a/.github/workflows/dependencies_latest.yml b/.github/workflows/dependencies_latest.yml index 9cebbb3ce..211e6f23b 100644 --- a/.github/workflows/dependencies_latest.yml +++ b/.github/workflows/dependencies_latest.yml @@ -27,18 +27,18 @@ jobs: # --------------------------------------------------------------------------- linux_latest: - name: 'Linux CentOS 7 VFX CY${{ matrix.vfx-cy }} latest + name: 'Linux VFX CY${{ matrix.vfx-cy }} latest <${{ matrix.compiler-desc }} cxx=${{ matrix.cxx-standard }}, docs=${{ matrix.build-docs }}>' # Don't run on OCIO forks if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' - # GH-hosted VM. The build runs in CentOS 7 'container' defined below. + # GH-hosted VM. The build runs in ASWF 'container' defined below. runs-on: ubuntu-latest container: # DockerHub: https://hub.docker.com/u/aswf # Source: https://github.com/AcademySoftwareFoundation/aswf-docker - image: aswf/ci-base:${{ matrix.vfx-cy }} + image: aswf/ci-base:${{ matrix.vfx-cy }}.1 strategy: matrix: build: [1, 2, 3, 4] @@ -49,42 +49,38 @@ jobs: - build: 1 build-docs: 'ON' build-openfx: 'ON' - cxx-standard: 17 + cxx-standard: 20 cxx-compiler: g++ cc-compiler: gcc compiler-desc: GCC - vfx-cy: 2022 - use-oiio: 'ON' + vfx-cy: 2025 - build: 2 build-docs: 'OFF' build-openfx: 'OFF' - cxx-standard: 14 + cxx-standard: 17 cxx-compiler: g++ cc-compiler: gcc compiler-desc: GCC - vfx-cy: 2021 - use-oiio: 'OFF' + vfx-cy: 2024 # ------------------------------------------------------------------- # Clang # ------------------------------------------------------------------- - build: 3 build-docs: 'OFF' build-openfx: 'OFF' - cxx-standard: 17 + cxx-standard: 20 cxx-compiler: clang++ cc-compiler: clang compiler-desc: Clang - vfx-cy: 2022 - use-oiio: 'OFF' + vfx-cy: 2025 - build: 4 build-docs: 'ON' build-openfx: 'ON' - cxx-standard: 14 + cxx-standard: 17 cxx-compiler: clang++ cc-compiler: clang compiler-desc: Clang - vfx-cy: 2021 - use-oiio: 'ON' + vfx-cy: 2024 env: CXX: ${{ matrix.cxx-compiler }} CC: ${{ matrix.cc-compiler }} @@ -100,25 +96,20 @@ jobs: run: | EXT_PATH=/usr/local echo "EXT_PATH=$EXT_PATH" >> $GITHUB_ENV - - name: Install indirect dependencies - run: | - share/ci/scripts/multi/install_pugixml.sh latest - name: Install fixed ext package versions # Minizip-ng depends on ZLIB. ZLIB must be installed first. run: | - share/ci/scripts/multi/install_expat.sh 2.4.1 $EXT_PATH - share/ci/scripts/multi/install_lcms2.sh 2.2 $EXT_PATH - share/ci/scripts/multi/install_yaml-cpp.sh 0.7.0 $EXT_PATH - share/ci/scripts/multi/install_pystring.sh 1.1.3 $EXT_PATH - share/ci/scripts/multi/install_pybind11.sh 2.9.2 $EXT_PATH - share/ci/scripts/multi/install_zlib.sh 1.2.12 $EXT_PATH - share/ci/scripts/multi/install_minizip-ng.sh 3.0.6 $EXT_PATH + share/ci/scripts/multi/install_expat.sh 2.7.2 $EXT_PATH + share/ci/scripts/multi/install_lcms2.sh 2.17 $EXT_PATH + share/ci/scripts/multi/install_yaml-cpp.sh 0.8.0 $EXT_PATH + share/ci/scripts/multi/install_pystring.sh 1.1.4 $EXT_PATH + share/ci/scripts/multi/install_pybind11.sh 3.0.1 $EXT_PATH + share/ci/scripts/multi/install_zlib.sh 1.3.1 $EXT_PATH + share/ci/scripts/multi/install_minizip-ng.sh 4.0.10 $EXT_PATH - name: Install latest ext package versions run: | share/ci/scripts/multi/install_imath.sh latest $EXT_PATH share/ci/scripts/multi/install_openexr.sh latest $EXT_PATH - share/ci/scripts/multi/install_oiio.sh latest $EXT_PATH - share/ci/scripts/multi/install_osl.sh latest $EXT_PATH share/ci/scripts/multi/install_openfx.sh latest $EXT_PATH - name: Create build directories run: | @@ -135,8 +126,7 @@ jobs: -DOCIO_BUILD_GPU_TESTS=OFF \ -DOCIO_INSTALL_EXT_PACKAGES=NONE \ -DOCIO_WARNING_AS_ERROR=OFF \ - -DPython_EXECUTABLE=$(which python) \ - -DOCIO_USE_OIIO_FOR_APPS=${{ matrix.use-oiio }} + -DPython_EXECUTABLE=$(which python) working-directory: _build - name: Build run: | @@ -178,15 +168,13 @@ jobs: - build: 1 build-docs: 'ON' build-openfx: 'ON' - cxx-standard: 17 - python-version: '3.11' - use-oiio: 'ON' + cxx-standard: 20 + python-version: '3.13' - build: 2 build-docs: 'ON' build-openfx: 'ON' - cxx-standard: 14 + cxx-standard: 17 python-version: '3.9' - use-oiio: 'OFF' steps: - name: Setup Python uses: actions/setup-python@v5 @@ -201,29 +189,23 @@ jobs: run: share/ci/scripts/macos/install_tests_env.sh - name: Setup ext environment run: | - EXT_PATH=/usr/local + EXT_PATH=$GITHUB_WORKSPACE/_ext echo "EXT_PATH=$EXT_PATH" >> $GITHUB_ENV - - name: Install indirect dependencies - run: | - share/ci/scripts/macos/install_bison.sh latest - share/ci/scripts/macos/install_boost.sh latest - share/ci/scripts/multi/install_pugixml.sh latest $EXT_PATH + echo "CMAKE_PREFIX_PATH=$EXT_PATH" >> $GITHUB_ENV - name: Install fixed ext package versions # Minizip-ng depends on ZLIB. ZLIB must be installed first. run: | - share/ci/scripts/multi/install_expat.sh 2.4.1 $EXT_PATH - share/ci/scripts/multi/install_lcms2.sh 2.2 $EXT_PATH - share/ci/scripts/multi/install_yaml-cpp.sh 0.7.0 $EXT_PATH - share/ci/scripts/multi/install_pystring.sh 1.1.3 $EXT_PATH - share/ci/scripts/multi/install_pybind11.sh 2.9.2 $EXT_PATH - share/ci/scripts/multi/install_zlib.sh 1.2.12 $EXT_PATH - share/ci/scripts/multi/install_minizip-ng.sh 3.0.6 $EXT_PATH + share/ci/scripts/multi/install_expat.sh 2.7.2 $EXT_PATH + share/ci/scripts/multi/install_lcms2.sh 2.17 $EXT_PATH + share/ci/scripts/multi/install_yaml-cpp.sh 0.8.0 $EXT_PATH + share/ci/scripts/multi/install_pystring.sh 1.1.4 $EXT_PATH + share/ci/scripts/multi/install_pybind11.sh 3.0.1 $EXT_PATH + share/ci/scripts/multi/install_zlib.sh 1.3.1 $EXT_PATH + share/ci/scripts/multi/install_minizip-ng.sh 4.0.10 $EXT_PATH - name: Install latest ext package versions run: | share/ci/scripts/multi/install_imath.sh latest $EXT_PATH share/ci/scripts/multi/install_openexr.sh latest $EXT_PATH - share/ci/scripts/multi/install_oiio.sh latest $EXT_PATH - share/ci/scripts/multi/install_osl.sh latest $EXT_PATH share/ci/scripts/multi/install_openfx.sh latest $EXT_PATH - name: Create build directories run: | @@ -240,8 +222,7 @@ jobs: -DOCIO_BUILD_GPU_TESTS=OFF \ -DOCIO_INSTALL_EXT_PACKAGES=NONE \ -DOCIO_WARNING_AS_ERROR=OFF \ - -DPython_EXECUTABLE=$(which python) \ - -DOCIO_USE_OIIO_FOR_APPS=${{ matrix.use-oiio }} + -DPython_EXECUTABLE=$(which python) working-directory: _build - name: Build run: | @@ -260,6 +241,7 @@ jobs: -DCMAKE_BUILD_TYPE=Release cmake --build . \ --config Release + export DYLD_LIBRARY_PATH=$EXT_PATH/lib:$DYLD_LIBRARY_PATH ./consumer working-directory: _build/tests/cmake-consumer-dist @@ -283,13 +265,13 @@ jobs: - build: 1 build-docs: 'ON' build-openfx: 'ON' - cxx-standard: 17 - python-version: '3.11' + cxx-standard: 20 + python-version: '3.13' use-oiio: 'ON' - build: 2 build-docs: 'ON' build-openfx: 'ON' - cxx-standard: 14 + cxx-standard: 17 python-version: '3.9' use-oiio: 'OFF' steps: @@ -323,32 +305,23 @@ jobs: run: | vcpkg install zlib:x64-windows vcpkg install tiff:x64-windows - vcpkg install boost-asio:x64-windows - vcpkg install boost-container:x64-windows - vcpkg install boost-filesystem:x64-windows - vcpkg install boost-math:x64-windows - vcpkg install boost-stacktrace:x64-windows - vcpkg install boost-system:x64-windows - vcpkg install boost-thread:x64-windows - share/ci/scripts/multi/install_pugixml.sh latest $EXT_PATH shell: bash - name: Install fixed ext package versions # Minizip-ng depends on ZLIB. ZLIB must be installed first. run: | - share/ci/scripts/multi/install_lcms2.sh 2.2 $EXT_PATH - share/ci/scripts/multi/install_yaml-cpp.sh 0.7.0 $EXT_PATH - share/ci/scripts/multi/install_pystring.sh 1.1.3 $EXT_PATH - share/ci/scripts/multi/install_pybind11.sh 2.9.2 $EXT_PATH - share/ci/scripts/multi/install_expat.sh 2.4.1 $EXT_PATH - share/ci/scripts/multi/install_zlib.sh 1.2.12 $EXT_PATH - share/ci/scripts/multi/install_minizip-ng.sh 3.0.6 $EXT_PATH + share/ci/scripts/multi/install_lcms2.sh 2.17 $EXT_PATH + share/ci/scripts/multi/install_yaml-cpp.sh 0.8.0 $EXT_PATH + share/ci/scripts/multi/install_pystring.sh 1.1.4 $EXT_PATH + share/ci/scripts/multi/install_pybind11.sh 3.0.1 $EXT_PATH + share/ci/scripts/multi/install_expat.sh 2.7.2 $EXT_PATH + share/ci/scripts/multi/install_zlib.sh 1.3.1 $EXT_PATH + share/ci/scripts/multi/install_minizip-ng.sh 4.0.10 $EXT_PATH shell: bash # OSL not installed due to LLVM compilation time. - name: Install latest ext package versions run: | share/ci/scripts/multi/install_imath.sh latest $EXT_PATH share/ci/scripts/multi/install_openexr.sh latest $EXT_PATH - share/ci/scripts/multi/install_oiio.sh latest $EXT_PATH share/ci/scripts/multi/install_openfx.sh latest $EXT_PATH shell: bash - name: Create build directories @@ -369,8 +342,7 @@ jobs: -DOCIO_INSTALL_EXT_PACKAGES=NONE \ -DOCIO_WARNING_AS_ERROR=OFF \ -DPython_EXECUTABLE=$(which python) \ - -DOCIO_BUILD_PYTHON=OFF \ - -DOCIO_USE_OIIO_FOR_APPS=${{ matrix.use-oiio }} + -DOCIO_BUILD_PYTHON=OFF shell: bash working-directory: _build - name: Build diff --git a/.github/workflows/platform_latest.yml b/.github/workflows/platform_latest.yml index ab1749bab..aa0be17dd 100644 --- a/.github/workflows/platform_latest.yml +++ b/.github/workflows/platform_latest.yml @@ -153,7 +153,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -187,14 +187,14 @@ jobs: build-shared: ON cxx-standard: 23 enable-sanitizer: OFF - python-version: '3.11' + python-version: '3.13' - build: 2 build-python: OFF build-type: Debug build-shared: ON cxx-standard: 23 enable-sanitizer: ON - python-version: '3.11' + python-version: '3.9' steps: - name: Setup Python uses: actions/setup-python@v5 @@ -266,7 +266,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -298,14 +298,14 @@ jobs: build-python: ON build-type: Release build-shared: ON - cxx-standard: 23 - python-version: '3.11' + cxx-standard: 20 + python-version: '3.13' - build: 2 build-python: ON build-type: Debug build-shared: ON - cxx-standard: 23 - python-version: '3.11' + cxx-standard: 20 + python-version: '3.9' steps: - name: Setup Python uses: actions/setup-python@v5 @@ -387,7 +387,7 @@ jobs: -Dpystring_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_ROOT=${{ env.ocio_build_path }}/ext/dist \ -Dyaml-cpp_STATIC_LIBRARY=ON \ - -Dyaml-cpp_VERSION=0.7.0 \ + -Dyaml-cpp_VERSION=0.8.0 \ -DZLIB_ROOT=${{ env.ocio_build_path }}/ext/dist \ -DZLIB_STATIC_LIBRARY=ON \ -Dminizip-ng_ROOT=${{ env.ocio_build_path }}/ext/dist \ diff --git a/.github/workflows/wheel_workflow.yml b/.github/workflows/wheel_workflow.yml index 51fb225be..f0877d863 100644 --- a/.github/workflows/wheel_workflow.yml +++ b/.github/workflows/wheel_workflow.yml @@ -81,10 +81,6 @@ jobs: # ------------------------------------------------------------------- # CPython 64 bits manylinux_2_28 # ------------------------------------------------------------------- - - build: CPython 3.8 64 bits manylinux_2_28 - manylinux: manylinux_2_28 - python: cp38-manylinux_x86_64 - arch: x86_64 - build: CPython 3.9 64 bits manylinux_2_28 manylinux: manylinux_2_28 python: cp39-manylinux_x86_64 @@ -105,13 +101,13 @@ jobs: manylinux: manylinux_2_28 python: cp313-manylinux_x86_64 arch: x86_64 + - build: CPython 3.14 64 bits manylinux_2_28 + manylinux: manylinux_2_28 + python: cp314-manylinux_x86_64 + arch: x86_64 # ------------------------------------------------------------------- # CPython 64 bits manylinux2014 # ------------------------------------------------------------------- - - build: CPython 3.8 64 bits manylinux2014 - manylinux: manylinux2014 - python: cp38-manylinux_x86_64 - arch: x86_64 - build: CPython 3.9 64 bits manylinux2014 manylinux: manylinux2014 python: cp39-manylinux_x86_64 @@ -132,6 +128,10 @@ jobs: manylinux: manylinux2014 python: cp313-manylinux_x86_64 arch: x86_64 + - build: CPython 3.14 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp314-manylinux_x86_64 + arch: x86_64 steps: - uses: actions/checkout@v4 @@ -139,10 +139,10 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.9' + python-version: '3.11' - name: Build wheels - uses: pypa/cibuildwheel@v2.22.0 + uses: pypa/cibuildwheel@v3.1.4 env: CIBW_BUILD: ${{ matrix.python }} CIBW_ARCHS: ${{ matrix.arch }} @@ -170,10 +170,6 @@ jobs: # ------------------------------------------------------------------- # CPython ARM 64 bits manylinux2014 # ------------------------------------------------------------------- - - build: CPython 3.8 ARM 64 bits manylinux2014 - manylinux: manylinux2014 - python: cp38-manylinux_aarch64 - arch: aarch64 - build: CPython 3.9 ARM 64 bits manylinux2014 manylinux: manylinux2014 python: cp39-manylinux_aarch64 @@ -194,6 +190,10 @@ jobs: manylinux: manylinux2014 python: cp313-manylinux_aarch64 arch: aarch64 + - build: CPython 3.14 ARM 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp314-manylinux_aarch64 + arch: aarch64 steps: - uses: actions/checkout@v4 @@ -201,10 +201,10 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.9' + python-version: '3.11' - name: Build wheels - uses: pypa/cibuildwheel@v2.22.0 + uses: pypa/cibuildwheel@v3.1.4 env: CIBW_BUILD: ${{ matrix.python }} CIBW_ARCHS: ${{ matrix.arch }} @@ -232,9 +232,6 @@ jobs: # ------------------------------------------------------------------- # CPython 64 bits # ------------------------------------------------------------------- - - build: CPython 3.8 64 bits - python: cp38-macosx_x86_64 - arch: x86_64 - build: CPython 3.9 64 bits python: cp39-macosx_x86_64 arch: x86_64 @@ -250,6 +247,9 @@ jobs: - build: CPython 3.13 64 bits python: cp313-macosx_x86_64 arch: x86_64 + - build: CPython 3.14 64 bits + python: cp314-macosx_x86_64 + arch: x86_64 steps: - uses: actions/checkout@v4 @@ -257,14 +257,14 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.9' + python-version: '3.11' - name: Remove brew OpenEXR/Imath run: | brew uninstall --ignore-dependencies openexr imath || true - name: Build wheels - uses: pypa/cibuildwheel@v2.22.0 + uses: pypa/cibuildwheel@v3.1.4 env: CIBW_BUILD: ${{ matrix.python }} CIBW_ARCHS: ${{ matrix.arch }} @@ -291,9 +291,6 @@ jobs: # ------------------------------------------------------------------- # CPython ARM 64 bits # ------------------------------------------------------------------- - - build: CPython 3.8 ARM 64 bits - python: cp38-macosx_arm64 - arch: arm64 - build: CPython 3.9 ARM 64 bits python: cp39-macosx_arm64 arch: arm64 @@ -309,6 +306,9 @@ jobs: - build: CPython 3.13 ARM 64 bits python: cp313-macosx_arm64 arch: arm64 + - build: CPython 3.14 ARM 64 bits + python: cp314-macosx_arm64 + arch: arm64 steps: - uses: actions/checkout@v4 @@ -316,10 +316,10 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.9' + python-version: '3.11' - name: Build wheels - uses: pypa/cibuildwheel@v2.22.0 + uses: pypa/cibuildwheel@v3.1.4 env: CIBW_BUILD: ${{ matrix.python }} CIBW_ARCHS: ${{ matrix.arch }} @@ -346,9 +346,6 @@ jobs: # ------------------------------------------------------------------- # CPython 64 bits # ------------------------------------------------------------------- - - build: CPython 3.8 64 bits - python: cp38-win_amd64 - arch: AMD64 - build: CPython 3.9 64 bits python: cp39-win_amd64 arch: AMD64 @@ -364,6 +361,9 @@ jobs: - build: CPython 3.13 64 bits python: cp313-win_amd64 arch: AMD64 + - build: CPython 3.14 64 bits + python: cp314-win_amd64 + arch: AMD64 steps: - uses: actions/checkout@v4 @@ -371,10 +371,10 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.9' + python-version: '3.11' - name: Build wheels - uses: pypa/cibuildwheel@v2.22.0 + uses: pypa/cibuildwheel@v3.1.4 env: CIBW_BUILD: ${{ matrix.python }} CIBW_ARCHS: ${{ matrix.arch }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 579255ddd..9ad6d3c8a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set(CMAKE_WARN_DEPRECATED ON) if(APPLE AND NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET) # The value of this variable should be set prior to the first project() command invocation # because it may influence configuration of the toolchain and flags. - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version") + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") endif() diff --git a/docs/quick_start/installation.rst b/docs/quick_start/installation.rst index 03da2f9e9..d8d208e05 100644 --- a/docs/quick_start/installation.rst +++ b/docs/quick_start/installation.rst @@ -122,28 +122,28 @@ items manually: Required components: -- C++ 11-17 compiler (gcc, clang, msvc) +- C++ 17-23 compiler (gcc, clang, msvc) - CMake >= 3.14 -- \*Expat >= 2.4.1 (XML parser for CDL/CLF/CTF) -- \*yaml-cpp >= 0.7.0 (YAML parser for Configs) +- \*Expat >= 2.6.0 (XML parser for CDL/CLF/CTF) +- \*yaml-cpp >= 0.8.0 (YAML parser for Configs) - \*Imath >= 3.1.1 (for half domain LUTs) - \*pystring >= 1.1.3 -- \*minizip-ng >= 3.0.7 (for config archiving) +- \*minizip-ng >= 4.0.0 (for config archiving) - \*ZLIB >= 1.2.13 (for config archiving) Optional OCIO functionality also depends on: - \*Little CMS >= 2.2 (for ociobakelut ICC profile baking) - \*OpenGL GLUT & GLEW (for ociodisplay) -- \*OpenEXR >= 3.0.5 (for apps including ocioconvert) +- \*OpenEXR >= 3.2.0 (for apps including ocioconvert) - OpenImageIO >= 2.2.14 (for apps including ocioconvert) - \*OpenFX >= 1.4 (for the OpenFX plug-ins) -- OpenShadingLanguage >= 1.11 (for the OSL unit tests) +- OpenShadingLanguage >= 1.13 (for the OSL unit tests) - Doxygen (for the docs) - NumPy (optionally used in the Python test suite) - \*pybind11 >= 2.9.2 (for the Python binding) -- Python >= 3.7 (for the Python binding only) -- Python 3.7 - 3.9 (for building the documentation) +- Python >= 3.9 (for the Python binding only) +- Python 3.9+ (for building the documentation) Building the documentation requires the following packages, available via PyPI: diff --git a/pyproject.toml b/pyproject.toml index 793353ff6..f5677d121 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,9 +30,9 @@ test-command = [ before-build = "share/ci/scripts/linux/dnf/install_docs_env.sh" [tool.cibuildwheel.macos] -# cibuildwheel in some cases set this to 10.9 by default, OCIO needs >= 10.13 +# cibuildwheel in some cases set this to 10.9 by default, OCIO needs >= 10.15 # macOS ARM wheels needs 11.0, cibuildwheel will automatically bump where appropriate -environment = { MACOSX_DEPLOYMENT_TARGET="10.13" } +environment = { MACOSX_DEPLOYMENT_TARGET="10.15" } before-build = "share/ci/scripts/macos/install_docs_env.sh" [tool.cibuildwheel.windows] diff --git a/setup.cfg b/setup.cfg index d5af16ae6..aa1015183 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,13 +7,12 @@ classifiers = Topic :: Software Development :: Libraries :: Python Modules Programming Language :: C++ Programming Language :: Python :: 3 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: 3.13 + Programming Language :: Python :: 3.14 Programming Language :: Python :: Implementation :: CPython Programming Language :: C++ description = OpenColorIO (OCIO) is a complete color management solution geared towards motion picture production with an emphasis on visual effects and computer animation. @@ -22,7 +21,7 @@ license_files = LICENSE long_description = file: README.md, LICENSE long_description_content_type = text/markdown name = opencolorio -python_requires = '>=3.7' +python_requires = '>=3.9' url = https://opencolorio.org/ [options] diff --git a/share/ci/scripts/multi/install_yaml-cpp.sh b/share/ci/scripts/multi/install_yaml-cpp.sh index 7a916170b..726514137 100755 --- a/share/ci/scripts/multi/install_yaml-cpp.sh +++ b/share/ci/scripts/multi/install_yaml-cpp.sh @@ -23,8 +23,10 @@ if [ "$YAMLCPP_VERSION" == "latest" ]; then else if [[ "$YAMLCPP_MINOR" -lt 6 && "$YAMLCPP_PATCH" -lt 3 ]]; then git checkout tags/release-${YAMLCPP_VERSION} -b release-${YAMLCPP_VERSION} - else + elif [[ "$YAMLCPP_MINOR" -lt 8 ]]; then git checkout tags/yaml-cpp-${YAMLCPP_VERSION} -b yaml-cpp-${YAMLCPP_VERSION} + else + git checkout tags/${YAMLCPP_VERSION} -b ${YAMLCPP_VERSION} fi fi diff --git a/share/cmake/macros/GetPythonPreCommand.cmake b/share/cmake/macros/GetPythonPreCommand.cmake index d5539f8ec..018692a33 100644 --- a/share/cmake/macros/GetPythonPreCommand.cmake +++ b/share/cmake/macros/GetPythonPreCommand.cmake @@ -22,6 +22,7 @@ macro(get_python_pre_command) if(WIN32) # Use Windows path separators since this is being passed through to cmd file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR} _WIN_BINARY_DIR) + file(TO_NATIVE_PATH ${PROJECT_SOURCE_DIR} _WIN_SOURCE_DIR) set(_DLL_PATH "${_WIN_BINARY_DIR}\\src\\OpenColorIO") if(MSVC_IDE) @@ -42,15 +43,20 @@ macro(get_python_pre_command) # Build path list set(_WIN_PATHS - ${_PYD_PATH} - "${PROJECT_SOURCE_DIR}\\share\\docs" + ${_PYD_PATH} + "${_WIN_SOURCE_DIR}\\share\\docs" ) # Include optional paths from macro arguments foreach(_PATH ${ARGN}) file(TO_NATIVE_PATH ${_PATH} _WIN_PATH) list(APPEND _WIN_PATHS ${_WIN_PATH}) endforeach() - list(APPEND _WIN_PATHS "%PYTHONPATH%") + + # Double % to escape as the cmd.exe will eat one level of %. That + # results in an empty path in the ENV variable and Python fails to + # convert that to absolute path. Possibly due to + # https://www.cve.news/cve-2023-41105/ + list(APPEND _WIN_PATHS "%%PYTHONPATH%%") string(JOIN "\\\\;" _PYTHONPATH_VALUE ${_WIN_PATHS}) string(CONCAT _PYTHONPATH_SET "PYTHONPATH=${_PYTHONPATH_VALUE}") diff --git a/share/cmake/modules/FindExtPackages.cmake b/share/cmake/modules/FindExtPackages.cmake index 7cdb17b4e..6353bdf5c 100644 --- a/share/cmake/modules/FindExtPackages.cmake +++ b/share/cmake/modules/FindExtPackages.cmake @@ -55,29 +55,29 @@ message(STATUS "Checking for mandatory dependencies...") # expat # https://github.com/libexpat/libexpat ocio_handle_dependency( expat REQUIRED ALLOW_INSTALL - MIN_VERSION 2.4.1 - RECOMMENDED_VERSION 2.5.0 - RECOMMENDED_VERSION_REASON "CVE fixes and fix issue with symbol leakage when built as a static library") + MIN_VERSION 2.6.0 + RECOMMENDED_VERSION 2.7.2 + RECOMMENDED_VERSION_REASON "CVE fixes and Latest version tested with OCIO") # yaml-cpp # https://github.com/jbeder/yaml-cpp ocio_handle_dependency( yaml-cpp REQUIRED ALLOW_INSTALL - MIN_VERSION 0.6.3 - RECOMMENDED_VERSION 0.7.0 + MIN_VERSION 0.8.0 + RECOMMENDED_VERSION 0.8.0 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") # pystring # https://github.com/imageworks/pystring ocio_handle_dependency( pystring REQUIRED ALLOW_INSTALL MIN_VERSION 1.1.3 - RECOMMENDED_VERSION 1.1.3 + RECOMMENDED_VERSION 1.1.4 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") -# Imath (>=3.1) +# Imath # https://github.com/AcademySoftwareFoundation/Imath ocio_handle_dependency( Imath REQUIRED ALLOW_INSTALL MIN_VERSION 3.1.1 - RECOMMENDED_VERSION 3.1.12 + RECOMMENDED_VERSION 3.2.1 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") ############################################################################### @@ -101,9 +101,9 @@ ocio_handle_dependency( Imath REQUIRED ALLOW_INSTALL # See https://nvd.nist.gov/vuln/detail/CVE-2022-37434 # See https://github.com/madler/zlib/releases/tag/v1.2.13 ocio_handle_dependency( ZLIB REQUIRED ALLOW_INSTALL - MIN_VERSION 1.2.8 - RECOMMENDED_VERSION 1.2.13 - RECOMMENDED_VERSION_REASON "CVE fixes" + MIN_VERSION 1.2.13 # CVE fixes + RECOMMENDED_VERSION 1.3.1 + RECOMMENDED_VERSION_REASON "Latest version tested with OCIO" VERSION_VARS ZLIB_VERSION_STRING ZLIB_VERSION ) ############################################################################### @@ -111,8 +111,8 @@ ocio_handle_dependency( ZLIB REQUIRED ALLOW_INSTALL # minizip-ng # https://github.com/zlib-ng/minizip-ng ocio_handle_dependency( minizip-ng REQUIRED ALLOW_INSTALL - MIN_VERSION 3.0.6 - RECOMMENDED_VERSION 3.0.7 + MIN_VERSION 4.0.0 + RECOMMENDED_VERSION 4.0.10 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") ############################################################################### @@ -133,7 +133,7 @@ if(OCIO_BUILD_APPS) # https://github.com/mm2/Little-CMS ocio_handle_dependency( lcms2 REQUIRED ALLOW_INSTALL MIN_VERSION 2.2 - RECOMMENDED_VERSION 2.2 + RECOMMENDED_VERSION 2.17 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") endif() @@ -142,7 +142,7 @@ if(OCIO_BUILD_OPENFX) # https://github.com/ofxa/openfx ocio_handle_dependency( openfx REQUIRED ALLOW_INSTALL MIN_VERSION 1.4 - RECOMMENDED_VERSION 1.4 + RECOMMENDED_VERSION 1.5 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") endif() @@ -179,19 +179,18 @@ if(OCIO_BUILD_PYTHON OR OCIO_BUILD_DOCS) # pybind11 2.9 fixes issues with MS Visual Studio 2022 (Debug). ocio_handle_dependency( pybind11 REQUIRED ALLOW_INSTALL MIN_VERSION 2.9.2 - RECOMMENDED_VERSION 2.12.1) + RECOMMENDED_VERSION 3.0.1) endif() endif() # Set OpenEXR Minimum version as a variable since it it used at multiple places. -set(OpenEXR_MININUM_VERSION "3.1.6") if((OCIO_BUILD_APPS AND OCIO_USE_OIIO_FOR_APPS) OR OCIO_BUILD_TESTS) # OpenImageIO is required for OSL unit test and optional for apps. # OpenImageIO # https://github.com/OpenImageIO/oiio set(OIIO_VERSION "2.2.14") - set(OIIO_RECOMMENDED_VERSION "2.4") + set(OIIO_RECOMMENDED_VERSION "3") # Supported from OIIO 2.4+. Setting this for lower versions doesn't affect anything. set(OPENIMAGEIO_CONFIG_DO_NOT_FIND_IMATH 1) @@ -259,8 +258,8 @@ if(OCIO_BUILD_APPS) ############################################################################### # Calling find_package in CONFIG mode using PREFER_CONFIG option. ocio_handle_dependency( OpenEXR PREFER_CONFIG ALLOW_INSTALL - MIN_VERSION ${OpenEXR_MININUM_VERSION} - RECOMMENDED_VERSION 3.1.6 + MIN_VERSION 3.2.0 + RECOMMENDED_VERSION 3.3.5 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO" PROMOTE_TARGET OpenEXR::OpenEXR) @@ -285,8 +284,8 @@ if(OCIO_BUILD_TESTS) # OpenShadingLanguage # https://github.com/AcademySoftwareFoundation/OpenShadingLanguage ocio_handle_dependency( OSL - MIN_VERSION 1.11 - RECOMMENDED_VERSION 1.11 + MIN_VERSION 1.13 + RECOMMENDED_VERSION 1.14 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO") if(NOT OSL_FOUND) message(WARNING "Skipping build of the OpenShadingLanguage unit tests (OSL missing)") diff --git a/share/cmake/modules/Findyaml-cpp.cmake b/share/cmake/modules/Findyaml-cpp.cmake index 110ae2e4c..d10bdb4f5 100644 --- a/share/cmake/modules/Findyaml-cpp.cmake +++ b/share/cmake/modules/Findyaml-cpp.cmake @@ -12,10 +12,6 @@ # Global targets defined by this module: # yaml-cpp::yaml-cpp # -# For compatibility with the upstream CMake package, the following variables and targets are defined: -# YAML_CPP_LIBRARIES - Libraries to link against yaml-cpp -# YAML_CPP_INCLUDE_DIR - Include directory -# # Usually CMake will use the dynamic library rather than static, if both are present. # In this case, you may set yaml-cpp_STATIC_LIBRARY to ON to request use of the static one. # If only the static library is present (such as when OCIO builds the dependency), then the option @@ -163,10 +159,3 @@ if (yaml-cpp_FOUND AND NOT TARGET yaml-cpp::yaml-cpp) add_library(yaml-cpp ALIAS yaml-cpp::yaml-cpp) endif () endif () - -if (yaml-cpp_FOUND) - # TODO: Remove this variable and use the `yaml-cpp::yaml-cpp` target - # directly when the minimum version of yaml-cpp is updated to 0.8. - get_target_property(YAML_CPP_INCLUDE_DIR yaml-cpp::yaml-cpp INCLUDE_DIRECTORIES) - set(YAML_CPP_LIBRARIES yaml-cpp::yaml-cpp) -endif () diff --git a/share/cmake/modules/install/InstallOpenEXR.cmake b/share/cmake/modules/install/InstallOpenEXR.cmake index be9a70872..7fde736ee 100644 --- a/share/cmake/modules/install/InstallOpenEXR.cmake +++ b/share/cmake/modules/install/InstallOpenEXR.cmake @@ -110,7 +110,9 @@ if(NOT OpenEXR_FOUND AND OCIO_INSTALL_EXT_PACKAGES AND NOT OCIO_INSTALL_EXT_PACK -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DOPENEXR_INSTALL_EXAMPLES=OFF + -DOPENEXR_BUILD_EXAMPLES=OFF -DOPENEXR_BUILD_TOOLS=OFF + -DOPENEXR_FORCE_INTERNAL_DEFLATE=ON # Try to use in-source built Imath first, if available. -DCMAKE_PREFIX_PATH=${_EXT_DIST_ROOT} ) @@ -177,6 +179,13 @@ if(NOT OpenEXR_FOUND AND OCIO_INSTALL_EXT_PACKAGES AND NOT OCIO_INSTALL_EXT_PACK add_dependencies(OpenEXR::OpenEXR openexr_install) + # When building Imath ourselves, make sure it has been built first + # so that OpenEXR can find it. Otherwise OpenEXR will build its + # own copy of Imath which might result in version conflicts. + if (TARGET imath_install) + add_dependencies(openexr_install imath_install) + endif() + if(OCIO_VERBOSE) message(STATUS "Installing OpenEXR: ${OpenEXR_LIBRARY} (version \"${OpenEXR_VERSION}\")") endif() @@ -209,7 +218,7 @@ if(_OpenEXR_TARGET_CREATE) set_target_properties(OpenEXR::OpenEXR PROPERTIES IMPORTED_LOCATION ${OpenEXR_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIR}" - INTERFACE_LINK_LIBRARIES "OpenEXR::IlmThreadConfig;Imath::Imath;OpenEXR::IlmThreadConfig;OpenEXR::Iex;OpenEXR::IlmThread;ZLIB::ZLIB" + INTERFACE_LINK_LIBRARIES "OpenEXR::IlmThreadConfig;Imath::Imath;OpenEXR::IlmThreadConfig;OpenEXR::Iex;OpenEXR::IlmThread;OpenEXR::OpenEXRCore" ) set_target_properties(OpenEXR::OpenEXRConfig PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIR};${OpenEXR_INCLUDE_DIR}/OpenEXR" @@ -217,13 +226,13 @@ if(_OpenEXR_TARGET_CREATE) set_target_properties(OpenEXR::OpenEXRCore PROPERTIES IMPORTED_LOCATION ${OpenEXRCore_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIR}" - INTERFACE_LINK_LIBRARIES "OpenEXR::IlmThreadConfig;ZLIB::ZLIB;\$" + INTERFACE_LINK_LIBRARIES "OpenEXR::IlmThreadConfig;Imath::Imath" STATIC_LIBRARY_OPTIONS "-no_warning_for_no_symbols" ) set_target_properties(OpenEXR::OpenEXRUtil PROPERTIES IMPORTED_LOCATION ${OpenEXRUtil_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIR}" - INTERFACE_LINK_LIBRARIES "OpenEXR::IlmThreadConfig;OpenEXR::OpenEXR" + INTERFACE_LINK_LIBRARIES "OpenEXR::IlmThreadConfig;OpenEXR::OpenEXR;OpenEXR::OpenEXRCore" ) mark_as_advanced(OpenEXR_INCLUDE_DIR OpenEXR_LIBRARY OpenEXR_VERSION) diff --git a/share/cmake/modules/install/Installminizip-ng.cmake b/share/cmake/modules/install/Installminizip-ng.cmake index 19c54a950..28b6e6a78 100644 --- a/share/cmake/modules/install/Installminizip-ng.cmake +++ b/share/cmake/modules/install/Installminizip-ng.cmake @@ -45,7 +45,12 @@ if(NOT minizip-ng_FOUND AND OCIO_INSTALL_EXT_PACKAGES AND NOT OCIO_INSTALL_EXT_P set(minizip-ng_INCLUDE_DIR "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_INCLUDEDIR}/minizip-ng") # Minizip-ng use a hardcoded lib prefix instead of CMAKE_STATIC_LIBRARY_PREFIX - set(_minizip-ng_LIB_PREFIX "lib") + # Fixed from 4.0.7, see https://github.com/zlib-ng/minizip-ng/issues/778 + if(${minizip-ng_VERSION} VERSION_GREATER_EQUAL "4.0.7") + set(_minizip-ng_LIB_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}") + else() + set(_minizip-ng_LIB_PREFIX "lib") + endif() set(minizip-ng_LIBRARY "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_LIBDIR}/${_minizip-ng_LIB_PREFIX}minizip-ng${_minizip-ng_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") @@ -63,11 +68,6 @@ if(NOT minizip-ng_FOUND AND OCIO_INSTALL_EXT_PACKAGES AND NOT OCIO_INSTALL_EXT_P -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DCMAKE_INSTALL_DATADIR=${CMAKE_INSTALL_DATADIR} -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} - # Since the other modules create a subfolder for the includes by default and since - # minizip-ng does not, a suffix is added to CMAKE_INSTALL_INCLUDEDIR in order to - # install the headers under a subdirectory named "minizip-ng". - # Note that this does not affect external builds for minizip-ng. - -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR}/minizip-ng -DCMAKE_OBJECT_PATH_MAX=${CMAKE_OBJECT_PATH_MAX} -DBUILD_SHARED_LIBS=OFF -DMZ_OPENSSL=OFF diff --git a/share/cmake/modules/install/Installopenfx.cmake b/share/cmake/modules/install/Installopenfx.cmake index be454de4c..8ce587b33 100644 --- a/share/cmake/modules/install/Installopenfx.cmake +++ b/share/cmake/modules/install/Installopenfx.cmake @@ -50,9 +50,11 @@ if(NOT openfx_FOUND AND OCIO_INSTALL_EXT_PACKAGES AND NOT OCIO_INSTALL_EXT_PACKA ExternalProject_Add(openfx_install GIT_REPOSITORY "https://github.com/ofxa/openfx.git" - # The latest version from 2015 is OFX_Release_1_4_TAG. + # The latest version from 2015 is OFX_Release_1_4_TAG. + # The latest version from 2024 is OFX_Release_1.5. # Need to be careful since older version might have the patch number in the tag. - GIT_TAG "OFX_Release_${openfx_VERSION_MAJOR}_${openfx_VERSION_MINOR}_TAG" + # There don't seem to be enough consistency in tag names that we can rely on. + GIT_TAG "OFX_Release_${openfx_VERSION_MAJOR}.${openfx_VERSION_MINOR}" GIT_CONFIG advice.detachedHead=false GIT_SHALLOW TRUE PREFIX "${_EXT_BUILD_ROOT}/openfx" diff --git a/share/cmake/modules/install/Installpybind11.cmake b/share/cmake/modules/install/Installpybind11.cmake index a0ae71f15..f432d5289 100644 --- a/share/cmake/modules/install/Installpybind11.cmake +++ b/share/cmake/modules/install/Installpybind11.cmake @@ -120,5 +120,13 @@ if(_pybind11_TARGET_CREATE) INTERFACE_INCLUDE_DIRECTORIES ${pybind11_INCLUDE_DIR} ) + # See pybind11Common.cmake for reasoning + if (MSVC) + set_target_properties(pybind11::module PROPERTIES + INTERFACE_COMPILE_OPTIONS /bigobj + ) + + endif() + mark_as_advanced(pybind11_INCLUDE_DIR pybind11_VERSION) endif() diff --git a/share/cmake/modules/install/Installyaml-cpp.cmake b/share/cmake/modules/install/Installyaml-cpp.cmake index 6353a4d1d..3ec993969 100644 --- a/share/cmake/modules/install/Installyaml-cpp.cmake +++ b/share/cmake/modules/install/Installyaml-cpp.cmake @@ -10,12 +10,7 @@ # yaml-cpp_VERSION - Library's version # # Global targets defined by this module: -# yaml-cpp::yaml-cpp -# -# For compatibility with the upstream CMake package, the following variables and targets are defined: -# yaml-cpp::yaml-cpp - Alias of the yaml-cpp target -# YAML_CPP_LIBRARIES - Libraries to link against yaml-cpp -# YAML_CPP_INCLUDE_DIR - Include directory +# yaml-cpp::yaml-cpp # ############################################################################### @@ -118,7 +113,8 @@ if(NOT yaml-cpp_FOUND AND OCIO_INSTALL_EXT_PACKAGES AND NOT OCIO_INSTALL_EXT_PAC -DANDROID_STL=${ANDROID_STL}) endif() - set(yaml-cpp_GIT_TAG "yaml-cpp-${yaml-cpp_VERSION}") + # in v0.8.0 yaml switched from "yaml-cpp-vA.B.C" to "vA.B.C" format for tags. + set(yaml-cpp_GIT_TAG "${yaml-cpp_VERSION}") # Hack to let imported target be built from ExternalProject_Add file(MAKE_DIRECTORY ${yaml-cpp_INCLUDE_DIR}) @@ -154,10 +150,9 @@ if(_yaml-cpp_TARGET_CREATE) set_target_properties(yaml-cpp::yaml-cpp PROPERTIES IMPORTED_LOCATION ${yaml-cpp_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${yaml-cpp_INCLUDE_DIR} + # https://github.com/jbeder/yaml-cpp/issues/1339 + INTERFACE_COMPILE_DEFINITIONS YAML_CPP_STATIC_DEFINE ) mark_as_advanced(yaml-cpp_INCLUDE_DIR yaml-cpp_LIBRARY yaml-cpp_VERSION) endif() - -set(YAML_CPP_INCLUDE_DIR "${yaml-cpp_INCLUDE_DIR}") -set(YAML_CPP_LIBRARIES yaml-cpp::yaml-cpp) diff --git a/share/cmake/utils/CompilerFlags.cmake b/share/cmake/utils/CompilerFlags.cmake index d87e73f2d..3e609ef6a 100644 --- a/share/cmake/utils/CompilerFlags.cmake +++ b/share/cmake/utils/CompilerFlags.cmake @@ -60,12 +60,13 @@ if(USE_MSVC) # /we4062 Enables warning in switch when an enumeration value is not explicitly handled. set(PLATFORM_COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS};/EHsc;/DWIN32;/we4062") - if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 17) - # Inheriting from std::iterator is deprecated starting with C++17 and Yaml 0.6.3 does that. - set(PLATFORM_COMPILE_OPTIONS - "${PLATFORM_COMPILE_OPTIONS};/D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING" - ) - endif() + # seems no longer needed, there were c++ modernization on 0.7.0. /coz +# if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 17) +# # Inheriting from std::iterator is deprecated starting with C++17 and Yaml 0.6.3 does that. +# set(PLATFORM_COMPILE_OPTIONS +# "${PLATFORM_COMPILE_OPTIONS};/D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING" +# ) +# endif() # Make MSVC compiler report correct __cplusplus version (otherwise reports 199711L) set(PLATFORM_COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS};/Zc:__cplusplus") diff --git a/share/cmake/utils/CppVersion.cmake b/share/cmake/utils/CppVersion.cmake index 175d89c20..127ec9e7f 100644 --- a/share/cmake/utils/CppVersion.cmake +++ b/share/cmake/utils/CppVersion.cmake @@ -5,12 +5,12 @@ ############################################################################### # C++ version configuration -set(SUPPORTED_CXX_STANDARDS 11 14 17) +set(SUPPORTED_CXX_STANDARDS 17 20 23) string(REPLACE ";" ", " SUPPORTED_CXX_STANDARDS_STR "${SUPPORTED_CXX_STANDARDS}") if(NOT DEFINED CMAKE_CXX_STANDARD) - message(STATUS "Setting C++ version to '14' as none was specified.") - set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to compile against") + message(STATUS "Setting C++ version to '17' as none was specified.") + set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to compile against") elseif(NOT CMAKE_CXX_STANDARD IN_LIST SUPPORTED_CXX_STANDARDS) message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} is unsupported. Supported standards are: ${SUPPORTED_CXX_STANDARDS_STR}.") @@ -29,48 +29,45 @@ else() set(CUSTOM_CXX_FLAGS "-w") endif() -if(${CMAKE_CXX_STANDARD} EQUAL 11) +if(${CMAKE_CXX_STANDARD} EQUAL 17) if(USE_MSVC) - CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std:c++11" COMPILER_SUPPORTS_CXX11) + CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std:c++17" COMPILER_SUPPORTS_CXX17) else() - CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std=c++11" COMPILER_SUPPORTS_CXX11) + CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std=c++17" COMPILER_SUPPORTS_CXX17) endif() - if(NOT COMPILER_SUPPORTS_CXX11) - message(STATUS - "The compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++11 only support. Use C++14.") - set(CMAKE_CXX_STANDARD 14) + if(NOT COMPILER_SUPPORTS_CXX17) + message(FATAL_ERROR + "The compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++17 support.") endif() endif() -if(${CMAKE_CXX_STANDARD} EQUAL 14) +if(${CMAKE_CXX_STANDARD} EQUAL 20) if(USE_MSVC) - CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std:c++14" COMPILER_SUPPORTS_CXX14) + CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std:c++20" COMPILER_SUPPORTS_CXX20) else() - CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std=c++14" COMPILER_SUPPORTS_CXX14) + CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std=c++20" COMPILER_SUPPORTS_CXX20) endif() - if(NOT COMPILER_SUPPORTS_CXX14) - message(STATUS - "The compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++14 only support. Use C++17.") - set(CMAKE_CXX_STANDARD 17) + if(NOT COMPILER_SUPPORTS_CXX20) + message(FATAL_ERROR + "The compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++20 support.") endif() endif() -if(${CMAKE_CXX_STANDARD} EQUAL 17) +if(${CMAKE_CXX_STANDARD} EQUAL 23) if(USE_MSVC) - CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std:c++17" COMPILER_SUPPORTS_CXX17) + CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std:c++23" COMPILER_SUPPORTS_CXX23) else() - CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std=c++17" COMPILER_SUPPORTS_CXX17) + CHECK_CXX_COMPILER_FLAG("${CUSTOM_CXX_FLAGS} -std=c++23" COMPILER_SUPPORTS_CXX23) endif() - if(NOT COMPILER_SUPPORTS_CXX17) + if(NOT COMPILER_SUPPORTS_CXX23) message(FATAL_ERROR - "The compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++17 support.") + "The compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++23 support.") endif() endif() - # Disable fallback to other C++ version if standard is not supported. set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/src/OpenColorIO/CMakeLists.txt b/src/OpenColorIO/CMakeLists.txt index 7d2894da6..ebef9328a 100755 --- a/src/OpenColorIO/CMakeLists.txt +++ b/src/OpenColorIO/CMakeLists.txt @@ -315,7 +315,7 @@ target_link_libraries(OpenColorIO "$" "$" "$" - ${YAML_CPP_LIBRARIES} + yaml-cpp::yaml-cpp MINIZIP::minizip-ng ) diff --git a/src/OpenColorIO/SystemMonitor_macos.cpp b/src/OpenColorIO/SystemMonitor_macos.cpp index 995790388..4b212e685 100644 --- a/src/OpenColorIO/SystemMonitor_macos.cpp +++ b/src/OpenColorIO/SystemMonitor_macos.cpp @@ -190,13 +190,13 @@ void SystemMonitorsImpl::getAllMonitors() CFDictionaryGetKeysAndValues(productInfo, nullptr, (const void **)&values[0]); const CFIndex bufferSize = CFStringGetLength(values[0]) + 1; // +1 for null termination - char buffer[bufferSize]; + std::vector buffer(bufferSize); // Return false if the buffer is too small or if the conversion fails. - if (CFStringGetCString(values[0], buffer, bufferSize, kCFStringEncodingUTF8)) + if (CFStringGetCString(values[0], buffer.data(), buffer.size(), kCFStringEncodingUTF8)) { // Build a name using the vendor information. - displayName = buffer; + displayName = buffer.data(); // Add the display unit number (i.e. identify the display's framebuffer) // to differentiate same type of monitors. diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index 66c32cb8a..322f0f94b 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -35,7 +35,7 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES) sampleicc::sampleicc unittest_data utils::strings - ${YAML_CPP_LIBRARIES} + yaml-cpp::yaml-cpp testutils MINIZIP::minizip-ng xxHash diff --git a/tests/cpu/fileformats/FileFormatCTF_tests.cpp b/tests/cpu/fileformats/FileFormatCTF_tests.cpp index b9b266216..25cc87a4d 100644 --- a/tests/cpu/fileformats/FileFormatCTF_tests.cpp +++ b/tests/cpu/fileformats/FileFormatCTF_tests.cpp @@ -1454,7 +1454,7 @@ OCIO_ADD_TEST(FileFormatCTF, difficult_xml_unknown_elements) "(37): Unrecognized element 'just_ignore' where its parent is 'ProcessList' (8): Unknown element", "(69): Unrecognized element 'just_ignore' where its parent is 'Description' (66)", "(70): Unrecognized element 'just_ignore' where its parent is 'just_ignore' (69)", - "(75): Unrecognized element 'Matrix' where its parent is 'LUT1D' (43): 'Matrix' not allowed in this element", + "(75): Unrecognized element 'Matrix' where its parent is 'LUT1D' (", // Line number is expat library version dependent. "(76): Unrecognized element 'Description' where its parent is 'Matrix' (75)", "(77): Unrecognized element 'Array' where its parent is 'Matrix' (75)" }; diff --git a/tests/data/files/configs/context_test1/context_test1_windows.ocioz b/tests/data/files/configs/context_test1/context_test1_windows.ocioz index 091b68e52dff5ca6a84804261552391182cb2e95..eb52db3a76a668985327effc763604f5333c8b2a 100644 GIT binary patch literal 3966 zcmbuBc|4SR8^#~|K4ZyJbPQRNeK^rOWtv1pLMUtYWh|4eY+0ug#UROA4wbDK+sM9T zC$dB|vb9P`wwjK29_4MQw^N;G{+MSz&u6aZ^S!U@ci*?J77gtdfSHjI@bQx~1-@JY ztN_45zPG`+**iJNU~HT){YFPH{6g$i^OBB}8A$xFMpne+e_W4A7)mz35{+QDddx@H zz;gm&6u+7lQZjHcM@+}CWVja&wfBimd>F;uR#^Yo%&GNikFOnDBdw6r)i&cIoR}_l z&X%lz%GdxNz`608P$?fAUTJ+PX3GufUOdZ$#MLK}Ev$0v4a^RwjMnWy6g+^nApU6DBHSglhX_+ieRWTaOuaW5xBd*!t| zEsSo&jJD)T9wby&hA_zaL=tF}>YLQ5Q$Czv5HnGP_Yt&*RV;K5b3%NE(VR%$eT!tlA(VcXWY9 z|B|T)jL=pvD6hR-Grv=Uc-2ttr1<23?^CaNV($Tc8YL4A>p}kzfgYbdlZ_r46VGt_ zCTsClVIS?vu4DDWL@zDk*n>tcyTx<{<1ulyc*Ru36Aw=J`Kezl5NjE(r9Ba~>MW0l zLTaK7i|qIvRQ6tjq{R@n9$XzBS$dSmKeD`}tHr>$&8S#hl^OuRgz5e-d*T-)jMuZ* zOalN+fC%7%!8m)$*x0%-1F*GcQ~)0UWG~HhQx8)C=;?|r;!mj7e>cWiIoHdvpGO{_ zMPdUneivP=FP_swMlgS(Q`>RHyDFy16&b|Kb({NzE>U9jJ#6rO*vD`ID+ z*;t{~(a&mNOL#MteFRQY&7 z7Dp|!$bp=&Gn;I#4-%K%^-M2IJxDRmD+^munLNrY*|jCAcc$1ZD0YEJq+1;}cS!Qb zX9m%LwNAd3ImJN*0ANMGU+d@O!ZL!j_V$vOv2n5gnNk}@bwWbr*s(Jrl@0bYhvRWR zH`s&fnYf@I04xvjph=HW7zRW2XITRAO-Dka;><8&?@fFrcXNNNkcOc%>UG~Ex? zCAPH5K$gAFk7*orIGBoshQ76!BtL&>$L!@xw>r`>ijpZ+R3LYu_|SzkG8stseePG} zClE5Xrz6HoUiL@y!DSXuE{dQTMs<H1N=5gyv2RKOocG~mVjnGW|t(Z zWTDoU0Q0zL*YK1MI4=f-7ovNgluE_}5&sz;{x9I+W8)#Hb$FL=;HxVI$||I7Wi&Tq*5xkv`)Iq?*^xf{^^j{Qemw1&{L z)6zHSmkN_pSKx68RpkxGOb)4gnn`aB?YqN~nJ>_F8;x%&49_4r9+6DVZS{rK>G4Z* zm}Hcjn}1rCnyq8AdZ#)ey|CX;D^L~@#Ny$Hl7p_Ut^hlV@uj{YFm90+dI>susVKh8 zUgqYG>z8Vk;EC`H)vbA_=IBA^M+hIoLHM7Gy~4k7p4iwBy!-{;()yd&$3VZtzH#l) zPn|bN9)D&gwfmZbyNJ%0Lyy)sFww-CocUBO6}We)a+Ut%_=!EB^D&4Pvh$VI!Y?m; ztkJGzbiJHy(XIPJbQCoXI!~k0Sn~=efU}c?DTd zZ);m853mLbzZrlMUMT7Q^;7lt!&CqXZY8|5Q*IrB5WMY4yW8pK?b;^qUqg;MZQq(Y zhHhogz?z`ssS_UPoW^@UmkLK0( zm9RG?>6R(UP~YX%E(X5zJ0%M&+w@V?DjEWO1?q@8ouA4D9+K@5O)2JTasTMB>3+7i zc1nnOJF(7>i)8DioEqIrY#H_YO>pHNl_`;p^z%}zJ#i09ic3YNf@u%kj6ay=Jv`k$ z-rStFw{5n>7WkML&ks| z84{i^`8$~%*1A3}BMJJ|dMavZ=C4aV<;n#v^&2mW6<=5D>mR|5jBFpgh#JPeZ|TZdvXrt!MOm|NS0;u`ma-;Vh$yl&sjKXg$$qnB zPeqn2k@Z%iv1Utt^QwEjUGDR{-FN<&d7gRZJJ08Q&-tEXtWO6+0th%9;ItAq1-?Jr zEC9ev{p^7Abar!*!8y3$I?YUQ9dhjF7xLvgcJ)2>Wsa9pdg${s_M)csJEvr+7hYz+ z=J9)ET1R{yR8c)$##HDF-%p696j8neRjH2U7$+vQaUIqt-Ds2iRZIkasOWfGa)eTd z;1$u47+j`9bSYjUIld{9GrG8V?|?eZ5V_?_(5@Fo;-B$5FREEb>=*H&v7E?Eciw~5 zvhfxj&l$Dbm2uXqOZCc%8-EN-GRn=Yb|7maJKL(X7qv8W11`+iHJ&^?BoXCPJcK+o zr>KC=-&c~(zs)9YadP)|@2J=!i)DhJ471I9&B75$xyslB3b`zDFaxgkLl_~g_fA&D z(;tR+1ic4%0d{=ngIa7o;aj3M0;E`WI`; z=p%liXnyu!298j4QgP`~R&?e9$Bm}#vS4?j&ysh_#KTh${-K@`d6O%UIF~#e7UtND zLv>5!6{MoAak43HAQlENQV%c(m5~susF(EZ@#)0LJ=^@Ol~nUTsKh4|iR>&DH>lI%oEb}z71c1(xvzS9 z+`WS}_tTC^+oo>IZnh$_?ea`f#N^>)d3OgB%;ecbUkeI8 zJ7T^-)f#v#+5sgG|Pg~=!nTq&%I)jcm!u0J^@dA_mcgklOK;by$sga zK4)CQkGx>!<$vqJ&H#UJ2e#k5bnQPQ`y;0_xVP2wnWR{=K6`K#{*@`>R7j{?frz8R z{0LrbYA@fNR>r`X3mjT|Io2%M?NBk9ilw~@{jcmk)p&-s5NLI|GcN~QvE7|Mtp@Y^ zNK|~LrjxXb1}wCn*rX#X4FG`U+$i*T_(q`zs8xl7h4%H4mvQiLhSnMA!Krj^QD@U@ z&k;3p?BSGi(N2_JS8;;tu`k3-#I8A-!#jPeg@mJy4!*sQy70MxS#?%E{$^Ndwf2f; z8&}CKeb{Ns?(3CE!alPiRN~=LMv4W$mZ1QxFTI7!9<7fCzvpJNr77gWrbbsp{CR`P z7l(}&rkg*^Tp9W_y{5Qy(0MXwHvAfkWbC835SX}-BhT0=YY6mMF0SdUj+(138o7APnzNv~zV?dV^OFDwcx2)5)_e+1hAhP<0dB7m{ zj&LoDp0gvO;t;}npX^k^Ws|iw&SU5kC=Kh&q9C}}c#Uq-re^2-o8_qQW3Fh0_qBI) z^9K19|L%OSF7oh}{MRZ$=ffA&BgXhS8f#)n!v|BN>i{<6Vj8LS0^njg11@)5=+FiAjHg&da+5cJ)Tvk^0}W=$u1d5kczW6PXtVGWgIuUL>&4me@_3qg#1_q*^Y z##P{`gr}giTXyyDe)J;_3kC71Nv)0cf8?#_9FNSne5i7>vSTmHkp^#4jo^-%p`7-& zCr0UvznV(`qINmnxG|&Rw?a3J7D&|x9y&~aZ!SK4Gc;l`;g z(f>3ZOEsO>m64k98Xt}eF%W{Yw%M+a`#I{kPmfe51}?mpk!8e(MSc!Rkv=1T6W&Y8 z!vu&=`Q$iDN+mS1y)E7so~#A?fOy>I9^RF7-txq5tdkYfP}73poD%S6+q2Y9BMF^j zJkD!~Mqxa>g6$Z~PFvx}awQcy)by(A2j;>Xr6WHyBhJyfdKN7`!t! zq{pZ?$yU4fpRNw5GPup5+YU_j4dpj5;6Lnks6Mzep*!VA{SNwX`aicpq59xvf+qKm z`p+34`u}=QLG{7>hX&-2`VEZV^nY#}K=r|xh2{?!vm5n)3jb68KZGvyZ@@5v&iaoS s)lA?1=I5dfst+axbfA9JuRuWb|8;&C>(f*10{{f|l|XIrC+m~=KPH;OX#fBK From 13f8f64076ef7aad4998c187f296e4279410aa50 Mon Sep 17 00:00:00 2001 From: "cuneyt.ozdas" Date: Fri, 19 Sep 2025 23:12:31 -0700 Subject: [PATCH 5/5] - Try to use vfx 2025 latest container - Bump up recommended OpenEXR to 3.4.0 Signed-off-by: cuneyt.ozdas --- .github/workflows/ci_workflow.yml | 19 ++++++++++++++++--- .github/workflows/dependencies_latest.yml | 6 +++--- .github/workflows/platform_latest.yml | 6 +++--- share/cmake/modules/FindExtPackages.cmake | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index f76a61205..7b3e1d933 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -57,9 +57,9 @@ jobs: container: # DockerHub: https://hub.docker.com/u/aswf # Source: https://github.com/AcademySoftwareFoundation/aswf-docker - image: aswf/ci-ocio:${{ matrix.vfx-cy }}.1 + image: aswf/ci-ocio:${{ matrix.vfx-cy }} strategy: - fail-fast: true + fail-fast: false matrix: build: [7, 8, 9, 10, 11, 12, 13, 14, 15] include: @@ -207,6 +207,7 @@ jobs: - name: Configure run: | cmake ../. \ + -DOCIO_VERBOSE=ON \ -DCMAKE_INSTALL_PREFIX=../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ @@ -251,6 +252,7 @@ jobs: # the static version of the package. run: | cmake . \ + -DOCIO_VERBOSE=ON \ -DCMAKE_PREFIX_PATH=../../../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -Dexpat_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -297,7 +299,7 @@ jobs: - /node20217:/node20217:rw,rshared - /node20217:/__e/node20:ro,rshared strategy: - fail-fast: true + fail-fast: false matrix: build: [1, 2, 3] include: @@ -377,6 +379,7 @@ jobs: - name: Configure run: | cmake ../. \ + -DOCIO_VERBOSE=ON \ -DCMAKE_INSTALL_PREFIX=../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ @@ -421,6 +424,7 @@ jobs: # the static version of the package. run: | cmake . \ + -DOCIO_VERBOSE=ON \ -DCMAKE_PREFIX_PATH=../../../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -Dexpat_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -461,6 +465,7 @@ jobs: github.event.pull_request.head.repo.full_name != github.repository runs-on: macos-13 strategy: + fail-fast: false matrix: build: [1, 2, 3, 4, 5] include: @@ -534,6 +539,7 @@ jobs: - name: Configure run: | cmake ../. \ + -DOCIO_VERBOSE=ON \ -DCMAKE_INSTALL_PREFIX=../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ @@ -579,6 +585,7 @@ jobs: # the static version of the package. run: | cmake . \ + -DOCIO_VERBOSE=ON \ -DCMAKE_PREFIX_PATH=../../../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -Dexpat_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -616,6 +623,7 @@ jobs: runs-on: macos-14 strategy: + fail-fast: false matrix: build: [1, 2] include: @@ -660,6 +668,7 @@ jobs: - name: Configure run: | cmake ../. \ + -DOCIO_VERBOSE=ON \ -DCMAKE_INSTALL_PREFIX=../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ @@ -710,6 +719,7 @@ jobs: # the static version of the package. run: | cmake . \ + -DOCIO_VERBOSE=ON \ -DCMAKE_PREFIX_PATH=../../../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -Dexpat_ROOT=${{ env.ocio_build_path }}/ext/dist \ @@ -751,6 +761,7 @@ jobs: github.event.pull_request.head.repo.full_name != github.repository runs-on: windows-2022 strategy: + fail-fast: false matrix: build: [1, 2, 3, 4] include: @@ -816,6 +827,7 @@ jobs: - name: Configure run: | cmake ../. \ + -DOCIO_VERBOSE=ON \ -DCMAKE_INSTALL_PREFIX=../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \ @@ -865,6 +877,7 @@ jobs: # the static version of the package. run: | cmake . \ + -DOCIO_VERBOSE=ON \ -DCMAKE_PREFIX_PATH=../../../_install \ -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -Dexpat_ROOT=${{ env.ocio_build_path }}/ext/dist \ diff --git a/.github/workflows/dependencies_latest.yml b/.github/workflows/dependencies_latest.yml index 211e6f23b..ced7859f6 100644 --- a/.github/workflows/dependencies_latest.yml +++ b/.github/workflows/dependencies_latest.yml @@ -32,7 +32,7 @@ jobs: cxx=${{ matrix.cxx-standard }}, docs=${{ matrix.build-docs }}>' # Don't run on OCIO forks - if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' + # if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' # GH-hosted VM. The build runs in ASWF 'container' defined below. runs-on: ubuntu-latest container: @@ -159,7 +159,7 @@ jobs: docs=${{ matrix.build-docs }}, python=${{ matrix.python-version }}>' # Don't run on OCIO forks - if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' + # if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' runs-on: macos-latest strategy: matrix: @@ -256,7 +256,7 @@ jobs: docs=${{ matrix.build-docs }}, python=${{ matrix.python-version }}>' # Don't run on OCIO forks - if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' + # if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' runs-on: windows-latest strategy: matrix: diff --git a/.github/workflows/platform_latest.yml b/.github/workflows/platform_latest.yml index aa0be17dd..c6f1ab1c2 100644 --- a/.github/workflows/platform_latest.yml +++ b/.github/workflows/platform_latest.yml @@ -33,7 +33,7 @@ jobs: shared=${{ matrix.build-shared }}, cxx=${{ matrix.cxx-standard }}>' # Don't run on OCIO forks - if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' + # if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' runs-on: ubuntu-latest strategy: matrix: @@ -175,7 +175,7 @@ jobs: cxx=${{ matrix.cxx-standard }}, python=${{ matrix.python-version }}>' # Don't run on OCIO forks - if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' + # if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' runs-on: macos-latest strategy: matrix: @@ -288,7 +288,7 @@ jobs: cxx=${{ matrix.cxx-standard }}, python=${{ matrix.python-version }}>' # Don't run on OCIO forks - if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' + # if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' runs-on: windows-latest strategy: matrix: diff --git a/share/cmake/modules/FindExtPackages.cmake b/share/cmake/modules/FindExtPackages.cmake index 6353bdf5c..66c8fa5ff 100644 --- a/share/cmake/modules/FindExtPackages.cmake +++ b/share/cmake/modules/FindExtPackages.cmake @@ -259,7 +259,7 @@ if(OCIO_BUILD_APPS) # Calling find_package in CONFIG mode using PREFER_CONFIG option. ocio_handle_dependency( OpenEXR PREFER_CONFIG ALLOW_INSTALL MIN_VERSION 3.2.0 - RECOMMENDED_VERSION 3.3.5 + RECOMMENDED_VERSION 3.4 RECOMMENDED_VERSION_REASON "Latest version tested with OCIO" PROMOTE_TARGET OpenEXR::OpenEXR)