Compare commits

...
11 Commits
Author SHA1 Message Date
Cédrik Fuoco d4435d33e7 Adsk contrib - Remove dev suffix from RB-2.0 (#1652)
* Removing dev suffix in RB-2.0

Signed-off-by: Cedrik Fuoco <cedrik.fuoco@autodesk.com>

* Keep the line but make it empty instead

Signed-off-by: Cedrik Fuoco <cedrik.fuoco@autodesk.com>
2022-06-01 20:35:08 -04:00
Patrick HodoulandDoug Walker 73229d885d Adsk Contrib - Fix half-domain Lut1D issue for values above HALF_MAX (#1614) (#1625)
* Fix half-domain Lut1D issue for values above HALF_MAX

Signed-off-by: Doug Walker <doug.walker@autodesk.com>

* Address review comments

Signed-off-by: Doug Walker <doug.walker@autodesk.com>

Co-authored-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: Doug Walker <doug.walker@autodesk.com>
2022-04-06 10:12:35 -04:00
Patrick HodoulandRémi Achard 2983316028 Port from main to RB-2.0 - Python copy support (#1575) (#1612)
* Python copy support (#1575)

* Add deepcopy support for object with createEditableCopy method

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Minor fixes

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Removing python shallow copy method

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Update comment and formating

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Testing COnfig FileRules deepCopy

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Add comment for ConfigTest

Signed-off-by: Rémi Achard <remiachard@gmail.com>

Co-authored-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Unit test fix

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: Rémi Achard <remiachard@gmail.com>
2022-03-11 09:04:52 -05:00
Patrick HodoulandMichael Dolan f74c1b88a9 Port from main to RB-2.0 - Add virtual display python bindings (#1464) (#1611)
* Add virtual display python bindings (#1464)

* Add virtual display python bindings

Signed-off-by: Michael Dolan <michdolan@gmail.com>

* Add virtual display test, missing methods

Signed-off-by: Michael Dolan <michdolan@gmail.com>

* Fix the Config Python binding

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: Michael Dolan <michdolan@gmail.com>
2022-03-11 08:15:41 -05:00
Patrick Hodoul 14f13c8b4e Open the 2.0.4 patch release (#1570)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-12-17 08:49:21 -05:00
Patrick Hodoul 8fed1b3bc6 Prepare the 2.0.3 patch release (#1560)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-12-14 12:10:33 -05:00
52faf7449c Adsk Contrib - Fix RGB spline curve inversion when the slope is zero (#1539) (#1554)
* Fix RGBCurve inverse when slope=0

Signed-off-by: Doug Walker <Doug.Walker@autodesk.com>

* Add GPU fix and test

Signed-off-by: Doug Walker <Doug.Walker@autodesk.com>

* Tweak var name

Signed-off-by: Doug Walker <Doug.Walker@autodesk.com>

Co-authored-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: doug-walker <43830961+doug-walker@users.noreply.github.com>
2021-12-12 09:11:47 -05:00
Patrick Hodoul e1b3ffecdd Adsk Contrib - Fix some weaknesses in the search path validation (#1535) (#1552)
* Adsk Contrib - Fix some weaknesses in the search path validation

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix the Windows path in the unit test validations

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix the Windows path in the unit test validations, part II

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-12-10 15:37:15 -05:00
Patrick HodoulandBo Zhou a8626f8b45 Write converted image with output colorspace (#1420) (#1500) (#1531)
* Write converted image with output colorspace (#1420)

Signed-off-by: Bo Zhou <Bo.Schwarzstein@gmail.com>

* Check if outputcolorspace is null and set it as oiio:ColorSpace (#1460)

Signed-off-by: Bo Zhou <Bo.Schwarzstein@gmail.com>

* Call getDisplayViewColorSpaceName to get output colorspace for view mode. #1420

Signed-off-by: Bo Zhou <Bo.Schwarzstein@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: Bo Zhou <bo.schwarzstein@gmail.com>
2021-11-03 16:30:56 -04:00
Patrick Hodoul df74525ef9 Adsk Contrib - Fix the CDL write for CLF file format (#1526) (#1530)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-11-03 07:53:49 -04:00
Patrick Hodoul 9b619d837a Adsk Contrib - Change RB-2.0 branch to the version '2.0.3dev' (#1480)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-09-16 08:46:02 -04:00
32 changed files with 939 additions and 82 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ endif()
# Project definition.
project(OpenColorIO
VERSION 2.0.2
VERSION 2.0.4
DESCRIPTION "OpenColorIO (OCIO) is a complete color management solution"
HOMEPAGE_URL https://github.com/AcademySoftwareFoundation/OpenColorIO
LANGUAGES CXX C)
+22 -24
View File
@@ -1328,30 +1328,28 @@ extern OCIOEXPORT std::ostream & operator<< (std::ostream &, const FileRules &);
// TODO: Move to .rst
//
// ViewingRules
// ************
// Viewing Rules allow config authors to filter the list of views an application should offer
// based on the color space of an image. For example, a config may define a large number of
// views but not all of them may be appropriate for use with all color spaces. E.g., some views
// may be intended for use with scene-linear color space encodings and others with video color
// space encodings.
//
// Each rule has a name key for applications to refer to the rule. Name values must be unique
// (using case insensitive comparison). Viewing Rules may also have the following keys:
//
// * colorspaces: Either a single colorspace name or a list of names.
//
// * encodings: One or more strings to be found in the colorspace's encoding attribute.
// Either this attribute or colorspaces must be present, but not both.
//
// * custom : Allows arbitrary key / value string pairs, similar to FileRules.
//
// Getters and setters are using the rule position, they will throw if the position is not
// valid.
/**
* ViewingRules
*
* Viewing Rules allow config authors to filter the list of views an application should offer
* based on the color space of an image. For example, a config may define a large number of
* views but not all of them may be appropriate for use with all color spaces. E.g., some views
* may be intended for use with scene-linear color space encodings and others with video color
* space encodings.
*
* Each rule has a name key for applications to refer to the rule. Name values must be unique
* (using case insensitive comparison). Viewing Rules may also have the following keys:
*
* * colorspaces: Either a single colorspace name or a list of names.
*
* * encodings: One or more strings to be found in the colorspace's encoding attribute.
* Either this attribute or colorspaces must be present, but not both.
*
* * custom : Allows arbitrary key / value string pairs, similar to FileRules.
*
* Getters and setters are using the rule position, they will throw if the position is not
* valid.
*/
class OCIOEXPORT ViewingRules
{
public:
+3 -4
View File
@@ -1737,7 +1737,7 @@ void Config::validate() const
if (!path || !*path)
{
errMsg += " The search_path is empty.";
break;
continue;
}
const std::string resolvedSearchPath = getImpl()->m_context->resolveStringVar(path);
@@ -1755,17 +1755,16 @@ void Config::validate() const
}
oss << ".";
errMsg += oss.str();
break;
continue;
}
foundOne = true;
}
// After looping over all the search paths, none of them can be successfully resolved.
if (!foundOne)
{
// No valid paths were found.
getImpl()->m_validationtext = errMsg;
throw Exception(errMsg.c_str());
}
@@ -838,17 +838,17 @@ void CDLWriter::writeContent() const
oss.str("");
params = m_cdl->getSlopeParams();
oss << params[0] << ", " << params[1] << ", " << params[2];
oss << params[0] << " " << params[1] << " " << params[2];
m_formatter.writeContentTag(TAG_SLOPE, oss.str());
oss.str("");
params = m_cdl->getOffsetParams();
oss << params[0] << ", " << params[1] << ", " << params[2];
oss << params[0] << " " << params[1] << " " << params[2];
m_formatter.writeContentTag(TAG_OFFSET, oss.str());
oss.str("");
params = m_cdl->getPowerParams();
oss << params[0] << ", " << params[1] << ", " << params[2];
oss << params[0] << " " << params[1] << " " << params[2];
m_formatter.writeContentTag(TAG_POWER, oss.str());
}
m_formatter.writeEndTag(TAG_SOPNODE);
@@ -192,7 +192,7 @@ void EstimateSlopes(const std::vector<GradingControlPoint> & ctrlPnts, std::vect
{
size_t j = i;
float DL = secantLen[i];
while ((j < numCtrlPnts - 2) && (fabs(secantSlope[j + 1] - secantSlope[j]) < 1e-6f))
while ((j < numCtrlPnts - 2) && (std::fabs(secantSlope[j + 1] - secantSlope[j]) < 1e-6f))
{
DL += secantLen[j + 1];
j++;
@@ -255,7 +255,7 @@ void FitSpline(const std::vector<GradingControlPoint> & ctrlPnts,
}
else
{
if (fabs(aa) > fabs(bb))
if (std::fabs(aa) > std::fabs(bb))
{
ksi = xi_pl1 + aa * del_x / (slopes[i + 1] - slopes[i]);
}
@@ -471,7 +471,7 @@ void GradingBSplineCurveImpl::AddShaderEval(GpuShaderText & st,
st.newLine() << "{";
st.newLine() << " float B = " << coefs << "[coefsOffs + coefsSets];";
st.newLine() << " float C = " << coefs << "[coefsOffs + coefsSets * 2];";
st.newLine() << " return (x - C) / B + knStart;";
st.newLine() << " return abs(B) < 1e-5 ? knStart : (x - C) / B + knStart;";
st.newLine() << "}";
st.newLine() << "else if (x >= knEndY)";
@@ -483,7 +483,7 @@ void GradingBSplineCurveImpl::AddShaderEval(GpuShaderText & st,
st.newLine() << " float t = knEnd - kn;";
st.newLine() << " float slope = 2. * A * t + B;";
st.newLine() << " float offs = ( A * t + B ) * t + C;";
st.newLine() << " return (x - offs) / slope + knEnd;";
st.newLine() << " return abs(slope) < 1e-5 ? knEnd : (x - offs) / slope + knEnd;";
st.newLine() << "}";
// else
@@ -580,7 +580,7 @@ float GradingBSplineCurveImpl::KnotsCoefs::evalCurveRev(int c, float y) const
{
const float B = m_coefsArray[coefsOffs + coefsSets];
const float C = m_coefsArray[coefsOffs + coefsSets * 2];
return (y - C) / B + knStart;
return std::fabs(B) < 1e-5f ? knStart : (y - C) / B + knStart;
}
else if (y >= knEndY)
{
@@ -591,7 +591,7 @@ float GradingBSplineCurveImpl::KnotsCoefs::evalCurveRev(int c, float y) const
const float t = knEnd - kn;
const float slope = 2.f * A * t + B;
const float offs = (A * t + B) * t + C;
return (y - offs) / slope + knEnd;
return std::fabs(slope) < 1e-5f ? knEnd : (y - offs) / slope + knEnd;
}
else
{
+3 -1
View File
@@ -534,7 +534,7 @@ IndexPair IndexPair::GetEdgeFloatValues(float fIn)
const float floatTemp = (float) halfVal;
// Strict comparison required otherwise negative fractions will occur.
if (fabs(floatTemp)> fabs(fIn))
if (fabs(floatTemp) > fabs(fIn))
{
idxPair.valB = halfVal.bits();
idxPair.valA = idxPair.valB;
@@ -551,6 +551,8 @@ IndexPair IndexPair::GetEdgeFloatValues(float fIn)
{
halfVal = halfVal.isNegative () ? -HALF_MAX : HALF_MAX;
idxPair.valB = halfVal.bits();
// Necessary to reset fIn too (consider fIn = 65519, it's > HALF_MAX but not Inf).
fIn = halfVal;
}
}
+11
View File
@@ -616,6 +616,17 @@ int main(int argc, const char **argv)
exit(1);
}
if (useDisplayView)
{
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
outputcolorspace = config->getDisplayViewColorSpaceName(display, view);
}
if (outputcolorspace)
{
spec.attribute("oiio:ColorSpace", outputcolorspace);
}
f->open(outputimage, spec);
if(!f->write_image(spec.format, img.getBuffer()))
+6
View File
@@ -72,6 +72,12 @@ Each item is a tuple containing format name and format extension.
"shaperSize"_a = DEFAULT->getShaperSize(),
DOC(Baker, Create))
.def("__deepcopy__", [](const ConstBakerRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def_static("getFormats", []()
{
return FormatIterator(nullptr);
+6
View File
@@ -152,6 +152,12 @@ void bindPyColorSpace(py::module & m)
"categories"_a = getCategoriesStdVec(DEFAULT),
DOC(ColorSpace, Create, 2))
.def("__deepcopy__", [](const ConstColorSpaceRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("getName", &ColorSpace::getName,
DOC(ColorSpace, getName))
.def("setName", &ColorSpace::setName, "name"_a.none(false),
+6
View File
@@ -40,6 +40,12 @@ void bindPyColorSpaceSet(py::module & m)
.def(py::init(&ColorSpaceSet::Create),
DOC(ColorSpaceSet, Create))
.def("__deepcopy__", [](const ConstColorSpaceSetRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("__eq__", &ColorSpaceSet::operator==, py::is_operator(),
DOC(ColorSpaceSet, operator, eq))
.def("__ne__", &ColorSpaceSet::operator!=, py::is_operator(),
+151 -4
View File
@@ -33,7 +33,10 @@ enum ConfigIterator
IT_NAMED_TRANSFORM_NAME,
IT_NAMED_TRANSFORM,
IT_ACTIVE_NAMED_TRANSFORM_NAME,
IT_ACTIVE_NAMED_TRANSFORM
IT_ACTIVE_NAMED_TRANSFORM,
IT_DISPLAY_ALL,
IT_DISPLAY_VIEW_TYPE,
IT_VIRTUAL_DISPLAY_VIEW,
};
using EnvironmentVarNameIterator = PyIterator<ConfigRcPtr, IT_ENVIRONMENT_VAR_NAME>;
@@ -45,16 +48,21 @@ using ColorSpaceNameIterator = PyIterator<ConfigRcPtr,
using ColorSpaceIterator = PyIterator<ConfigRcPtr,
IT_COLOR_SPACE,
SearchReferenceSpaceType,
ColorSpaceVisibility>;
ColorSpaceVisibility>;
using ActiveColorSpaceNameIterator = PyIterator<ConfigRcPtr, IT_ACTIVE_COLOR_SPACE_NAME>;
using ActiveColorSpaceIterator = PyIterator<ConfigRcPtr, IT_ACTIVE_COLOR_SPACE>;
using RoleNameIterator = PyIterator<ConfigRcPtr, IT_ROLE_NAME>;
using RoleColorSpaceIterator = PyIterator<ConfigRcPtr, IT_ROLE_COLOR_SPACE>;
using DisplayIterator = PyIterator<ConfigRcPtr, IT_DISPLAY>;
using DisplayAllIterator = PyIterator<ConfigRcPtr, IT_DISPLAY_ALL>;
using SharedViewIterator = PyIterator<ConfigRcPtr, IT_SHARED_VIEW>;
using VirtualViewIterator = PyIterator<ConfigRcPtr, IT_VIRTUAL_DISPLAY_VIEW,
ViewType>;
using ViewIterator = PyIterator<ConfigRcPtr, IT_DISPLAY_VIEW, std::string>;
using ViewForColorSpaceIterator = PyIterator<ConfigRcPtr, IT_DISPLAY_VIEW_COLORSPACE,
std::string, std::string>;
using ViewForViewTypeIterator = PyIterator<ConfigRcPtr, IT_DISPLAY_VIEW_TYPE,
ViewType, std::string>;
using LookNameIterator = PyIterator<ConfigRcPtr, IT_LOOK_NAME>;
using LookIterator = PyIterator<ConfigRcPtr, IT_LOOK>;
using ViewTransformNameIterator = PyIterator<ConfigRcPtr, IT_VIEW_TRANSFORM_NAME>;
@@ -110,10 +118,18 @@ void bindPyConfig(py::module & m)
py::class_<DisplayIterator>(
clsConfig, "DisplayIterator");
auto clsDisplayAllIterator =
py::class_<DisplayAllIterator>(
clsConfig, "DisplayAllIterator");
auto clsSharedViewIterator =
py::class_<SharedViewIterator>(
clsConfig, "SharedViewIterator");
auto clsVirtualViewIterator =
py::class_<VirtualViewIterator>(
clsConfig, "VirtualViewIterator");
auto clsViewIterator =
py::class_<ViewIterator>(
clsConfig, "ViewIterator");
@@ -122,6 +138,10 @@ void bindPyConfig(py::module & m)
py::class_<ViewForColorSpaceIterator>(
clsConfig, "ViewForColorSpaceIterator");
auto clsViewForViewTypeIterator =
py::class_<ViewForViewTypeIterator>(
clsConfig, "ViewForViewTypeIterator");
auto clsLookNameIterator =
py::class_<LookNameIterator>(
clsConfig, "LookNameIterator");
@@ -158,6 +178,12 @@ void bindPyConfig(py::module & m)
.def(py::init(&Config::Create),
DOC(Config, Create))
.def("__deepcopy__", [](const ConstConfigRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def_static("CreateRaw", &Config::CreateRaw,
DOC(Config, CreateRaw))
.def_static("CreateFromEnv", &Config::CreateFromEnv,
@@ -342,13 +368,24 @@ void bindPyConfig(py::module & m)
{
return DisplayIterator(self);
})
.def("getDefaultView", &Config::getDefaultView, "display"_a,
.def("getDisplaysAll", [](ConfigRcPtr & self)
{
return DisplayAllIterator(self);
})
.def("getDefaultView",
(const char * (Config::*)(const char *) const)
&Config::getDefaultView, "display"_a,
DOC(Config, getDefaultView))
.def("getViews", [](ConfigRcPtr & self, const std::string & display)
{
return ViewIterator(self, display);
},
"display"_a)
.def("getViews", [](ConfigRcPtr & self, ViewType type, const std::string & display)
{
return ViewForViewTypeIterator(self, type, display);
},
"type"_a, "display"_a)
.def("getViews", [](ConfigRcPtr & self,
const std::string & display,
const std::string & colorSpaceName)
@@ -394,6 +431,59 @@ void bindPyConfig(py::module & m)
DOC(Config, removeDisplayView))
.def("clearDisplays", &Config::clearDisplays,
DOC(Config, clearDisplays))
// Virtual Display
.def("addVirtualDisplayView", &Config::addVirtualDisplayView,
"view"_a, "viewTransformName"_a, "colorSpaceName"_a,
"looks"_a = "",
"ruleName"_a = "",
"description"_a = "",
DOC(Config, addVirtualDisplayView))
.def("addVirtualDisplaySharedView", &Config::addVirtualDisplaySharedView, "sharedView"_a,
DOC(Config, addVirtualDisplaySharedView))
.def("getVirtualDisplayViews", [](ConfigRcPtr & self, ViewType type)
{
return VirtualViewIterator(self, type);
},
"display"_a)
.def("getVirtualDisplayViewTransformName", &Config::getVirtualDisplayViewTransformName,
"view"_a,
DOC(Config, getVirtualDisplayViewTransformName))
.def("getVirtualDisplayViewColorSpaceName", &Config::getVirtualDisplayViewColorSpaceName,
"view"_a,
DOC(Config, getVirtualDisplayViewColorSpaceName))
.def("getVirtualDisplayViewLooks", &Config::getVirtualDisplayViewLooks, "view"_a,
DOC(Config, getVirtualDisplayViewLooks))
.def("getVirtualDisplayViewRule", &Config::getVirtualDisplayViewRule, "view"_a,
DOC(Config, getVirtualDisplayViewRule))
.def("getVirtualDisplayViewDescription", &Config::getVirtualDisplayViewDescription,
"view"_a,
DOC(Config, getVirtualDisplayViewDescription))
.def("removeVirtualDisplayView", &Config::removeVirtualDisplayView, "view"_a,
DOC(Config, removeVirtualDisplayView))
.def("clearVirtualDisplay", &Config::clearVirtualDisplay,
DOC(Config, clearVirtualDisplay))
.def("instantiateDisplayFromMonitorName", &Config::instantiateDisplayFromMonitorName,
"monitorName"_a,
DOC(Config, instantiateDisplayFromMonitorName))
.def("instantiateDisplayFromICCProfile", &Config::instantiateDisplayFromICCProfile,
"ICCProfileFilepath"_a,
DOC(Config, instantiateDisplayFromICCProfile))
.def("isDisplayTemporary", [](ConfigRcPtr & self, const std::string & display) -> bool
{
for (int i = 0; i < self->getNumDisplaysAll(); i++)
{
std::string other(self->getDisplayAll(i));
if (StringUtils::Compare(display, other))
{
return self->isDisplayTemporary(i);
}
}
return false;
},
"display"_a)
// Active Displays and Views
.def("setActiveDisplays", &Config::setActiveDisplays, "displays"_a,
DOC(Config, setActiveDisplays))
.def("getActiveDisplays", &Config::getActiveDisplays,
@@ -844,6 +934,20 @@ void bindPyConfig(py::module & m)
return it.m_obj->getDisplay(i);
});
clsDisplayAllIterator
.def("__len__", [](DisplayAllIterator & it) { return it.m_obj->getNumDisplaysAll(); })
.def("__getitem__", [](DisplayAllIterator & it, int i)
{
it.checkIndex(i, it.m_obj->getNumDisplaysAll());
return it.m_obj->getDisplayAll(i);
})
.def("__iter__", [](DisplayAllIterator & it) -> DisplayAllIterator & { return it; })
.def("__next__", [](DisplayAllIterator & it)
{
int i = it.nextIndex(it.m_obj->getNumDisplaysAll());
return it.m_obj->getDisplayAll(i);
});
clsSharedViewIterator
.def("__len__", [](SharedViewIterator & it) { return it.m_obj->getNumViews(VIEW_SHARED,
nullptr); })
@@ -859,6 +963,23 @@ void bindPyConfig(py::module & m)
return it.m_obj->getView(VIEW_SHARED, nullptr, i);
});
clsVirtualViewIterator
.def("__len__", [](VirtualViewIterator & it)
{
return it.m_obj->getVirtualDisplayNumViews(std::get<0>(it.m_args));
})
.def("__getitem__", [](VirtualViewIterator & it, int i)
{
it.checkIndex(i, it.m_obj->getVirtualDisplayNumViews(std::get<0>(it.m_args)));
return it.m_obj->getVirtualDisplayView(std::get<0>(it.m_args), i);
})
.def("__iter__", [](VirtualViewIterator & it) -> VirtualViewIterator & { return it; })
.def("__next__", [](VirtualViewIterator & it)
{
int i = it.nextIndex(it.m_obj->getVirtualDisplayNumViews(std::get<0>(it.m_args)));
return it.m_obj->getVirtualDisplayView(std::get<0>(it.m_args), i);
});
clsViewIterator
.def("__len__", [](ViewIterator & it)
{ return it.m_obj->getNumViews(std::get<0>(it.m_args).c_str()); })
@@ -885,7 +1006,10 @@ void bindPyConfig(py::module & m)
return it.m_obj->getView(std::get<0>(it.m_args).c_str(),
std::get<1>(it.m_args).c_str(), i);
})
.def("__iter__", [](ViewForColorSpaceIterator & it) -> ViewForColorSpaceIterator & { return it; })
.def("__iter__", [](ViewForColorSpaceIterator & it) -> ViewForColorSpaceIterator &
{
return it;
})
.def("__next__", [](ViewForColorSpaceIterator & it)
{
int i = it.nextIndex(it.m_obj->getNumViews(std::get<0>(it.m_args).c_str(),
@@ -894,6 +1018,29 @@ void bindPyConfig(py::module & m)
std::get<1>(it.m_args).c_str(), i);
});
clsViewForViewTypeIterator
.def("__len__", [](ViewForViewTypeIterator & it)
{ return it.m_obj->getNumViews(std::get<0>(it.m_args),
std::get<1>(it.m_args).c_str()); })
.def("__getitem__", [](ViewForViewTypeIterator & it, int i)
{
it.checkIndex(i, it.m_obj->getNumViews(std::get<0>(it.m_args),
std::get<1>(it.m_args).c_str()));
return it.m_obj->getView(std::get<0>(it.m_args),
std::get<1>(it.m_args).c_str(), i);
})
.def("__iter__", [](ViewForViewTypeIterator & it) -> ViewForViewTypeIterator &
{
return it;
})
.def("__next__", [](ViewForViewTypeIterator & it)
{
int i = it.nextIndex(it.m_obj->getNumViews(std::get<0>(it.m_args),
std::get<1>(it.m_args).c_str()));
return it.m_obj->getView(std::get<0>(it.m_args),
std::get<1>(it.m_args).c_str(), i);
});
clsLookNameIterator
.def("__len__", [](LookNameIterator & it) { return it.m_obj->getNumLooks(); })
.def("__getitem__", [](LookNameIterator & it, int i)
+7 -1
View File
@@ -99,7 +99,13 @@ void bindPyContext(py::module & m)
"searchPaths"_a = getSearchPathsStdVec(DEFAULT),
"stringVars"_a = getStringVarsStdMap(DEFAULT),
"environmentMode"_a = DEFAULT->getEnvironmentMode(),
DOC(Context, Create))
DOC(Context, Create))
.def("__deepcopy__", [](const ConstContextRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("__iter__", [](ContextRcPtr & self)
{
+6
View File
@@ -16,6 +16,12 @@ void bindPyFileRules(py::module & m)
.def(py::init(&FileRules::Create),
DOC(FileRules, Create))
.def("__deepcopy__", [](const ConstFileRulesRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("getNumEntries", &FileRules::getNumEntries,
DOC(FileRules, getNumEntries))
.def("getIndexForRule", &FileRules::getIndexForRule, "ruleName"_a,
+6
View File
@@ -38,6 +38,12 @@ void bindPyLook(py::module & m)
"description"_a = DEFAULT->getDescription(),
DOC(Look, Create))
.def("__deepcopy__", [](const ConstLookRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("getName", &Look::getName,
DOC(Look, getName))
.def("setName", &Look::setName, "name"_a.none(false),
+7 -1
View File
@@ -118,6 +118,12 @@ void bindPyNamedTransform(py::module & m)
"categories"_a = getCategoriesStdVec(DEFAULT),
DOC(NamedTransform, Create))
.def("__deepcopy__", [](const ConstNamedTransformRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("getName", &NamedTransform::getName,
DOC(NamedTransform, getName))
.def("setName", &NamedTransform::setName, "name"_a.none(false),
@@ -145,7 +151,7 @@ void bindPyNamedTransform(py::module & m)
DOC(NamedTransform, setDescription))
.def("getEncoding", &NamedTransform::getEncoding,
DOC(NamedTransform, getEncoding))
.def("setEncoding", &NamedTransform::setEncoding, "encodig"_a.none(false),
.def("setEncoding", &NamedTransform::setEncoding, "encoding"_a.none(false),
DOC(NamedTransform, setEncoding))
// Transform
+6
View File
@@ -13,6 +13,12 @@ void bindPyTransform(py::module & m)
py::class_<Transform, TransformRcPtr>(
m.attr("Transform"))
.def("__deepcopy__", [](const ConstTransformRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("validate", &Transform::validate,
DOC(Transform, validate))
.def("getTransformType", &Transform::getTransformType,
+7 -1
View File
@@ -85,7 +85,13 @@ void bindPyViewTransform(py::module & m)
"toReference"_a = DEFAULT->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE),
"fromReference"_a = DEFAULT->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE),
"categories"_a = getCategoriesStdVec(DEFAULT),
DOC(ViewTransform, Create))
DOC(ViewTransform, Create))
.def("__deepcopy__", [](const ConstViewTransformRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("getName", &ViewTransform::getName,
DOC(ViewTransform, getName))
+7 -1
View File
@@ -33,7 +33,13 @@ void bindPyViewingRules(py::module & m)
clsViewingRules
.def(py::init(&ViewingRules::Create),
DOC(ViewingRules, Create))
.def("__deepcopy__", [](const ConstViewingRulesRcPtr & self, py::dict)
{
return self->createEditableCopy();
},
"memo"_a)
.def("getNumEntries", &ViewingRules::getNumEntries,
DOC(ViewingRules, getNumEntries))
.def("getIndexForRule", &ViewingRules::getIndexForRule, "ruleName"_a,
+161 -4
View File
@@ -1433,9 +1433,97 @@ OCIO_ADD_TEST(Config, context_variable_with_display_view)
}
}
OCIO_ADD_TEST(Config, context_variable_with_search_path)
OCIO_ADD_TEST(Config, context_variable_with_search_path_v1)
{
// Test a search_path pointing to a context variable.
// Test a search_path containing a context variable for a v1 config file.
// Note: The config validation does not check the path existence, it checks only if the path can
// be successfully resolved. But the processor creation needs to have at least one existing path.
// That's why the tests below check for the config validation and the processor creation.
static const std::string CONFIG =
"ocio_profile_version: 1\n"
"\n"
"search_path: $ENV1\n"
"\n"
"roles:\n"
" default: cs1\n"
" reference: cs1\n"
"\n"
"displays:\n"
" disp1:\n"
" - !<View> {name: view1, colorspace: cs2}\n"
"\n"
"colorspaces:\n"
" - !<ColorSpace>\n"
" name: cs1\n"
"\n"
" - !<ColorSpace>\n"
" name: cs2\n"
" from_reference: !<FileTransform> {src: lut1d_green.ctf}\n";
std::istringstream iss;
iss.str(CONFIG);
// $ENV1 is missing.
OCIO::ConfigRcPtr cfg;
OCIO_CHECK_NO_THROW(cfg = OCIO::Config::CreateFromStream(iss)->createEditableCopy());
OCIO_CHECK_THROW_WHAT(cfg->validate(), OCIO::Exception,
"The search_path '$ENV1' cannot be resolved.");
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1/lut1d_green.ctf'.");
#endif
// $ENV1 now exists.
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", OCIO::GetTestFilesDir().c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
// $ENV1 is faulty.
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", "faulty/path"));
OCIO_CHECK_NO_THROW(cfg->validate()); // Success because there is at least one resolved path.
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: 'faulty\\path\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: 'faulty/path/lut1d_green.ctf'.");
#endif
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", nullptr));
{
// Change the search_path to have at least one successful path i.e. the first one.
const std::string searchPath = OCIO::GetTestFilesDir() + ":$ENV1";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the second one.
const std::string searchPath = "$ENV1:" + OCIO::GetTestFilesDir();
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
}
OCIO_ADD_TEST(Config, context_variable_with_search_path_v2)
{
// Test a search_path containing a context variable for a v2 config file.
// Note: The config validation does not check the path existence, it checks only if the path can
// be successfully resolved. But the processor creation needs to have at least one existing path.
// That's why the tests below check for the config validation and the processor creation.
static const std::string CONFIG =
"ocio_profile_version: 2\n"
@@ -1463,19 +1551,88 @@ OCIO_ADD_TEST(Config, context_variable_with_search_path)
std::istringstream iss;
iss.str(CONFIG);
// $ENV1 exists in the config itself.
OCIO::ConfigRcPtr cfg;
OCIO_CHECK_NO_THROW(cfg = OCIO::Config::CreateFromStream(iss)->createEditableCopy());
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
/// Remove the context variable.
/// Remove the context variable so, there is no more successful path.
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", nullptr));
OCIO_CHECK_THROW_WHAT(cfg->validate(), OCIO::Exception,
"The search_path '$ENV1' cannot be resolved.");
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. ");
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1/lut1d_green.ctf'.");
#endif
// The following tests validate that in a list of search paths at least one can be resolved.
{
// Change the search_path to have at least one successful path i.e. the first one.
const std::string searchPath = OCIO::GetTestFilesDir() + ":$ENV1";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the second one.
const std::string searchPath = "$ENV1:" + OCIO::GetTestFilesDir();
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the first one.
const std::string searchPath = OCIO::GetTestFilesDir() + ":";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the second one.
const std::string searchPath = ":" + OCIO::GetTestFilesDir();
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
// The following test highlights the difference between the validation and the processor
// creation related to the search paths i.e. resolved vs. existing search paths.
{
// Change the search_path to have at least one potentially successful path
// i.e. the second one.
const std::string searchPath = "$ENV1:faulty/path";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
// The validation succeeds because the first path does not resolve but the second path does.
OCIO_CHECK_NO_THROW(cfg->validate());
// The first path does not resolve and the second path does resolve but it does not exist
// so the processor creation fails.
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: "
"'$ENV1\\lut1d_green.ctf' : 'faulty\\path\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: "
"'$ENV1/lut1d_green.ctf' : 'faulty/path/lut1d_green.ctf'.");
#endif
}
}
OCIO_ADD_TEST(Config, role_without_colorspace)
+24 -6
View File
@@ -5725,9 +5725,9 @@ OCIO_ADD_TEST(CTFTransform, cdl_clf)
<SOPNode>
<Description>SOP description 1</Description>
<Description>SOP description 2</Description>
<Slope>1, 1.1, 1.2</Slope>
<Offset>0.2, 0.3, 0.4</Offset>
<Power>3.1, 3.2, 3.3</Power>
<Slope>1 1.1 1.2</Slope>
<Offset>0.2 0.3 0.4</Offset>
<Power>3.1 3.2 3.3</Power>
</SOPNode>
<SatNode>
<Description>Sat description 1</Description>
@@ -5740,6 +5740,24 @@ OCIO_ADD_TEST(CTFTransform, cdl_clf)
OCIO_CHECK_EQUAL(expected.size(), outputTransform.str().size());
OCIO_CHECK_EQUAL(expected, outputTransform.str());
// Now test if the read is working.
std::istringstream ctfStream;
ctfStream.str(expected);
std::string emptyString;
OCIO::LocalFileFormat tester;
OCIO::CachedFileRcPtr file = tester.read(ctfStream, emptyString, OCIO::INTERP_DEFAULT);
auto cachedFile = OCIO::DynamicPtrCast<OCIO::LocalCachedFile>(file);
const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps();
OCIO_REQUIRE_EQUAL(opList.size(), 1);
auto cdlData = std::dynamic_pointer_cast<const OCIO::CDLOpData>(opList[0]);
OCIO_REQUIRE_ASSERT(cdlData);
OCIO_CHECK_EQUAL(cdlData->getSlopeParams()[0], 1.);
OCIO_CHECK_EQUAL(cdlData->getSlopeParams()[1], 1.1);
OCIO_CHECK_EQUAL(cdlData->getSlopeParams()[2], 1.2);
}
OCIO_ADD_TEST(CTFTransform, cdl_ctf)
@@ -5768,9 +5786,9 @@ OCIO_ADD_TEST(CTFTransform, cdl_ctf)
"<ProcessList version=\"1.7\" id=\"cdl2\">\n"
" <ASC_CDL inBitDepth=\"32f\" outBitDepth=\"32f\" style=\"Fwd\">\n"
" <SOPNode>\n"
" <Slope>1, 1.1, 1.2</Slope>\n"
" <Offset>0.2, 0.3, 0.4</Offset>\n"
" <Power>3.1, 3.2, 3.3</Power>\n"
" <Slope>1 1.1 1.2</Slope>\n"
" <Offset>0.2 0.3 0.4</Offset>\n"
" <Power>3.1 3.2 3.3</Power>\n"
" </SOPNode>\n"
" <SatNode>\n"
" <Saturation>2.1</Saturation>\n"
@@ -176,14 +176,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, log)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
const float input_32f[] = {
constexpr float input_32f[] = {
-0.2f, 0.2f, 0.5f, 0.0f,
0.8f, 1.0f, 2.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
0.25306581f, 0.35779659f, 0.98416632f, 0.0f,
1.09451043f, 1.54596428f, 1.78067802f, 0.5f };
@@ -219,14 +219,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, log_partial_identity)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
-0.2f, 0.2f, 0.5f, 0.0f,
0.8f, 1.0f, 2.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
-0.2f, 0.15779659f, 0.5f, 0.0f,
0.8f, 1.34596419f, 2.0f, 0.5f };
@@ -264,14 +264,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, monotonic)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
0.8f, 0.2f, 0.5f, 0.0f,
0.9f, 1.0f, 2.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
0.52230538f, 0.2f, 0.5f, 0.0f,
0.68079938f, 1.0f, 2.0f, 0.5f };
@@ -311,14 +311,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, lin_bypass)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
-8.f, -3.f, -1.f, 0.0f,
1.f, 2.5f, 4.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
-8.50508935f, -6.37181915f, -3.01264257f, 0.0f,
1.95205522f, 4.76796850f, 5.76796850f, 0.5f };
@@ -357,14 +357,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, lin)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
-0.003f, 0.02f, 0.09f, 0.0f,
0.360f, 1.00f, 3.00f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
-4.20784139e-03f, 1.26825221e-03f, 2.23983977e-02f, 0.0f,
6.96706128e-01f, 4.79411018e+00f, 9.95152432e+00f, 0.5f };
@@ -410,14 +410,33 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, slopes)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 1;
constexpr long num_samples = 2;
float input_32f[] = {
-3.f, -1.f, 1.f, 0.5f };
-3.f, -1.f, 1.f, 0.5f,
-7.f, 0.f, 7.f, 1.0f };
// Test that the slopes were used (the values are significantly different without slopes).
const float expected_32f[] = {
-2.92582282f, 0.28069129f, 2.81987724f, 0.5f };
constexpr float expected_32f[] = {
-2.92582282f, 0.28069129f, 2.81987724f, 0.5f,
-4.0f, 1.73250193f, 4.0f, 1.0f };
OCIO_CHECK_NO_THROW(op->apply(input_32f, input_32f, num_samples));
ValidateImage(expected_32f, input_32f, num_samples, __LINE__);
// Test in inverse direction.
float rev_input_32f[] = {
-2.92582282f, 0.28069129f, 2.81987724f, 0.5f,
-7.0f, 1.73250193f, 7.0f, 1.0f };
constexpr float rev_expected_32f[] = {
-3.f, -1.f, 1.f, 0.5f,
-5.26017743f, 0.f, 4.67381243f, 1.0f };
gc->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
OCIO_CHECK_NO_THROW(op->apply(rev_input_32f, rev_input_32f, num_samples));
ValidateImage(rev_expected_32f, rev_input_32f, num_samples, __LINE__);
}
+40
View File
@@ -1238,6 +1238,46 @@ OCIO_ADD_TEST(Lut1DRenderer, lut_1d_special_values)
OCIO_CHECK_EQUAL(outImage[7], 1.0f);
}
OCIO_ADD_TEST(Lut1DRenderer, lut_1d_hd_above_half_max)
{
// Test the processing of half-domain Lut1D for float input values that are greater than
// HALF_MAX but round down to HALF_MAX. These are the values 65504 < x < 65520.
// In other words, half(65519) rounds down to 65504 and half(65520) rounds up to Inf.
// There was a bug where these values were not processed correctly.
OCIO::ConfigRcPtr config = OCIO::Config::Create();
const std::string ctfLUT("lut1d_hd_16f_16i_1chan.ctf");
OCIO::FileTransformRcPtr fileTransform = OCIO::CreateFileTransform(ctfLUT);
OCIO::ConstProcessorRcPtr proc;
OCIO_CHECK_NO_THROW(proc = config->getProcessor(fileTransform));
OCIO::ConstCPUProcessorRcPtr cpuFwd;
OCIO_CHECK_NO_THROW(cpuFwd = proc->getDefaultCPUProcessor());
float inImage[] = {
65505.0f, 65519.0f, 65520.0f, 0.0f,
-65505.0f, -65519.0f, -65520.0f, 1.0f
};
std::vector<float> outImage(2 * 4, -12.345f);
OCIO::PackedImageDesc srcImgDesc((void*)&inImage[0], 2, 1, 4);
OCIO::PackedImageDesc dstImgDesc((void*)&outImage[0], 2, 1, 4);
cpuFwd->apply(srcImgDesc, dstImgDesc);
static const float rtol = 1e-5f;
OCIO_CHECK_CLOSE(outImage[0], 0.7785763f, rtol);
OCIO_CHECK_CLOSE(outImage[1], 0.7785763f, rtol);
OCIO_CHECK_CLOSE(outImage[2], 0.7785763f, rtol);
OCIO_CHECK_EQUAL(outImage[3], 0.0f);
OCIO_CHECK_CLOSE(outImage[4], 0.f, rtol);
OCIO_CHECK_CLOSE(outImage[5], 0.f, rtol);
OCIO_CHECK_CLOSE(outImage[6], 0.f, rtol);
OCIO_CHECK_EQUAL(outImage[7], 1.0f);
}
namespace
{
constexpr OCIO::OptimizationFlags DefaultNoLutInvFast =
+62
View File
@@ -105,6 +105,68 @@ OCIO_ADD_GPU_TEST(GradingRGBCurve, style_lin_rev_dynamic)
GradingRGBCurveLin(test, OCIO::TRANSFORM_DIR_INVERSE, true);
}
void GradingRGBSCurve(OCIOGPUTest & test, OCIO::TransformDirection dir, bool dynamic)
{
// Create an S-curve with 0 slope at each end.
auto curve = OCIO::GradingBSplineCurve::Create({
{-5.26017743f, -4.f},
{-3.75502745f, -3.57868829f},
{-2.24987747f, -1.82131329f},
{-0.74472749f, 0.68124124f},
{ 1.06145248f, 2.87457742f},
{ 2.86763245f, 3.83406206f},
{ 4.67381243f, 4.f}
});
float slopes[] = { 0.f, 0.55982688f, 1.77532247f, 1.55f, 0.8787017f, 0.18374463f, 0.f };
for (size_t i = 0; i < 7; ++i)
{
curve->setSlope( i, slopes[i] );
}
OCIO::ConstGradingBSplineCurveRcPtr m = curve;
// Adjust scaling to ensure the test vector for the inverse hits the flat areas.
auto scaling = OCIO::GradingBSplineCurve::Create({ { -5.f, 0.f }, { 5.f, 1.f } });
OCIO::ConstGradingBSplineCurveRcPtr z = scaling;
OCIO::ConstGradingRGBCurveRcPtr curves = OCIO::GradingRGBCurve::Create(m, m, m, z);
auto gc = OCIO::GradingRGBCurveTransform::Create(OCIO::GRADING_LOG);
gc->setValue(curves);
gc->setDirection(dir);
if (dynamic)
{
gc->makeDynamic();
}
test.setProcessor(gc);
test.setErrorThreshold(1.5e-4f);
test.setExpectedMinimalValue(1.0f);
test.setRelativeComparison(true);
test.setTestWideRange(true);
test.setTestInfinity(false);
test.setTestNaN(true);
}
OCIO_ADD_GPU_TEST(GradingRGBCurve, scurve_fwd)
{
GradingRGBSCurve(test, OCIO::TRANSFORM_DIR_FORWARD, false);
}
OCIO_ADD_GPU_TEST(GradingRGBCurve, scurve_fwd_dynamic)
{
GradingRGBSCurve(test, OCIO::TRANSFORM_DIR_FORWARD, true);
}
OCIO_ADD_GPU_TEST(GradingRGBCurve, scurve_rev)
{
GradingRGBSCurve(test, OCIO::TRANSFORM_DIR_INVERSE, false);
}
OCIO_ADD_GPU_TEST(GradingRGBCurve, scurve_rev_dynamic)
{
GradingRGBSCurve(test, OCIO::TRANSFORM_DIR_INVERSE, true);
}
namespace
{
+27 -1
View File
@@ -3,7 +3,7 @@
# TODO: Add getFormatMetadata tests.
import unittest, os, sys
import copy, unittest, os, sys
import PyOpenColorIO as OCIO
class BakerTest(unittest.TestCase):
@@ -55,6 +55,32 @@ END METADATA
"""
def test_copy(self):
"""
Test the deepcopy() method.
"""
cfg = OCIO.Config().CreateFromStream(self.SIMPLE_PROFILE)
bake = OCIO.Baker()
bake.setConfig(cfg)
bake.setFormat("cinespace")
bake.setInputSpace("lnh")
bake.setLooks("foo, +bar")
bake.setTargetSpace("test")
bake.setShaperSize(4)
bake.setCubeSize(2)
other = copy.deepcopy(bake)
self.assertFalse(other is bake)
self.assertEqual(other.getConfig(), bake.getConfig())
self.assertEqual(other.getFormat(), bake.getFormat())
self.assertEqual(other.getInputSpace(), bake.getInputSpace())
self.assertEqual(other.getLooks(), bake.getLooks())
self.assertEqual(other.getTargetSpace(), bake.getTargetSpace())
self.assertEqual(other.getShaperSize(), bake.getShaperSize())
self.assertEqual(other.getCubeSize(), bake.getCubeSize())
def test_interface(self):
"""
Test similar to C++ CPU test.
+38
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import copy
import unittest
import os
import sys
@@ -10,6 +11,7 @@ from UnitTestUtils import SIMPLE_CONFIG, TEST_NAMES, TEST_DESCS, TEST_CATEGORIES
class ColorSpaceTest(unittest.TestCase):
def setUp(self):
self.colorspace = OCIO.ColorSpace()
self.log_tr = OCIO.LogTransform(10)
@@ -18,6 +20,42 @@ class ColorSpaceTest(unittest.TestCase):
self.colorspace = None
self.log_tr = None
def test_copy(self):
"""
Test the deepcopy() method.
"""
self.colorspace.setName('colorspace1')
self.colorspace.setFamily('family')
self.colorspace.setEqualityGroup('group')
self.colorspace.setDescription('description')
self.colorspace.setBitDepth(OCIO.BIT_DEPTH_UINT8)
self.colorspace.setEncoding('encoding')
self.colorspace.setIsData(False)
self.colorspace.setAllocation(OCIO.ALLOCATION_LG2)
self.colorspace.setAllocationVars([-8, 5, 0.00390625])
mat = OCIO.MatrixTransform()
self.colorspace.setTransform(mat, OCIO.COLORSPACE_DIR_TO_REFERENCE)
self.colorspace.setTransform(direction=OCIO.COLORSPACE_DIR_FROM_REFERENCE, transform=mat)
self.colorspace.addAlias('alias')
self.colorspace.addCategory('cat')
other = copy.deepcopy(self.colorspace)
self.assertFalse(other is self.colorspace)
self.assertEqual(other.getName(), self.colorspace.getName())
self.assertEqual(other.getFamily(), self.colorspace.getFamily())
self.assertEqual(other.getEqualityGroup(), self.colorspace.getEqualityGroup())
self.assertEqual(other.getDescription(), self.colorspace.getDescription())
self.assertEqual(other.getBitDepth(), self.colorspace.getBitDepth())
self.assertEqual(other.getEncoding(), self.colorspace.getEncoding())
self.assertEqual(other.isData(), self.colorspace.isData())
self.assertEqual(other.getAllocation(), self.colorspace.getAllocation())
self.assertEqual(other.getAllocationVars(), self.colorspace.getAllocationVars())
self.assertTrue(other.getTransform(OCIO.COLORSPACE_DIR_TO_REFERENCE).equals(self.colorspace.getTransform(OCIO.COLORSPACE_DIR_TO_REFERENCE)))
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()))
def test_allocation(self):
"""
Test the setAllocation() and getAllocation() methods.
+142
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import copy
import unittest
import os
import sys
@@ -241,6 +242,45 @@ from UnitTestUtils import TEST_DATAFILES_DIR, TEST_NAMES, TEST_DESCS
class ConfigTest(unittest.TestCase):
def test_copy(self):
"""
Test the deepcopy() method.
"""
cfg = OCIO.Config.CreateRaw()
cfg.setMajorVersion(2)
cfg.setMinorVersion(0)
cfg.setName('test config')
cfg.setDescription('test description')
cfg.addColorSpace(
OCIO.ColorSpace(OCIO.REFERENCE_SPACE_DISPLAY,
"display_cs",
toReference=OCIO.CDLTransform(sat=1.5)))
cfg.addColorSpace(
OCIO.ColorSpace(OCIO.REFERENCE_SPACE_SCENE,
"raw",
isData=True))
rules = OCIO.FileRules()
rules.insertRule(0, 'A', 'raw', '*', 'exr')
rules.insertRule(1, 'B', 'display_cs', '*', 'png')
cfg.setFileRules(rules)
other = copy.deepcopy(cfg)
self.assertFalse(other is cfg)
self.assertEqual(other.getMajorVersion(), cfg.getMajorVersion())
self.assertEqual(other.getMinorVersion(), cfg.getMinorVersion())
self.assertEqual(other.getName(), cfg.getName())
self.assertEqual(other.getDescription(), cfg.getDescription())
self.assertEqual(list(other.getColorSpaceNames()), list(cfg.getColorSpaceNames()))
self.assertEqual(other.getFileRules().getNumEntries(), cfg.getFileRules().getNumEntries())
# Check that the file rules are not shared between the two config instances.
rules.removeRule(0)
other.setFileRules(rules)
self.assertEqual(other.getFileRules().getNumEntries(), cfg.getFileRules().getNumEntries() - 1)
def test_shared_views(self):
# Test these Config functions: addSharedView, getSharedViews, removeSharedView.
@@ -751,3 +791,105 @@ colorspaces:
self.assertEqual(cfg.getCanonicalName('NT1'), 'nt1')
self.assertEqual(cfg.getCanonicalName('Alias1'), 'nt1')
self.assertEqual(cfg.getCanonicalName('Test1'), 'nt1')
def test_virtual_display(self):
# Test platform agnostic virtual display interface.
cfg = OCIO.Config().CreateRaw()
cfg.addColorSpace(
OCIO.ColorSpace(OCIO.REFERENCE_SPACE_DISPLAY,
"display_cs",
toReference=OCIO.CDLTransform(sat=1.5)))
cfg.addColorSpace(
OCIO.ColorSpace(OCIO.REFERENCE_SPACE_SCENE,
"raw",
isData=True))
cfg.addViewTransform(
OCIO.ViewTransform(OCIO.REFERENCE_SPACE_SCENE,
"default_vt",
toReference=OCIO.CDLTransform(sat=1.5)))
cfg.addViewTransform(
OCIO.ViewTransform(OCIO.REFERENCE_SPACE_DISPLAY,
"display_vt",
toReference=OCIO.CDLTransform(sat=1.5)))
cfg.addDisplayView("sRGB", "Raw", "raw")
cfg.addDisplayView("sRGB", "view",
viewTransform="display_vt",
displayColorSpaceName="display_cs")
cfg.addSharedView("sview1", "", "raw")
cfg.addSharedView("sview2", "", "raw")
cfg.addDisplaySharedView("sRGB", "sview1")
# Add virtual display and views
cfg.addVirtualDisplayView("Raw", "", "raw")
cfg.addVirtualDisplayView("Film", "display_vt",
OCIO.OCIO_VIEW_USE_DISPLAY_NAME)
cfg.addVirtualDisplaySharedView("sview2")
# Some basic checks
self.assertEqual(3, len(cfg.getViews("sRGB")))
self.assertEqual(2, len(cfg.getViews(OCIO.VIEW_DISPLAY_DEFINED,
"sRGB")))
self.assertEqual(1, len(cfg.getViews(OCIO.VIEW_SHARED, "sRGB")))
# Validate the virtual display information
self.assertEqual(
2,
len(cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)))
view_name = cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)[0]
self.assertEqual("Raw", view_name)
self.assertEqual("", cfg.getVirtualDisplayViewTransformName(view_name))
self.assertEqual("raw",
cfg.getVirtualDisplayViewColorSpaceName(view_name))
self.assertEqual("", cfg.getVirtualDisplayViewLooks(view_name))
self.assertEqual("", cfg.getVirtualDisplayViewRule(view_name))
self.assertEqual("", cfg.getVirtualDisplayViewDescription(view_name))
view_name = cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)[1]
self.assertEqual("Film", view_name)
self.assertEqual("display_vt",
cfg.getVirtualDisplayViewTransformName(view_name))
self.assertEqual(OCIO.OCIO_VIEW_USE_DISPLAY_NAME,
cfg.getVirtualDisplayViewColorSpaceName(view_name))
self.assertEqual("", cfg.getVirtualDisplayViewLooks(view_name))
self.assertEqual("", cfg.getVirtualDisplayViewRule(view_name))
self.assertEqual("", cfg.getVirtualDisplayViewDescription(view_name))
self.assertEqual(1, len(cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)))
self.assertEqual("sview2",
cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)[0])
# Remove a view from the virtual display
cfg.removeVirtualDisplayView("Raw")
self.assertEqual(
1,
len(cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)))
self.assertEqual(
"Film",
cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)[0])
self.assertEqual(1, len(cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)))
self.assertEqual("sview2",
cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)[0])
# Remove a shared view from the virtual display
cfg.removeVirtualDisplayView("sview2")
self.assertEqual(
1,
len(cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)))
self.assertEqual(0, len(cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)))
cfg.addVirtualDisplaySharedView("sview2")
self.assertEqual(
1,
len(cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)))
self.assertEqual(1, len(cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)))
# Remove the virtual display
cfg.clearVirtualDisplay()
self.assertEqual(
0,
len(cfg.getVirtualDisplayViews(OCIO.VIEW_DISPLAY_DEFINED)))
self.assertEqual(0, len(cfg.getVirtualDisplayViews(OCIO.VIEW_SHARED)))
+21 -1
View File
@@ -1,11 +1,31 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import unittest, os, sys
import copy, unittest, os, sys
import PyOpenColorIO as OCIO
class ContextTest(unittest.TestCase):
def test_copy(self):
"""
Test the deepcopy() method.
"""
cont = OCIO.Context()
cont.setSearchPath('testing123:testing456')
cont.setWorkingDir('/dir/123')
cont.setEnvironmentMode(OCIO.ENV_ENVIRONMENT_LOAD_PREDEFINED)
cont['TeSt'] = 'foobar'
cont['Bar'] = 'Foo'
other = copy.deepcopy(cont)
self.assertFalse(other is cont)
self.assertEqual(other.getCacheID(), cont.getCacheID())
self.assertEqual(other.getSearchPath(), cont.getSearchPath())
self.assertEqual(other.getWorkingDir(), cont.getWorkingDir())
self.assertEqual(other.getEnvironmentMode(), cont.getEnvironmentMode())
self.assertEqual(list(other), list(cont))
def test_interface(self):
"""
Construct and use Context.
+26 -1
View File
@@ -1,11 +1,36 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import unittest, os, sys
import copy, unittest, os, sys
import PyOpenColorIO as OCIO
class FileRulesTest(unittest.TestCase):
def test_copy(self):
"""
Test the deepcopy() method.
"""
rules = OCIO.FileRules()
rules.insertRule(0, 'test0', 'colorspace', 'pattern', 'ext')
rules.setCustomKey(0, 'key1', 'val1')
rules.insertRule(1, 'test2', 'colorspace', 'regex')
rules.setCustomKey(1, 'key2', 'val2')
other = copy.deepcopy(rules)
self.assertFalse(other is rules)
self.assertEqual(other.getNumEntries(), rules.getNumEntries())
for idx in range(other.getNumEntries()):
self.assertEqual(other.getName(idx), rules.getName(idx))
self.assertEqual(other.getPattern(idx), rules.getPattern(idx))
self.assertEqual(other.getExtension(idx), rules.getExtension(idx))
self.assertEqual(other.getRegex(idx), rules.getRegex(idx))
self.assertEqual(other.getColorSpace(idx), rules.getColorSpace(idx))
self.assertEqual(other.getNumCustomKeys(idx), rules.getNumCustomKeys(idx))
for idx_inner in range(other.getNumCustomKeys(idx)):
self.assertEqual(other.getCustomKeyName(idx, idx_inner), rules.getCustomKeyName(idx, idx_inner))
self.assertEqual(other.getCustomKeyValue(idx, idx_inner), rules.getCustomKeyValue(idx, idx_inner))
def test_default(self):
"""
Construct and verify default values.
+21
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import copy
import unittest
import os
import sys
@@ -19,6 +20,26 @@ class LookTest(unittest.TestCase):
def tearDown(self):
self.look = None
def test_copy(self):
"""
Test the deepcopy() method.
"""
self.look.setName('test name')
self.look.setProcessSpace('test space')
self.look.setDescription('test description')
mat = OCIO.MatrixTransform()
self.look.setTransform(mat)
self.look.setInverseTransform(mat)
other = copy.deepcopy(self.look)
self.assertFalse(other is self.look)
self.assertEqual(other.getName(), self.look.getName())
self.assertEqual(other.getProcessSpace(), self.look.getProcessSpace())
self.assertEqual(other.getDescription(), self.look.getDescription())
self.assertTrue(other.getTransform().equals(self.look.getTransform()))
self.assertTrue(other.getInverseTransform().equals(self.look.getInverseTransform()))
def test_name(self):
"""
Test the setName() and getName() methods.
+27
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import copy
import unittest
import PyOpenColorIO as OCIO
@@ -19,6 +20,32 @@ class NamedTransformTest(unittest.TestCase):
def tearDown(self):
self.named_tr = None
def test_copy(self):
"""
Test the deepcopy() method.
"""
self.named_tr.setName('test name')
self.named_tr.setFamily('test family')
self.named_tr.setDescription('test description')
self.named_tr.setEncoding('test encoding')
mat = OCIO.MatrixTransform()
self.named_tr.setTransform(mat, OCIO.TRANSFORM_DIR_FORWARD)
self.named_tr.setTransform(direction=OCIO.TRANSFORM_DIR_INVERSE, transform=mat)
self.named_tr.addCategory('cat1')
self.named_tr.addAlias("alias1")
other = copy.deepcopy(self.named_tr)
self.assertFalse(other is self.named_tr)
self.assertEqual(other.getName(), self.named_tr.getName())
self.assertEqual(other.getFamily(), self.named_tr.getFamily())
self.assertEqual(other.getDescription(), self.named_tr.getDescription())
self.assertEqual(other.getEncoding(), self.named_tr.getEncoding())
self.assertTrue(other.getTransform(OCIO.TRANSFORM_DIR_FORWARD).equals(self.named_tr.getTransform(OCIO.TRANSFORM_DIR_FORWARD)))
self.assertTrue(other.getTransform(OCIO.TRANSFORM_DIR_INVERSE).equals(self.named_tr.getTransform(OCIO.TRANSFORM_DIR_INVERSE)))
self.assertEqual(list(other.getCategories()), list(self.named_tr.getCategories()))
self.assertEqual(list(other.getAliases()), list(self.named_tr.getAliases()))
def test_name(self):
"""
Test the setName() and getName() methods.
+27 -7
View File
@@ -1,17 +1,13 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import unittest, os, sys
import copy, unittest, os, sys
import PyOpenColorIO as OCIO
import inspect
class TransformsTest(unittest.TestCase):
def test_binding_group_polymorphism(self):
"""
Tests polymorphism issue where transforms are cast as parent class when using
GroupTransforms. Flagged in https://github.com/AcademySoftwareFoundation/OpenColorIO/issues/1211
"""
def all_transforms_as_group(self):
# Default arguments for Transforms that can't be instantiated without arguments.
default_args = {
OCIO.FixedFunctionTransform: {
@@ -42,7 +38,31 @@ class TransformsTest(unittest.TestCase):
'Unintended Error Raised: {0}'.format(e)
)
for transform in allTransformsAsGroup:
return allTransformsAsGroup
def test_copy(self):
"""
Test the deepcopy() method.
"""
for transform in self.all_transforms_as_group():
other = copy.deepcopy(transform)
self.assertFalse(other is transform)
self.assertEquals(other.getTransformType(), transform.getTransformType())
self.assertEquals(other.getDirection(), transform.getDirection())
# Not all OCIO.Transform have equals methods
if hasattr(transform, 'equals'):
self.assertTrue(other.equals(transform))
other.setDirection(OCIO.TRANSFORM_DIR_INVERSE)
self.assertNotEquals(other.getDirection(), transform.getDirection())
def test_binding_group_polymorphism(self):
"""
Tests polymorphism issue where transforms are cast as parent class when using
GroupTransforms. Flagged in https://github.com/AcademySoftwareFoundation/OpenColorIO/issues/1211
"""
for transform in self.all_transforms_as_group():
# Ensure no transforms have been cast as parent transform
self.assertNotEqual(
type(transform),
+25
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
import copy
import unittest
import os
import sys
@@ -16,6 +17,30 @@ class ViewingRulesTest(unittest.TestCase):
def tearDown(self):
self.rule = None
def test_copy(self):
"""
Test the deepcopy() method.
"""
self.rules.insertRule(0, "rule1")
self.rules.insertRule(1, "rule2")
self.rules.insertRule(2, "rule3")
self.rules.addColorSpace(0, "cs1")
self.rules.addEncoding(1, "enc1")
self.rules.setCustomKey(2, "key1", "value1")
other = copy.deepcopy(self.rules)
self.assertFalse(other is self.rules)
self.assertEqual(other.getNumEntries(), self.rules.getNumEntries())
for idx in range(self.rules.getNumEntries()):
self.assertEqual(other.getName(idx), self.rules.getName(idx))
self.assertEqual(list(other.getColorSpaces(0)), list(self.rules.getColorSpaces(0)))
self.assertEqual(list(other.getEncodings(1)), list(self.rules.getEncodings(1)))
self.assertEqual(list(other.getCustomKeyName(2, 0)), list(self.rules.getCustomKeyName(2, 0)))
self.assertEqual(list(other.getCustomKeyValue(2, 0)), list(self.rules.getCustomKeyValue(2, 0)))
def test_insert_remove(self):
"""
Test the insertRule(), removeRule(), getNumEntrie(), getIndexForRule(), getName() methods.