Skip to content

Commit a9d4575

Browse files
committed
- 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 <cuneyt.ozdas@autodesk.com>
1 parent cc15e51 commit a9d4575

4 files changed

Lines changed: 140 additions & 32 deletions

File tree

include/OpenColorIO/OpenColorIO.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,17 @@ class OCIOEXPORT Config
622622
*/
623623
ConstColorSpaceRcPtr getColorSpace(const char * name) const;
624624

625+
626+
enum InteropIDSearchMethod : uint8_t
627+
{
628+
FullID, ///< Search only for the full interop ID ([namespace:]colorspace);
629+
NameOnlyFallback ///< If fullID fails, will search for name only (colorspace).
630+
};
631+
/**
632+
* \brief Get the color space from the provided interopID.
633+
*/
634+
ConstColorSpaceRcPtr getColorSpaceFromInteropID(const char * interopID, InteropIDSearchMethod method=FullID) const;
635+
625636
/**
626637
* Accepts an alias, role name, named transform name, or color space name and returns the
627638
* color space name or the named transform name.

src/OpenColorIO/Config.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2497,6 +2497,27 @@ const char * Config::getCanonicalName(const char * name) const
24972497
return "";
24982498
}
24992499

2500+
ConstColorSpaceRcPtr Config::getColorSpaceFromInteropID(const char * interopID, InteropIDSearchMethod method) const
2501+
{
2502+
// TODO: this currently searches for roles as well. Do we want that? /coz
2503+
2504+
auto cs = getColorSpace(interopID);
2505+
2506+
// Fall back to name-only if allowed.
2507+
if(!cs && method == NameOnlyFallback)
2508+
{
2509+
std::string id(interopID);
2510+
size_t pos = id.find(':');
2511+
if(pos != std::string::npos)
2512+
{
2513+
std::string csname = id.substr(pos+1);
2514+
cs = getColorSpace(id.c_str());
2515+
}
2516+
}
2517+
2518+
return cs;
2519+
}
2520+
25002521
int Config::getNumColorSpaces() const
25012522
{
25022523
return getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ACTIVE);

src/apps/ociocheck/main.cpp

Lines changed: 100 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,103 @@ const char * DESC_STRING = "\n\n"
2727
"Ociocheck can also be used to clean up formatting on an existing profile\n"
2828
"that has been manually edited, using the '-o' option.\n";
2929

30+
31+
// returns true if the interopID is valid
32+
bool isValidInteropID(const std::string& id)
33+
{
34+
static const std::set<std::string> cifTextureIDs = {
35+
"lin_ap1_scene",
36+
"lin_ap0_scene",
37+
"lin_rec709_scene",
38+
"lin_p3d65_scene",
39+
"lin_rec2020_scene",
40+
"lin_adobergb_scene",
41+
"lin_ciexyzd65_scene",
42+
"srgb_rec709_scene",
43+
"g22_rec709_scene",
44+
"g18_rec709_scene",
45+
"srgb_ap1_scene",
46+
"g22_ap1_scene",
47+
"srgb_p3d65_scene",
48+
"g22_adobergb_scene",
49+
"data",
50+
"unknown"
51+
};
52+
53+
// empty is fine
54+
if (id.empty())
55+
return true;
56+
57+
// check if it only uses ASCII characters: 0-9, a-z, and the following characters (no spaces):
58+
// - _ ~ / * # % ^ + ( ) [ ] |
59+
auto allowed = [](char c)
60+
{
61+
return (c >= '0' && c <= '9') ||
62+
(c >= 'a' && c <= 'z') ||
63+
c=='-'||c=='_'||c=='~'||c=='/'||c=='*'||c=='#'||c=='%'||
64+
c=='^'||c=='+'||c=='('||c==')'||c=='['||c==']'||c=='|' || c==':';
65+
};
66+
67+
if (!std::all_of(id.begin(), id.end(), allowed))
68+
{
69+
std::cout << "ERROR: InteropID '" << id << "' contains invalid characters. "
70+
"Only lowercase a-z, 0-9 and - _ ~ / * # % ^ + ( ) [ ] | are allowed." <<
71+
std::endl;
72+
return false;
73+
}
74+
75+
// Check if has a namespace.
76+
size_t pos = id.find(':');
77+
if (pos == std::string::npos)
78+
{
79+
// No namespace, so id must be in the forumID list.
80+
if (cifTextureIDs.count(id) == 0)
81+
{
82+
std::cout << "ERROR: InteropID '" << id << "' is not valid. "
83+
"It should either be one of Color Interop Forum standard IDs or "
84+
"it must contain a namespace followed by ':', e.g. 'mycompany:mycolorspace'." <<
85+
std::endl;
86+
return false;
87+
}
88+
}
89+
else
90+
{
91+
// Namespace found, split into namespace and id.
92+
std::string ns = id.substr(0, pos);
93+
std::string cs = id.substr(pos+1);
94+
95+
// both should be non-empty
96+
if (ns.empty() || cs.empty())
97+
{
98+
std::cout << "ERROR: InteropID '" << id << "' is not valid. "
99+
"If a namespace is used, it must be followed by a non-empty ID, e.g. 'mycompany:mycolorspace'." <<
100+
std::endl;
101+
return false;
102+
}
103+
104+
// More than one ':' is an error.
105+
if (cs.find(':') != std::string::npos)
106+
{
107+
std::cout << "ERROR: InteropID '" << id << "' is not valid. "
108+
"Only one ':' is allowed to separate the namespace and ID, e.g. 'mycompany:mycolorspace'." <<
109+
std::endl;
110+
return false;
111+
}
112+
113+
// id should not be in the cifID list.
114+
if (cifTextureIDs.count(cs) > 0)
115+
{
116+
std::cout << "ERROR: InteropID '" << id << "' is not valid. "
117+
"The ID part must not be one of the Color Interop Forum standard IDs when a namespace is used." <<
118+
std::endl;
119+
return false;
120+
}
121+
}
122+
123+
// all clear.
124+
return true;
125+
}
126+
30127
int main(int argc, const char **argv)
31128
{
32129
bool help = false;
@@ -288,25 +385,7 @@ int main(int argc, const char **argv)
288385
std::cout << std::endl;
289386
std::cout << "** ColorSpaces **" << std::endl;
290387

291-
// Valid Color Interop Forum IDs
292-
std::set<std::string> validInteropIDs = {
293-
"lin_ap1_scene",
294-
"lin_ap0_scene",
295-
"lin_rec709_scene",
296-
"lin_p3d65_scene",
297-
"lin_rec2020_scene",
298-
"lin_adobergb_scene",
299-
"lin_ciexyzd65_scene",
300-
"srgb_rec709_scene",
301-
"g22_rec709_scene",
302-
"g18_rec709_scene",
303-
"srgb_ap1_scene",
304-
"g22_ap1_scene",
305-
"srgb_p3d65_scene",
306-
"g22_adobergb_scene",
307-
"data",
308-
"unknown"
309-
};
388+
310389

311390
const int numCS = config->getNumColorSpaces(
312391
OCIO::SEARCH_REFERENCE_SPACE_ALL, // Iterate over scene & display color spaces.
@@ -327,21 +406,10 @@ int main(int argc, const char **argv)
327406
std::string interopID = cs->getInteropID();
328407
if (!interopID.empty())
329408
{
330-
// Check if the interopID contains a colon
331-
if (interopID.find(':') == std::string::npos)
409+
if (!isValidInteropID(interopID))
332410
{
333-
// No colon found, check if it's a valid Color Interop Forum ID (case insensitive)
334-
std::string lowerInteropID = interopID;
335-
std::transform(lowerInteropID.begin(), lowerInteropID.end(), lowerInteropID.begin(), ::tolower);
336-
337-
if (validInteropIDs.find(lowerInteropID) == validInteropIDs.end())
338-
{
339-
std::cout << "WARNING: Color space '" << cs->getName()
340-
<< "' has unknown interop_id '" << interopID
341-
<< "'. Expected one of the Color Interop Forum standard IDs or a namespaced ID with ':'." << std::endl;
342-
}
411+
errorcount += 1;
343412
}
344-
// If it contains a colon, it's assumed to be a namespaced ID and is valid
345413
}
346414

347415
// Try to load the transform for the to_ref direction -- this will load any LUTs.

src/apps/ocioconvert/main.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,14 @@ int main(int argc, const char **argv)
658658
if (outputcolorspace)
659659
{
660660
imgOutput->attribute("oiio:ColorSpace", outputcolorspace);
661+
662+
// Set the color space interopID if available.
663+
auto cs = config->getColorSpace(outputcolorspace);
664+
const char* interopID = cs ? cs->getInteropID() : nullptr;
665+
if(interopID && *interopID)
666+
{
667+
imgOutput->attribute("colorInteropID", interopID);
668+
}
661669
}
662670

663671
imgOutput->write(outputimage, userOutputBitDepth);

0 commit comments

Comments
 (0)