Skip to content

Commit 7e7f2de

Browse files
authored
Adsk Contrib - Adding interchange attributes to ViewTransforms and Looks (#2194)
* Adding interchange attributes to ViewTransforms and Looks - Currently only the amf_transform_ids key is supported. That key is needed for ACES 2 built-in configs. Signed-off-by: cuneyt.ozdas <[email protected]> * Fixing the build by propagating the last minute wording change. Signed-off-by: cuneyt.ozdas <[email protected]> * - Fixing a bug in ViewTransform python tests - Removing the ColorSpace amf_transform_ids_serialization test as almost all of the cases are now exercised in the Config interchange_attributes test. - minor cleanup Signed-off-by: cuneyt.ozdas <[email protected]> --------- Signed-off-by: cuneyt.ozdas <[email protected]>
1 parent 92ab718 commit 7e7f2de

File tree

12 files changed

+508
-92
lines changed

12 files changed

+508
-92
lines changed

include/OpenColorIO/OpenColorIO.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2044,7 +2044,7 @@ class OCIOEXPORT ColorSpace
20442044
*
20452045
* Currently supported attribute names are "amf_transform_ids" and
20462046
* "icc_profile_name". Using any other name will throw. If the attribute is
2047-
* not defined, it'll return an empty string. Setting the value to an empty
2047+
* not defined, it will return an empty string. Setting the value to an empty
20482048
* string will effectively delete the attribute.
20492049
*
20502050
* The AMF transform IDs are used to identify specific transforms in the
@@ -2407,6 +2407,22 @@ class OCIOEXPORT Look
24072407
const char * getDescription() const;
24082408
void setDescription(const char * description);
24092409

2410+
/**
2411+
* Get/Set the interchange attributes.
2412+
*
2413+
* Currently the only supported attribute name is "amf_transform_ids". Using
2414+
* any other name will throw. If the attribute is not defined, it will return
2415+
* an empty string. Setting the value to an empty string will effectively
2416+
* delete the attribute.
2417+
*
2418+
* The AMF transform IDs are used to identify specific transforms in the ACES
2419+
* Metadata File. Multiple transform IDs can be specified in a
2420+
* newline-separated string.
2421+
*/
2422+
const char *getInterchangeAttribute(const char *attrName) const;
2423+
void setInterchangeAttribute(const char* attrName, const char *value);
2424+
std::map<std::string, std::string> getInterchangeAttributes() const noexcept;
2425+
24102426
Look(const Look &) = delete;
24112427
Look& operator= (const Look &) = delete;
24122428
/// Do not use (needed only for pybind11).
@@ -2542,6 +2558,22 @@ class OCIOEXPORT ViewTransform
25422558
const char * getDescription() const noexcept;
25432559
void setDescription(const char * description);
25442560

2561+
/**
2562+
* Get/Set the interchange attributes.
2563+
*
2564+
* Currently the only supported attribute name is "amf_transform_ids". Using
2565+
* any other name will throw. If the attribute is not defined, it will return
2566+
* an empty string. Setting the value to an empty string will effectively
2567+
* delete the attribute.
2568+
*
2569+
* The AMF transform IDs are used to identify specific transforms in the ACES
2570+
* Metadata File. Multiple transform IDs can be specified in a
2571+
* newline-separated string.
2572+
*/
2573+
const char *getInterchangeAttribute(const char *attrName) const;
2574+
void setInterchangeAttribute(const char* attrName, const char *value);
2575+
std::map<std::string, std::string> getInterchangeAttributes() const noexcept;
2576+
25452577
/// \see ColorSpace::hasCategory
25462578
bool hasCategory(const char * category) const;
25472579
/// \see ColorSpace::addCategory

src/OpenColorIO/Config.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5904,6 +5904,38 @@ void Config::Impl::checkVersionConsistency() const
59045904
throw Exception("Only version 2 (or higher) can have ViewTransforms.");
59055905
}
59065906

5907+
// Check for new ViewTransform properties.
5908+
5909+
if (hexVersion < 0x02050000)
5910+
{
5911+
for (const auto& vt : m_viewTransforms)
5912+
{
5913+
if (vt->getInterchangeAttributes().size()>0)
5914+
{
5915+
std::ostringstream os;
5916+
os << "Config failed validation. The view transform '" << vt->getName() << "' ";
5917+
os << "has non-empty interchange attributes and config version is less than 2.5.";
5918+
throw Exception(os.str().c_str());
5919+
}
5920+
}
5921+
}
5922+
5923+
// Check for new Look properties.
5924+
5925+
if (hexVersion < 0x02050000)
5926+
{
5927+
for (const auto& look : m_looksList)
5928+
{
5929+
if (look->getInterchangeAttributes().size()>0)
5930+
{
5931+
std::ostringstream os;
5932+
os << "Config failed validation. The look '" << look->getName() << "' ";
5933+
os << "has non-empty interchange attributes and config version is less than 2.5.";
5934+
throw Exception(os.str().c_str());
5935+
}
5936+
}
5937+
}
5938+
59075939
// Check for the NamedTransforms.
59085940

