Source code for nukescripts.psd

#####
##
##  Uses meta-data from the incoming image stream to break a PSD files into layers
#
#   Each layer is combined together with a PSDMerge node which emulates the blending modes
#


import nuke_internal as nuke
import random
import math
import threading


[docs]class Layer(): def __init__(self): self.attrs = {}
[docs]def getLayers(metadata): layers = [] for key in metadata: if key.startswith( 'input/psd/layers/' ): splitKey = key.split( '/' ) num = int( splitKey[3] ) attr = splitKey[4] try: attr += '/' + splitKey[5] except: pass while ( len(layers) <= num ): layers.append( Layer() ) layers[num].attrs[ attr ] = metadata[key] return layers
[docs]def breakoutLayers( node, sRGB = True ): if not node: return nuke.Undo().begin() blendMap = {} blendMap['norm'] = "normal" blendMap['scrn'] = "screen" blendMap['div '] = "color dodge" blendMap['over'] = "overlay" blendMap['mul '] = "multiply" blendMap['dark'] = "darken" blendMap['idiv'] = "color burn" blendMap['lbrn'] = "linear burn" blendMap['lite'] = "lighten" blendMap['lddg'] = "linear dodge" blendMap['lgCl'] = "lighter color" blendMap['sLit'] = "soft light" blendMap['hLit'] = "hard light" blendMap['lLit'] = "linear light" blendMap['vLit'] = "vivid light" blendMap['pLit'] = "pin light" blendMap['hMix'] = "hard mix" blendMap['diff'] = "difference" blendMap['smud'] = "exclusion" blendMap['fsub'] = "subtract" blendMap['fdiv'] = "divide" blendMap['hue '] = "hue" blendMap['sat '] = "saturation" blendMap['colr'] = "color" blendMap['lum '] = "luminosity" metaData = node.metadata() layers = getLayers(metaData) xspacing = 80 dotXfudge = 34 dotYfudge = 4 backdropXfudge = -( xspacing//2 ) + 10 backdropYfudge = -40 spacing = 70 x = node.xpos() y = node.ypos() curY = y + spacing * 2 if not sRGB: colorSpace = nuke.nodes.Colorspace() colorSpace['channels'].setValue( 'all' ) colorSpace['colorspace_out'].setValue( 'sRGB') colorSpace.setInput(0, node ) colorSpace.setXYpos( x, curY ) inputNode = colorSpace else: inputNode = node curX = x curY = y + spacing * 2 topY = curY lastLayer = None background = None i = 0 for l in layers: try: if l.attrs['divider/type'] > 0: ## hidden divider or start of group continue except: pass i = i + 1 if i > 100: nuke.message( "Too many layers, stopping at layer 100." ) break; name = l.attrs['nukeName'] curY = topY if i % 2 : tileColor = 2829621248 else: tileColor = 1751668736 backdrop = nuke.nodes.BackdropNode(tile_color = tileColor, note_font_size=18) backdrop.setXYpos( curX + backdropXfudge, curY + backdropYfudge ) curY += spacing//2 dot = nuke.nodes.Dot() dot.setInput( 0, inputNode ) dot.setXYpos( curX + dotXfudge , curY + dotYfudge) curY += spacing inputNode = dot shuffle = nuke.nodes.Shuffle() shuffle['label'].setValue( name ) shuffle['in'].setValue( name ) shuffle['in2'].setValue( 'none' ) shuffle['red'].setValue( 'red' ) shuffle['green'].setValue( 'green' ) shuffle['blue'].setValue( 'blue' ) shuffle['alpha'].setValue( 'alpha' ) ## if no 'alpha' assume alpha of 1 alphaChan = name + ".alpha" if not alphaChan in inputNode.channels(): shuffle['alpha'].setValue( 'white' ) shuffle['black'].setValue( 'red2' ) shuffle['white'].setValue( 'green2' ) shuffle['red2'].setValue( 'blue2' ) shuffle['green2'].setValue( 'alpha2' ) shuffle['out'].setValue( 'rgba' ) shuffle['out2'].setValue( 'none' ) shuffle.setInput(0, inputNode ) shuffle.setXYpos( curX, curY ) curY += spacing crop = nuke.nodes.Crop() crop['box'].setValue( l.attrs['x'], 0 ) crop['box'].setValue( l.attrs['y'], 1 ) crop['box'].setValue( l.attrs['r'], 2 ) crop['box'].setValue( l.attrs['t'], 3 ) crop.setInput(0, shuffle ) crop.setXYpos( curX, curY ) curY += spacing * 2 layer = crop merge = None try: operation = blendMap[ l.attrs['blendmode'] ] except: print("unknown blending mode " + l.attrs['blendmode']) operation = "normal" if lastLayer: psdMerge = nuke.nodes.PSDMerge() psdMerge['operation'].setValue( operation ) psdMerge.setInput(0, lastLayer ) psdMerge.setInput(1, layer ) psdMerge.setXYpos( curX, curY ) psdMerge['sRGB'].setValue( sRGB ) psdMerge['mix'].setValue( (l.attrs['opacity'] / 255.0) ) try: if ( l.attrs['mask/disable'] != True ): psdMerge['maskChannelInput'].setValue( name + '.mask' ) if ( l.attrs['mask/invert'] == True ) : psdMerge['invert_mask'].setValue( True ) except: pass lastLayer = psdMerge else: dot = nuke.nodes.Dot() dot.setInput( 0, layer ) dot.setXYpos( curX + dotXfudge, curY + dotYfudge ) lastLayer = dot curY += spacing backdrop['bdwidth'].setValue( xspacing * 2 + backdropXfudge * 2 + 50) backdrop['bdheight'].setValue( ( curY - backdrop.ypos() ) - backdropYfudge - 50 ) backdrop['label'].setValue( l.attrs['name'] ) curY += spacing curX = curX + xspacing * 2 + backdropXfudge * 2 + 50 if not sRGB: colorSpace2 = nuke.nodes.Colorspace() colorSpace2['channels'].setValue( 'all' ) colorSpace2['colorspace_in'].setValue( 'sRGB') colorSpace2.setInput(0, lastLayer ) colorSpace2.setXYpos( lastLayer.xpos(), lastLayer.ypos() + 2 * spacing ) nuke.Undo().end()
[docs]class BreakoutThreadClass(threading.Thread): def __init__(self, node): threading.Thread.__init__(self) self.node = node
[docs] def run(self): nuke.executeInMainThread( breakoutLayers, self.node )
[docs]def doReaderBreakout(): ## horrible workaround for Bug 24578 that doesn't allow creating gizmos from a script button global readerBreakoutThread readerBreakoutThread = BreakoutThreadClass( nuke.thisNode() ) readerBreakoutThread.start()