Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion include/OpenColorIO/OpenColorIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -2044,7 +2044,7 @@ class OCIOEXPORT ColorSpace
*
* 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
* not defined, it will 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
Expand Down Expand Up @@ -2407,6 +2407,22 @@ class OCIOEXPORT Look
const char * getDescription() const;
void setDescription(const char * description);

/**
* Get/Set the interchange attributes.
*
* Currently the only supported attribute name is "amf_transform_ids". Using
* any other name will throw. If the attribute is not defined, it will 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.
*/
const char *getInterchangeAttribute(const char *attrName) const;
void setInterchangeAttribute(const char* attrName, const char *value);
std::map<std::string, std::string> getInterchangeAttributes() const noexcept;

Look(const Look &) = delete;
Look& operator= (const Look &) = delete;
/// Do not use (needed only for pybind11).
Expand Down Expand Up @@ -2542,6 +2558,22 @@ class OCIOEXPORT ViewTransform
const char * getDescription() const noexcept;
void setDescription(const char * description);

/**
* Get/Set the interchange attributes.
*
* Currently the only supported attribute name is "amf_transform_ids". Using
* any other name will throw. If the attribute is not defined, it will 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.
*/
const char *getInterchangeAttribute(const char *attrName) const;
void setInterchangeAttribute(const char* attrName, const char *value);
std::map<std::string, std::string> getInterchangeAttributes() const noexcept;

/// \see ColorSpace::hasCategory
bool hasCategory(const char * category) const;
/// \see ColorSpace::addCategory
Expand Down
32 changes: 32 additions & 0 deletions src/OpenColorIO/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5904,6 +5904,38 @@ void Config::Impl::checkVersionConsistency() const
throw Exception("Only version 2 (or higher) can have ViewTransforms.");
}

// Check for new ViewTransform properties.

if (hexVersion < 0x02050000)
{
for (const auto& vt : m_viewTransforms)
{
if (vt->getInterchangeAttributes().size()>0)
{
std::ostringstream os;
os << "Config failed validation. The view transform '" << vt->getName() << "' ";
os << "has non-empty interchange attributes and config version is less than 2.5.";
throw Exception(os.str().c_str());
}
}
}

// Check for new Look properties.

if (hexVersion < 0x02050000)
{
for (const auto& look : m_looksList)
{
if (look->getInterchangeAttributes().size()>0)
{
std::ostringstream os;
os << "Config failed validation. The look '" << look->getName() << "' ";
os << "has non-empty interchange attributes and config version is less than 2.5.";
throw Exception(os.str().c_str());
}
}
}

// Check for the NamedTransforms.

if (m_majorVersion < 2 && m_allNamedTransforms.size() != 0)
Expand Down
71 changes: 71 additions & 0 deletions src/OpenColorIO/Look.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@
#include <OpenColorIO/OpenColorIO.h>

#include "ContextVariableUtils.h"
#include "utils/StringUtils.h"

namespace
{
const std::array<const std::string, 1> knownInterchangeNames = {
"amf_transform_ids" };
}

namespace OCIO_NAMESPACE
{
Expand All @@ -29,6 +35,7 @@ class Look::Impl
std::string m_name;
std::string m_processSpace;
std::string m_description;
std::map<std::string, std::string> m_interchangeAttribs;
TransformRcPtr m_transform;
TransformRcPtr m_inverseTransform;

Expand All @@ -48,6 +55,8 @@ class Look::Impl
m_processSpace = rhs.m_processSpace;
m_description = rhs.m_description;

m_interchangeAttribs = rhs.m_interchangeAttribs;

m_transform = rhs.m_transform?
rhs.m_transform->createEditableCopy() : rhs.m_transform;

Expand Down Expand Up @@ -129,6 +138,63 @@ void Look::setDescription(const char * description)
getImpl()->m_description = description ? description : "";
}

const char * Look::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 Look::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<std::string, std::string> Look::getInterchangeAttributes() const noexcept
{
return m_impl->m_interchangeAttribs;
}