59095941
if (m_majorVersion < 2 && m_allNamedTransforms.size() != 0)

src/OpenColorIO/Look.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@
99
#include <OpenColorIO/OpenColorIO.h>
1010

1111
#include "ContextVariableUtils.h"
12+
#include "utils/StringUtils.h"
1213

14+
namespace
15+
{
16+
const std::array<const std::string, 1> knownInterchangeNames = {
17+
"amf_transform_ids" };
18+
}
1319

1420
namespace OCIO_NAMESPACE
1521
{
@@ -29,6 +35,7 @@ class Look::Impl
2935
std::string m_name;
3036
std::string m_processSpace;
3137
std::string m_description;
38+
std::map<std::string, std::string> m_interchangeAttribs;
3239
TransformRcPtr m_transform;
3340
TransformRcPtr m_inverseTransform;
3441

@@ -48,6 +55,8 @@ class Look::Impl
4855
m_processSpace = rhs.m_processSpace;
4956
m_description = rhs.m_description;
5057

58+
m_interchangeAttribs = rhs.m_interchangeAttribs;
59+
5160
m_transform = rhs.m_transform?
5261
rhs.m_transform->createEditableCopy() : rhs.m_transform;
5362

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

141+
const char * Look::getInterchangeAttribute(const char* attrName) const
142+
{
143+
std::string name = attrName ? attrName : "";
144+
145+
for (auto& key : knownInterchangeNames)
146+
{
147+
// do case-insensitive comparison.
148+
if (StringUtils::Compare(key, name))
149+
{
150+
auto it = m_impl->m_interchangeAttribs.find(key);
151+
if (it != m_impl->m_interchangeAttribs.end())
152+
{
153+
return it->second.c_str();
154+
}
155+
return "";
156+
}
157+
}
158+
159+
std::ostringstream oss;
160+
oss << "Unknown attribute name '" << name << "'.";
161+
throw Exception(oss.str().c_str());
162+
}
163+
164+
void Look::setInterchangeAttribute(const char* attrName, const char* value)
165+
{
166+
std::string name = attrName ? attrName : "";
167+
168+
for (auto& key : knownInterchangeNames)
169+
{
170+
// Do case-insensitive comparison.
171+
if (StringUtils::Compare(key, name))
172+
{
173+
// Use key instead of name for storing in correct capitalization.
174+
if (!value || !*value)
175+
{
176+
m_impl->m_interchangeAttribs.erase(key);
177+
}
178+
else
179+
{
180+
m_impl->m_interchangeAttribs[key] = value;
181+
}
182+
return;
183+
}
184+
}
185+
186+
std::ostringstream oss;
187+
oss << "Unknown attribute name '" << name << "'.";
188+
throw Exception(oss.str().c_str());
189+
}
190+
191+
std::map<std::string, std::string> Look::getInterchangeAttributes() const noexcept
192+
{
193+
return m_impl->m_interchangeAttribs;
194+
}
195+
196+
197+
132198
bool CollectContextVariables(const Config & config,
133199
const Context & context,
134200
TransformDirection direction,
@@ -216,6 +282,11 @@ std::ostream& operator<< (std::ostream& os, const Look& look)
216282
os << ", description=" << desc;
217283
}
218284

285+
for (const auto& attr : look.getInterchangeAttributes())
286+
{
287+
os << ", " << attr.first << "=" << attr.second;
288+
}
289+
219290
if(look.getTransform())
220291
{
221292
os << ",\n transform=";

src/OpenColorIO/OCIOYaml.cpp

Lines changed: 73 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,65 @@ inline void loadCustomKeys(const YAML::Node& node, CustomKeysLoader & ck, const
344344
}
345345
}
346346

347+
// Interchange Attributes
348+
349+
void saveInterchangeAttributes(
350+
YAML::Emitter& out,
351+
const std::map<std::string, std::string>& interchangemap)
352+
{
353+
if (interchangemap.empty())
354+
return;
355+
356+
out << YAML::Key << "interchange";
357+
out << YAML::Value;
358+
out << YAML::BeginMap;
359+
for (const auto& keyval : interchangemap)
360+
{
361+
std::string valStr = SanitizeNewlines(keyval.second);
362+
363+
out << YAML::Key << keyval.first << YAML::Value;
364+
if (valStr.find_first_of('\n') != std::string::npos)
365+
{
366+
out << YAML::Literal;
367+
}
368+
out << valStr;
369+
}
370+
371+
out << YAML::EndMap;
372+
}
373+
374+
template<class T>
375+
void loadInterchangeAttributes(const YAML::Node& node, T& owner)
376+
{
377+
if (node.Type() != YAML::NodeType::Map)
378+
{
379+
std::ostringstream os;
380+
os << "The 'interchange' content needs to be a map.";
381+
throwError(node, os.str());
382+
}
383+
384+
CustomKeysLoader kv;
385+
loadCustomKeys(node, kv, "interchange");
386+
387+
for (const auto& keyval : kv.m_keyVals)
388+
{
389+
std::string keystr = keyval.first.as<std::string>();
390+
std::string valstr = keyval.second.as<std::string>();
391+
valstr = SanitizeNewlines(valstr);
392+
393+
// OCIO exception means the key is not recognized. Convert that to a warning.
394+
try
395+
{
396+
owner->setInterchangeAttribute(keystr.c_str(), valstr.c_str());
397+
}
398+
catch (Exception &)
399+
{
400+
LogUnknownKeyWarning("interchange", keyval.first);
401+
}
402+
}
403+
}
404+
405+
347406
// View
348407

349408
inline void load(const YAML::Node& node, View& v)
@@ -3239,25 +3298,7 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major
32393298
}
32403299
else if (key == "interchange")
32413300
{
3242-
CustomKeysLoader kv;
3243-
loadCustomKeys(iter->second, kv, "ColorSpace interchange");
3244-
3245-
for (const auto& keyval : kv.m_keyVals)
3246-
{
3247-
std::string keystr = keyval.first.as<std::string>();
3248-
std::string valstr = keyval.second.as<std::string>();
3249-
valstr = SanitizeNewlines(valstr);
3250-
3251-
// OCIO exception means the key is not recognized. Convert that to a warning.
3252-
try
3253-
{
3254-
cs->setInterchangeAttribute(keystr.c_str(), valstr.c_str());
3255-
}
3256-
catch (Exception &)
3257-
{
3258-
LogUnknownKeyWarning(key, keyval.first);
3259-
}
3260-
}
3301+
loadInterchangeAttributes(iter->second, cs);
32613302
}
32623303
else if(key == "family")
32633304
{
@@ -3358,6 +3399,8 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs, unsigned int major
33583399
}
33593400
}
33603401

