Skip to content
Open
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
37 changes: 37 additions & 0 deletions include/OpenColorIO/OpenColorIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <fstream>
#include <vector>
#include <cstdint>
#include <map>

#include "OpenColorABI.h"
#include "OpenColorTypes.h"
Expand Down Expand Up @@ -1979,6 +1980,42 @@ 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). For more details, please review the interop ID
* white paper available from:
* https://github.com/AcademySoftwareFoundation/ColorInterop.
*/
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<std::string, std::string> getInterchangeAttributes() const noexcept;

BitDepth getBitDepth() const noexcept;
void setBitDepth(BitDepth bitDepth);

Expand Down
12 changes: 6 additions & 6 deletions src/OpenColorIO/Baker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.");
}
Expand Down
152 changes: 147 additions & 5 deletions src/OpenColorIO/ColorSpace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cstring>
#include <sstream>
#include <vector>
#include <map>

#include <OpenColorIO/OpenColorIO.h>

Expand All @@ -13,6 +14,13 @@
#include "utils/StringUtils.h"


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

namespace OCIO_NAMESPACE
{

Expand All @@ -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<std::string, std::string> m_interchangeAttribs;

BitDepth m_bitDepth{ BIT_DEPTH_UNKNOWN };
bool m_isData{ false };
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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<std::string, std::string> ColorSpace::getInterchangeAttributes() const noexcept
{
return m_impl->m_interchangeAttribs;
}

BitDepth ColorSpace::getBitDepth() const noexcept
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand All @@ -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 << ", ";
Expand Down Expand Up @@ -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";
Expand Down
Loading
Loading