bool CollectContextVariables(const Config & config,
const Context & context,
TransformDirection direction,
Expand Down Expand Up @@ -216,6 +282,11 @@ std::ostream& operator<< (std::ostream& os, const Look& look)
os << ", description=" << desc;
}

for (const auto& attr : look.getInterchangeAttributes())
{
os << ", " << attr.first << "=" << attr.second;
}

if(look.getTransform())
{
os << ",\n transform=";
Expand Down
112 changes: 73 additions & 39 deletions src/OpenColorIO/OCIOYaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,65 @@ inline void loadCustomKeys(const YAML::Node& node, CustomKeysLoader & ck, const
}
}

// Interchange Attributes

void saveInterchangeAttributes(
YAML::Emitter& out,
const std::map<std::string, std::string>& interchangemap)
{
if (interchangemap.empty())
return;

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;
}

template<class T>
void loadInterchangeAttributes(const YAML::Node& node, T& owner)
{
if (node.Type() != YAML::NodeType::Map)
{
std::ostringstream os;
os << "The 'interchange' content needs to be a map.";
throwError(node, os.str());
}

CustomKeysLoader kv;
loadCustomKeys(node, kv, "interchange");

for (const auto& keyval : kv.m_keyVals)
{
std::string keystr = keyval.first.as<std::string>();
std::string valstr = keyval.second.as<std::string>();
valstr = SanitizeNewlines(valstr);

// OCIO exception means the key is not recognized. Convert that to a warning.
try
{
owner->setInterchangeAttribute(keystr.c_str(), valstr.c_str());
}
catch (Exception &)
{
LogUnknownKeyWarning("interchange", keyval.first);
}
}
}


// View

inline void load(const YAML::Node& node, View& v)
Expand Down Expand Up @@ -3239,25 +3298,7 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major
}
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>();
std::string valstr = keyval.second.as<std::string>();
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);
}
}
loadInterchangeAttributes(iter->second, cs);
}
else if(key == "family")
{
Expand Down Expand Up @@ -3358,6 +3399,8 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major
}
}



inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int majorVersion)
{
out << YAML::VerbatimTag("ColorSpace");
Expand Down Expand Up @@ -3412,26 +3455,7 @@ 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;
}
saveInterchangeAttributes(out, cs->getInterchangeAttributes());

out << YAML::Key << "allocation" << YAML::Value;
save(out, cs->getAllocation());
Expand Down Expand Up @@ -3511,6 +3535,10 @@ inline void load(const YAML::Node& node, LookRcPtr& look)
loadDescription(iter->second, stringval);
look->setDescription(stringval.c_str());
}
else if(key == "interchange")
{
loadInterchangeAttributes(iter->second, look);
}
else
{
LogUnknownKeyWarning(node, iter->first);
Expand All @@ -3525,6 +3553,7 @@ inline void save(YAML::Emitter& out, ConstLookRcPtr look, unsigned int majorVers
out << YAML::Key << "name" << YAML::Value << look->getName();
out << YAML::Key << "process_space" << YAML::Value << look->getProcessSpace();
saveDescription(out, look->getDescription());
saveInterchangeAttributes(out, look->getInterchangeAttributes());

if(look->getTransform())
{
Expand Down Expand Up @@ -3627,6 +3656,10 @@ inline void load(const YAML::Node & node, ViewTransformRcPtr & vt)
loadDescription(iter->second, stringval);
vt->setDescription(stringval.c_str());
}
else if (key == "interchange")
{
loadInterchangeAttributes(iter->second, vt);
}
else if (key == "family")
{
std::string stringval;
Expand Down Expand Up @@ -3685,6 +3718,7 @@ inline void save(YAML::Emitter & out, ConstViewTransformRcPtr & vt, unsigned int
out << YAML::Key << "family" << YAML::Value << family;
}
saveDescription(out, vt->getDescription());
saveInterchangeAttributes(out, vt->getInterchangeAttributes());

if (vt->getNumCategories() > 0)
{
Expand Down
Loading