"""
A collection of tools and functions to help manage LUTs and color configuration
"""
from _nuke_color import * # bring the libnuke PythonAPI for color into scope
from . import callbacks
import types
import nuke_internal as nuke
defaultLUTMappers = {} # dictionary of all mappers
[docs]class ColorspaceLookupError(Exception):
""" an excpetion that should be thrown when looking up the colorspace """
pass
def _attemptColorspaceNameMatch(colorspaceName) :
""" Look through all options in the colorpsace knob, and see if we have an
exact match to one of the items. """
node = nuke.thisNode()
try:
colorspaceKnob = node['colorspace']
except ValueError:
# failed to get the Knob from the Node because the Node may be unattached
# when loading script or similar
return False
allColorspaces = getColorspaceList( colorspaceKnob )
return colorspaceName in allColorspaces
def _lookUpDataTypeDefaultSettings(colorspaceName, dataTypeHint):
"""
Nuke's default handling of colorspace lookups.
Maps applicable dataTypeHint values to knobs on the Preferecne panel
Possible values for dataTypeHint are
Nuke inbuilt data-type hints (map to knobs)
nuke.MONITOR == 0
nuke.VIEWER == 1
nuke.INT8 == 2
nuke.INT16 == 3
nuke.LOG == 4
nuke.FLOAT == 5
Other numeric values which map to those in DDImage/LUT.h
6 == DD::Image::LUT::GAMMA1_8
7 == DD::Image::LUT::GAMMA2_2
8 == DD::Image::LUT::GAMMA2_4
9 == DD::Image::LUT::PANALOG
10 == DD::Image::LUT::REDLOG
11 == DD::Image::LUT::VIPERLOG
12 == DD::Image::LUT::ALEXAV3LOGC
13 == DD::Image::LUT::PLOGLIN
14 == DD::Image::LUT::SLOG
15 == DD::Image::LUT::SLOG1
16 == DD::Image::LUT::SLOG2
17 == DD::Image::LUT::SLOG3
18 == DD::Image::LUT::CLOG
19 == DD::Image::LUT::PROTUNE
20 == DD::Image::LUT::GAMMA2_6
21 == DD::Image::LUT::LOG3G10
22 == DD::Image::LUT::LOG3G12
23 == DD::Image::LUT::BT1886
24 is deprecated and shouldn't be used
25 == DD::Image::LUT::HYBRIDLOGGAMMA
26 == DD::Image::LUT::ST2084
"""
root = nuke.thisRoot()
def getKnobValue( knobName ) :
try:
knob = root[ knobName ]
except ValueError:
raise ColorspaceLookupError
return knob.value()
retString = colorspaceName
if dataTypeHint == nuke.MONITOR: # 0 = LUT::MONITOR
retString = getKnobValue( "monitorLut" )
elif dataTypeHint == nuke.VIEWER: # 1 = LUT::VIEWER
pass
elif dataTypeHint == nuke.INT8: # 2 = LUT::INT8
retString = getKnobValue( "int8Lut" )
elif dataTypeHint == nuke.INT16: # 3 = LUT::INT16
retString = getKnobValue( "int16Lut" )
elif dataTypeHint == nuke.LOG: # 4 = LUT::LOG
retString = getKnobValue( "logLut" )
elif dataTypeHint == nuke.FLOAT: # 5 = LUT::FLOAT
retString = getKnobValue( "floatLut" )
return retString
def _nukeDefaultColorSpaceMapper(colorspaceName, dataTypeHint):
"""
Allows colorspaces selections to be altered before use on Readers and Writers
"""
if colorspaceName == "." :
raise RuntimeError( "Nuke has provided invalid colorspace name" )
try:
retName = _lookUpDataTypeDefaultSettings(colorspaceName, dataTypeHint)
except ColorspaceLookupError:
retName = colorspaceName
# TODO: find best name in colosrpace
return retName
[docs]def addDefaultColorspaceMapper(call, args=(), kwargs={}, nodeClass='*'):
"""
Add a function to modify default colorspaces before Nuke passes them to
Readers or Writers.
Functions should have the same positional argument as in the definition of
defaultLUTMapper()
All added functions are called in backwards order.
"""
callbacks._addCallback(defaultLUTMappers, call, args, kwargs, nodeClass)
[docs]def removeDefaultColorspaceMapper(call, args=(), kwargs={}, nodeClass='*'):
"""
Remove a previously-added callback with the same arguments.
"""
callbacks._removeCallback(defaultLUTMappers, call, args, kwargs, nodeClass)
def _doColorSpaceCallbacks( colorspace, dataTypeHint, callbacks, errorMsg ) :
"""
Perform the colorspace callbacks
expects a string or 'None' to be returned.
"""
for funcData in callbacks:
func = funcData[0]
args = funcData[1]
kwargs = funcData[2]
s = func(colorspace, dataTypeHint, *args, **kwargs)
if not isinstance(s, str) and s is not None:
raise TypeError( errorMsg + ". Got type %s"%str(type(s)) )
if s is not None:
colorspace = s
return colorspace
[docs]def defaultColorspaceMapper(colorspace, dataTypeHint):
"""
Called by libnuke.
Calls into Node-level callbacks first, then global callbacks
Arguments:
colorspace - the name string of the initial colorspace
dataTypeHint - sometimes Readers/Writer request the default for a
particular data-type, i.e. int8, in16, float, etc.
Return:
The return should be the transformed/modified colorspace name.
None is the same as returning the string unchanged.
"""
import __main__
# Do Nuke's in built mapping first.
colorspace = _nukeDefaultColorSpaceMapper(colorspace, dataTypeHint)
# Then do callbacks registered for this Node type
colorspaceCbs = defaultLUTMappers.get(nuke.thisClass())
if colorspaceCbs:
nodeErrMsg = ( "Colorspace Filter on Node '%s' returned invalid type,"
"expected string or None"%( nuke.thisClass() ) )
colorspace = _doColorSpaceCallbacks( colorspace, dataTypeHint, colorspaceCbs, nodeErrMsg )
# Do global manipulations afterwards
globalCbs = defaultLUTMappers.get('*')
if globalCbs:
globalErrMsg = ( "Global Colorspace Filter returned invalid type,"
"expected string or None" )
colorspace = _doColorSpaceCallbacks( colorspace, dataTypeHint, globalCbs, globalErrMsg )
return colorspace
[docs]def getColorspaceList(colorspaceKnob) :
"""
Get a list of all colorspaces listed in an enumeration knob.
This will strip family names if the knob has the STRIP_CASCADE_PREFIX flag set.
"""
allColorspaces = list(colorspaceKnob.values())
strippedColorspaces = []
if not colorspaceKnob.getFlag(nuke.STRIP_CASCADE_PREFIX) :
return allColorspaces
else:
for strippedColorspace in allColorspaces:
# Strip up until the last '/', which represents the family name
strippedColorspace = strippedColorspace.split('/')[-1]
strippedColorspaces.append(strippedColorspace)
return strippedColorspaces