3402+
3403+
33613404
inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int majorVersion)
33623405
{
33633406
out << YAML::VerbatimTag("ColorSpace");
@@ -3412,26 +3455,7 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int major
34123455
out << YAML::Value << is;
34133456
}
34143457

3415-
auto interchangemap = cs->getInterchangeAttributes();
3416-
if (interchangemap.size())
3417-
{
3418-
out << YAML::Key << "interchange";
3419-
out << YAML::Value;
3420-
out << YAML::BeginMap;
3421-
for (const auto& keyval : interchangemap)
3422-
{
3423-
std::string valStr = SanitizeNewlines(keyval.second);
3424-
3425-
out << YAML::Key << keyval.first << YAML::Value;
3426-
if (valStr.find_first_of('\n') != std::string::npos)
3427-
{
3428-
out << YAML::Literal;
3429-
}
3430-
out << valStr;
3431-
}
3432-
3433-
out << YAML::EndMap;
3434-
}
3458+
saveInterchangeAttributes(out, cs->getInterchangeAttributes());
34353459

34363460
out << YAML::Key << "allocation" << YAML::Value;
34373461
save(out, cs->getAllocation());
@@ -3511,6 +3535,10 @@ inline void load(const YAML::Node& node, LookRcPtr& look)
35113535
loadDescription(iter->second, stringval);
35123536
look->setDescription(stringval.c_str());
35133537
}
3538+
else if(key == "interchange")
3539+
{
3540+
loadInterchangeAttributes(iter->second, look);
3541+
}
35143542
else
35153543
{
35163544
LogUnknownKeyWarning(node, iter->first);
@@ -3525,6 +3553,7 @@ inline void save(YAML::Emitter& out, ConstLookRcPtr look, unsigned int majorVers
35253553
out << YAML::Key << "name" << YAML::Value << look->getName();
35263554
out << YAML::Key << "process_space" << YAML::Value << look->getProcessSpace();
35273555
saveDescription(out, look->getDescription());
3556+
saveInterchangeAttributes(out, look->getInterchangeAttributes());
35283557

35293558
if(look->getTransform())
35303559
{
@@ -3627,6 +3656,10 @@ inline void load(const YAML::Node & node, ViewTransformRcPtr & vt)
36273656
loadDescription(iter->second, stringval);
36283657
vt->setDescription(stringval.c_str());
36293658
}
3659+
else if (key == "interchange")
3660+
{
3661+
loadInterchangeAttributes(iter->second, vt);
3662+
}
36303663
else if (key == "family")
36313664
{
36323665
std::string stringval;
@@ -3685,6 +3718,7 @@ inline void save(YAML::Emitter & out, ConstViewTransformRcPtr & vt, unsigned int
36853718
out << YAML::Key << "family" << YAML::Value << family;
36863719
}
36873720
saveDescription(out, vt->getDescription());
3721+
saveInterchangeAttributes(out, vt->getInterchangeAttributes());
36883722

36893723
if (vt->getNumCategories() > 0)
36903724
{

0 commit comments

Comments
 (0)