def getFrameList(fileKnob, existingFilePaths):
    '''
    Return a list of frames that are part of the sequence that fileKnob is pointing to.
    If the file path is already in existingFilePaths it will not be included.
    '''
    node = fileKnob.node()
    originalCacheMode = node['cacheLocal'].value()
    node['cacheLocal'].setValue('never')

    frameRange = nuke.FrameRange(node.firstFrame(), node.lastFrame(), 1)
    outputContext = nuke.OutputContext()

    frameList = []
    # Cycle over views
    for viewNumber in xrange(outputContext.viewcount()):
        viewName = outputContext.viewname(viewNumber)
        # Skip "default" view
        if viewName not in nuke.views():
            continue

        # Set context to viewNumber
        outputContext.setView(viewNumber)

        # Cycle over frame range
        for frameNumber in frameRange:
            outputContext.setFrame(frameNumber)
            filePath = fileKnob.getEvaluatedValue(outputContext)
            if filePath not in existingFilePaths:
                frameList.append(filePath)

    node['cacheLocal'].setValue("always")
    #########node['cacheLocal'].setValue(originalCacheMode) my fix
    return frameList
Exemple #2
0
    def _addViewKnob(self):
        oc = nuke.OutputContext()
        self._views = [oc.viewname(i) for i in xrange(1, oc.viewcount())]
        if (oc.viewcount() > 2):
            supportedViews = self._selectedFlipbook().capabilities(
            )["maximumViews"]
            if (int(supportedViews) > 1):
                self._viewSelection = nuke.MultiView_Knob("views", "Views")
            else:
                self._viewSelection = nuke.OneView_Knob(
                    "views", "View", self._views)
            activeView = nuke.activeViewer().view()
            if activeView == "":
                activeView = self._views[0]

            # Retrieve previous view selection or default to selecting all available views
            previousViews = self._state.getValue(
                self._viewSelection.name(), " ".join(self._views)).split()
            # Get the intersection of the previous selection and the available views
            viewsToRestore = set(self._views).intersection(previousViews)
            if viewsToRestore:
                self._viewSelection.setValue(" ".join(viewsToRestore))
            else:
                self._viewSelection.setValue(activeView)
            self.addKnob(self._viewSelection)
            self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
 def _addViewKnob(self):
     """Add knobs for view selection."""
     oc = nuke.OutputContext()
     if (oc.viewcount() > 2):
         self._viewSelection = nuke.MultiView_Knob("multi_view", "Views")
         self._viewSelection.fromScript(
             self._state.get(self._viewSelection, self._getDefaultViews()))
         self.addKnob(self._viewSelection)
         self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
    def _performCleanup(self):
        """ Remove temporary files created by a previous capture.
    """
        outputContext = nuke.OutputContext()
        fileKnob = self._viewer['file']

        frameList = self._frameRange.toFrameList()
        for frame in frameList:
            outputContext.setFrame(frame)
            fileName = fileKnob.getEvaluatedValue(outputContext)

            if os.access(fileName, os.F_OK):
                os.remove(fileName)
Exemple #5
0
def get_matrix_at_frame(node, frame):
    """ Calculate a matrix for a Transform, Tracker4 or CornerPin2D node at a given frame

    :param nuke.Node node: Node to extract the matrix from
    :param int frame: Frame number
    :return: a 4x4 matrix
    """
    matrix = None
    if node.Class() == 'Transform' or node.Class() == 'Tracker4':
        k = node.knob('matrix')
        context = nuke.OutputContext()
        context.setFrame(frame)
        matrix = k.value(context)
    elif node.Class() == 'CornerPin2D':
        # Calculate 'to' matrix
        to_matrix = nuke.math.Matrix4()
        to1x = node['to1'].getValueAt(frame)[0]
        to1y = node['to1'].getValueAt(frame)[1]
        to2x = node['to2'].getValueAt(frame)[0]
        to2y = node['to2'].getValueAt(frame)[1]
        to3x = node['to3'].getValueAt(frame)[0]
        to3y = node['to3'].getValueAt(frame)[1]
        to4x = node['to4'].getValueAt(frame)[0]
        to4y = node['to4'].getValueAt(frame)[1]
        to_matrix.mapUnitSquareToQuad(to1x, to1y, to2x, to2y, to3x, to3y, to4x, to4y)
        # Calculate 'from' matrix
        from_matrix = nuke.math.Matrix4()
        from1x = node['from1'].getValueAt(frame)[0]
        from1y = node['from1'].getValueAt(frame)[1]
        from2x = node['from2'].getValueAt(frame)[0]
        from2y = node['from2'].getValueAt(frame)[1]
        from3x = node['from3'].getValueAt(frame)[0]
        from3y = node['from3'].getValueAt(frame)[1]
        from4x = node['from4'].getValueAt(frame)[0]
        from4y = node['from4'].getValueAt(frame)[1]
        from_matrix.mapUnitSquareToQuad(from1x, from1y, from2x, from2y, from3x, from3y, from4x, from4y)
        # Calculate the extra matrix
        k = node.knob('transform_matrix')
        values = k.getValueAt(frame)
        extra_matrix = nuke.math.Matrix4()
        for index in range(len(values)):
            extra_matrix[index] = values[index]
        extra_matrix.transpose()

        matrix = extra_matrix * (to_matrix * from_matrix.inverse())

        if node['invert'].getValueAt(frame):
            matrix = matrix.inverse()

    return matrix
 def _addViewKnob(self):
     oc = nuke.OutputContext()
     self._views = [oc.viewname(i) for i in xrange(1, oc.viewcount())]
     if (oc.viewcount() > 2):
         supportedViews = self._selectedFlipbook().capabilities(
         )["maximumViews"]
         if (int(supportedViews) > 1):
             self._viewSelection = nuke.MultiView_Knob("views", "Views")
         else:
             self._viewSelection = nuke.OneView_Knob(
                 "views", "View", self._views)
         activeView = nuke.activeViewer().view()
         if activeView == "":
             activeView = self._views[0]
         self._state.setKnob(self._viewSelection, activeView)
         self.addKnob(self._viewSelection)
         self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
Exemple #7
0
    def get_matrix_at_frame(node, frame):
        matrix = None
        if node.Class() == 'Transform' or node.Class() == 'Tracker4':
            k = node.knob('matrix')
            context = nuke.OutputContext()
            context.setFrame(frame)
            matrix = k.value(context)
        elif node.Class() == 'CornerPin2D':
            # Calculate 'to' matrix
            to_matrix = nuke.math.Matrix4()
            to1x = node['to1'].getValueAt(frame)[0]
            to1y = node['to1'].getValueAt(frame)[1]
            to2x = node['to2'].getValueAt(frame)[0]
            to2y = node['to2'].getValueAt(frame)[1]
            to3x = node['to3'].getValueAt(frame)[0]
            to3y = node['to3'].getValueAt(frame)[1]
            to4x = node['to4'].getValueAt(frame)[0]
            to4y = node['to4'].getValueAt(frame)[1]
            to_matrix.mapUnitSquareToQuad(to1x, to1y, to2x, to2y, to3x, to3y,
                                          to4x, to4y)
            # Calculate 'to' matrix
            from_matrix = nuke.math.Matrix4()
            from1x = node['from1'].getValueAt(frame)[0]
            from1y = node['from1'].getValueAt(frame)[1]
            from2x = node['from2'].getValueAt(frame)[0]
            from2y = node['from2'].getValueAt(frame)[1]
            from3x = node['from3'].getValueAt(frame)[0]
            from3y = node['from3'].getValueAt(frame)[1]
            from4x = node['from4'].getValueAt(frame)[0]
            from4y = node['from4'].getValueAt(frame)[1]
            from_matrix.mapUnitSquareToQuad(from1x, from1y, from2x, from2y,
                                            from3x, from3y, from4x, from4y)
            # Calculate the extra matrix
            k = node.knob('transform_matrix')
            values = k.getValueAt(frame)
            extra_matrix = nuke.math.Matrix4()
            for i in xrange(len(values)):
                extra_matrix[i] = values[i]
            extra_matrix.transpose()

            matrix = extra_matrix * (to_matrix * from_matrix.inverse())

            if node['invert'].getValueAt(frame):
                matrix = matrix.inverse()

        return matrix
 def _selectedViews(self):
     try:
         return self._viewSelection.value().split()
     except AttributeError:
         # If we didn't add the view selection knob, there should be just the one view.
         return [nuke.OutputContext().viewname(1)]
 def _getDefaultViews(self):
     oc = nuke.OutputContext()
     allViews = [oc.viewname(i) for i in xrange(1, oc.viewcount())]
     return " ".join(allViews)
Exemple #10
0
	def __init__(self, afnode, wnode, subblock, prefix, fparams):
		if VERBOSE == 2:
			print('Initializing block parameters for "%s"' % wnode.name())
		self.wnode = wnode
		self.valid = True

		self.subblock = subblock
		self.prefix = prefix

		self.framefirst = nuke.root().firstFrame()
		self.framelast = nuke.root().lastFrame()
		self.frameinc = 1
		self.framespertask = 1
		self.framesequential = 1
		self.skipexisting = 0
		self.maxhosts = -1
		self.capacity = -1
		self.maxperhost = -1
		self.maxruntime = -1
		self.hostsmask = None
		self.hostsmaskexclude = None
		self.fullrangedepend = 0
		self.tmpimage = 1
		self.pathsmap = 1
		self.imgfiles = []
		if afnode is not None:
			self.framefirst = int(afnode.knob('framefirst').value())
			self.framelast = int(afnode.knob('framelast').value())
			self.frameinc = int(afnode.knob('frameinc').value())
			self.framespertask = int(afnode.knob('framespertask').value())
			self.framesequential = int(afnode.knob('framesequential').value())
			self.skipexisting = int(afnode.knob('skipexisting').value())
			self.maxhosts = int(afnode.knob('maxhosts').value())
			self.capacity = int(afnode.knob('capacity').value())
			self.maxperhost = int(afnode.knob('maxperhost').value())
			self.maxruntime = int(afnode.knob('maxruntime').value())
			self.tmpimage = int(afnode.knob('tmpimage').value())
			self.pathsmap = int(afnode.knob('pathsmap').value())
			self.hostsmask = afnode.knob('hostsmask').value()
			self.hostsmaskexclude = afnode.knob('hostsmaskexcl').value()

		if self.skipexisting: self.framespertask = 1

		self.writename = str(wnode.fullName())

		if wnode.Class() == RenderNodeClassName:
			afcommon = __import__('afcommon', globals(), locals(), [])
			# Get images files:
			if nuke.toNode('root').knob('proxy').value():
				fileknob = wnode.knob('proxy')
			else:
				fileknob = wnode.knob('file')

			# Get views:
			views = wnode.knob('views')
			if views is not None:
				views = views.value()
				if views is None or views == '':
					views = nuke.views()
				else:
					views = views.split(' ')
			else:
				views = nuke.views()

			# Iterate views:
			for view in views:
				view = view.strip()
				if not len(view):
					continue  # skip empty view, may be after split(' ')

				# Check view exists:
				if not view in nuke.views():
					print('Error: Skipping invalid view: "%s"' % view)
					continue

					# if len( self.imgfiles):
				# self.imgfiles += ';'

				# Get show files for current view and first and last frames:
				octx = nuke.OutputContext()
				octx.setView(1 + nuke.views().index(view))
				octx_framefirst = self.framefirst
				octx_framelast = self.framelast
				if octx_framefirst < 0:
					octx_framefirst = 0
				if octx_framelast < 0:
					octx_framelast = 0

				# If frame first and frame last are equal no sequence needed
				if octx_framefirst == octx_framelast:
					octx.setFrame(octx_framefirst)
					self.imgfiles.append(fileknob.getEvaluatedValue(octx))
				else:
					# Get files from first and last frames
					# to calculate frames pattern:
					octx.setFrame(octx_framefirst)
					images1 = fileknob.getEvaluatedValue(octx)
					if images1 is None or images1 == '':
						nuke.message(
							'Error:\n'
							'%s\n'
							'Files are empty.\n'
							'View "%s", frame %d.' %
							(self.writename, view, self.framefirst)
						)
						self.valid = False
						return
					octx.setFrame(octx_framelast)
					images2 = fileknob.getEvaluatedValue(octx)
					if images2 is None or images2 == '':
						nuke.message(
							'Error:\n'
							'%s\n'
							'Files are empty.\n'
							'View "%s", frame %d.' %
							(self.writename, view, self.framelast)
						)
						self.valid = False
						return
					part1, padding, part2 = \
						afcommon.splitPathsDifference(images1, images2)

					if padding < 1:
						nuke.message(
							'Error:\n'
							'%s\n'
							'Invalid files pattern.\n'
							'View "%s".' %
							(self.writename, view)
						)
						self.valid = False
						return
					self.imgfiles.append(
						'%s@%s@%s' % (part1, '#' * padding, part2)
					)

			# Check images folders:
			for imgfile in self.imgfiles:
				folder = os.path.dirname(imgfile)
				if folder != '':
					if not os.path.isdir(folder):
						result = nuke.ask(
							'Write Node "%s" Directory\n'
							'%s\n'
							'Does not exist.\n'
							'Create it?' % (self.writename, folder)
						)
						if result:
							os.makedirs(folder)
							if not os.path.isdir(folder):
								nuke.message(
									"Can't create folder:\n%s" % folder
								)
								self.valid = False
						else:
							self.valid = False
		elif wnode.Class() == DailiesNodeClassName:
			if VERBOSE:
				print('Generating dailies "%s"' % self.writename)
		else:
			nuke.message('Node type\n"%s"\nis unsendable.' % self.writename)
			self.valid = False

		for par in fparams:
			if fparams[par] is not None:
				if hasattr(self, par):
					setattr(self, par, fparams[par])

		self.name = self.writename
		if subblock:
			if self.prefix is not None:
				if self.prefix != '':
					self.name = self.prefix + self.name

		self.dependmask = ''
		self.tasksdependmask = ''
Exemple #11
0
def dailiesGenCmd(node):
    # Process Input Node:
    inputnode = None
    for i in range(node.inputs()):
        inputnode = node.input(i)
    if inputnode is None:
        nuke.message('Error:\n'
                     '%s\n'
                     'Not connected to Read or Write node.' % node.name())
        return
    if not inputnode.Class() in ['Read', 'Write']:
        nuke.message('Error:\n'
                     '%s\n'
                     'Connected not to Read or Write node.' % node.name())
        return

    # Process Images:
    images = ''
    root_frame_first = nuke.Root().firstFrame()
    root_frame_last = nuke.Root().lastFrame()
    if root_frame_first == root_frame_last:
        root_frame_last += 100

    # Get needed views from dailies node if forced:
    if node.knob('forceviews').value():
        views = node.knob('viewsnames').value().split(' ')
    else:
        # Get needed views write node:
        views_knob = inputnode.knob('views')
        if views_knob is not None:
            views = inputnode.knob('views').value().split(' ')
        else:
            # Get all scene views:
            views = nuke.views()

    # Generate input pattern from each view:
    for view in views:
        if not len(view):
            continue  # skip empty view, may be after split(' ')

        if not view in nuke.views():
            print('Error: Skipping invalid view: "%s"' % view)
            continue

        octx = nuke.OutputContext()
        octx.setView(1 + nuke.views().index(view))
        octx.setFrame(root_frame_first)
        images1 = inputnode.knob('file').getEvaluatedValue(octx)
        if images1 is None or images1 == '':
            nuke.message('Error:\n'
                         '%s\n'
                         'Files are empty.\n'
                         'View "%s", frame %d.' %
                         (inputnode.name(), view, root_frame_first))
            return

        octx.setFrame(root_frame_last)
        images2 = inputnode.knob('file').getEvaluatedValue(octx)
        if images2 is None or images2 == '':
            nuke.message('Error:\n'
                         '%s\n'
                         'Files are empty.\n'
                         'View "%s", frame %d.' %
                         (inputnode.name(), view, root_frame_last))
            return
        part1, padding, part2 = afcommon.splitPathsDifference(images1, images2)
        if padding < 1:
            nuke.message('Error:\n'
                         '%s\Invalid files pattern.\n'
                         'View "%s".' % (inputnode.name(), view))
            return
        if len(images):
            images += ' '

        images += '%s%s%s' % (part1, '#' * padding, part2)

    if images == '':
        nuke.message('Error:\n%s\No valid views found.' % inputnode.name())
        return

    # Get Movie Name:
    movname = node.knob('movname').value()
    if movname is None or movname == '':
        nuke.message('Error:\n%s\nMovie name is not set.' % node.name())
        return

    # Get Movie Folder:
    movfolder = node.knob('movfolder').getEvaluatedValue()
    if movfolder is None or movfolder == '':
        nuke.message('Error:\n%s\nMovie folder is not set.' % node.name())
        return

    # Get Parameters:
    format = node.knob('format').value()
    fps = node.knob('fps').value()
    codec = node.knob('codec').value()
    template = node.knob('template').getEvaluatedValue()
    slate = node.knob('slate').getEvaluatedValue()
    company = node.knob('company').value()
    project = node.knob('project').value()
    shot = node.knob('shot').value()
    version = node.knob('version').value()
    artist = node.knob('artist').value()
    activity = node.knob('activity').value()
    comments = node.knob('comments').value()
    cach_op = node.knob('cach_op').value()
    line_clr = node.knob('line_clr').value()
    draw169 = node.knob('draw169').value()
    draw235 = node.knob('draw235').value()
    line169 = node.knob('line169').value()
    line235 = node.knob('line235').value()
    lgspath = node.knob('lgspath').getEvaluatedValue()
    lgfpath = node.knob('lgfpath').getEvaluatedValue()
    lgsgrav = node.knob('lgsgrav').value()
    lgfgrav = node.knob('lgfgrav').value()
    lgssize = int(node.knob('lgssize').value())
    lgfsize = int(node.knob('lgfsize').value())
    fstart = int(node.knob('fstart').value())
    fend = int(node.knob('fend').value())
    fffirst = int(node.knob('fffirst').value())
    faketime_on = int(node.knob('faketime_on').value())
    faketime_str = node.knob('faketime_str').value()
    encodeonly = node.knob('encodeonly').value()
    tmpformat = node.knob('tmpformat').value()
    tmpquality = node.knob('tmpquality').value()
    autocolorspace = int(node.knob('autocolorspace').value())
    asp_in = float(node.knob('asp_in').value())
    gamma = float(node.knob('gamma').value())
    cach_as = float(node.knob('cach_as').value())
    line_as = float(node.knob('line_as').value())

    # Command Construction:
    cmd = os.environ['CGRU_LOCATION']
    cmd = os.path.join(cmd, 'utilities')
    cmd = os.path.join(cmd, 'moviemaker')
    cmd = os.path.join(cmd, 'makemovie.py')
    cmd = 'python ' + cmd

    cmd += ' -f "%s"' % fps
    cmd += ' -c "%s"' % codec

    if faketime_on and faketime_str is not None and faketime_str != '':
        cmd += ' --faketime %d' % \
            int(time.mktime(time.strptime(faketime_str, TimeFromat)))

    if tmpformat is not None and tmpformat != '':
        cmd += ' --tmpformat "%s"' % tmpformat

    if tmpquality is not None and tmpquality != '':
        cmd += ' --tmpquality "%s"' % tmpquality

    if not autocolorspace:
        cmd += ' --noautocorr'

    if gamma != 1.0:
        cmd += ' -g %03f' % gamma

    if asp_in > 0.0:
        cmd += ' --aspect_in %f' % asp_in

    if fstart != -1:
        cmd += ' --fs %d' % fstart

    if fend != -1:
        cmd += ' --fe %d' % fend

    if fffirst:
        cmd += ' --fff'

    if not encodeonly:
        cmd += ' -r "%s"' % format
        if template is not None and template != '':
            cmd += ' -t "%s"' % template
        if slate is not None and slate != '':
            cmd += ' -s "%s"' % slate
        if company is not None and company != '':
            cmd += ' --company "%s"' % company
        if project is not None and project != '':
            cmd += ' --project "%s"' % project
        if shot is not None and shot != '':
            cmd += ' --shot "%s"' % shot
        if version is not None and version != '':
            cmd += ' --ver "%s"' % version
        if artist is not None and artist != '':
            cmd += ' --artist "%s"' % artist
        if activity is not None and activity != '':
            cmd += ' --activity "%s"' % activity
        if comments is not None and comments != '':
            cmd += ' --comments "%s"' % comments
        if draw169 is not None and draw169 != '':
            cmd += ' --draw169 "%s"' % draw169
        if draw235 is not None and draw235 != '':
            cmd += ' --draw235 "%s"' % draw235
        if line169 is not None and line169 != '':
            cmd += ' --line169 "%s"' % line169
        if line235 is not None and line235 != '':
            cmd += ' --line235 "%s"' % line235
        if line_clr is not None and line_clr != '':
            cmd += ' --line_aspect %f' % line_as
            cmd += ' --line_color "%s"' % line_clr
        if cach_op is not None and cach_op != '':
            cmd += ' --cacher_aspect %f' % cach_as
            cmd += ' --cacher_opacity "%s"' % cach_op
        if lgspath is not None and lgspath != '':
            cmd += ' --lgspath "%s"' % lgspath
            cmd += ' --lgssize %d' % lgssize
            cmd += ' --lgsgrav %s' % lgsgrav
        if lgfpath is not None and lgfpath != '':
            cmd += ' --lgfpath "%s"' % lgfpath
            cmd += ' --lgfsize %d' % lgfsize
            cmd += ' --lgfgrav %s' % lgfgrav
    if node.knob('stereodub').value():
        cmd += ' --stereo'

    cmd += ' ' + images
    cmd += ' ' + os.path.join(os.path.abspath(movfolder), movname)

    return cmd
Exemple #12
0
views_str = None
views = []
views_num = 0
try:
    views_str = writenode['views'].value()
    print('Views = "%s"' % views_str)
    for view in views_str.split(' '):
        view = view.strip()
        if view != '':
            if not view in nuke.views():
                print('Warning: Skipping invalid view: "%s"' % view)
                print(parser.str_warning)
                continue
            views_num += 1
            views.append(view)
            octx = nuke.OutputContext()
            octx.setView(1 + nuke.views().index(view))
            filename = fileknob.getEvaluatedValue(octx)
            imagesdirs.append(os.path.dirname(filename))
            filenames.append(filename)
except:
    errorExit(
        'Can`t process views on "%s" write node:\n' % xnode +
        str(sys.exc_info()[1]), True)
# Check for valid view founded:
if views_num < 1:
    errorExit('Can`t find valid views on "%s" write node.' % xnode, True)

# Check for multiview file (stereo EXR)
multiview_file = False
if views_num > 1:
Exemple #13
0
    def _createIntermediateNode(self):
        """Create a write node to render out the current node so that output may be used for flipbooking."""
        flipbooktmp = self._getIntermediatePath()

        fieldname = "file"
        if self._useProxy.value():
            fieldname = "proxy"

        fixup = nuke.createNode("Group",
                                "tile_color 0xff000000",
                                inpanel=False)
        with fixup:
            fixup.setName("Flipbook")
            inputNode = nuke.createNode("Input", inpanel=False)
            shuffle = nuke.createNode("Shuffle", inpanel=False)
            shuffle.knob("in").setValue(self._channels.value())
            if self._useRoi.value():
                crop = nuke.createNode("Crop", inpanel=False)
                crop['box'].fromScript(self._roi.toScript())
            write = nuke.createNode("Write",
                                    fieldname + " {" + flipbooktmp + "}",
                                    inpanel=False)
            write.knob('file_type').setValue(self._getIntermediateFileType())
            selectedViews = self._selectedViews()
            write.knob('views').fromScript(" ".join(selectedViews))

            if self._getIntermediateFileType() == "exr":
                write.knob('compression').setValue("B44")
                # Set the 'heroview' to be the first of the selected views. If we don't
                # do this then then 'heroview' is by default set to be 1 which may not
                # be a valid view for this clip. The 'heroview' is used as a fallback if
                # no view has been set on the reader. This assumes the user has selected
                # sensible views if they haven't then the write may still fail.
                if len(selectedViews) > 0:
                    firstView = nuke.OutputContext().viewFromName(
                        selectedViews[0])
                    write.knob('heroview').setValue(firstView)

            writeColorspace = ""

            if self._burnInLUT.value():
                # The user has chosen to burn the viewer transform into the intermedate render so set the colorspace
                # on the Write node appropriately.
                writeColorspace = self._getBurninWriteColorspace()
            else:
                # The viewer transform is not being burnt into the intermediate render, set the Write node's colorspace
                # to whatever the current working space is - when reading the file back in the flipbook we'll ssume
                # the media was written out in the working space.
                rootNode = nuke.root()
                if rootNode:
                    workingSpaceKnob = rootNode.knob("workingSpaceLUT")
                    if workingSpaceKnob:
                        writeColorspace = workingSpaceKnob.value()

            if writeColorspace:
                write.knob('colorspace').setValue(writeColorspace)

            outputNode = nuke.createNode("Output", inpanel=False)
        #If called on a Viewer connect fixup node to the one immediately above if exists.
        if self._node.Class() == "Viewer":
            fixup.setInput(
                0,
                self._node.input(
                    int(nuke.knob(self._node.fullName() + ".input_number"))))
        else:
            fixup.setInput(0, self._node)

        try:
            # Throws exception on render failure
            if (self.isBackgrounded()):
                nuke.executeBackgroundNuke(
                    nuke.EXE_PATH, [write],
                    nuke.FrameRanges(self._frameRange.value().split(',')),
                    self._selectedViews(), self._getBackgroundLimits(),
                    self._continueOnError.value(), self._flipbookEnum.value(),
                    self._getOptions(write))
            else:
                nuke.executeMultiple(
                    (write, ),
                    nuke.FrameRanges(self._frameRange.value().split(',')),
                    self._selectedViews(), self._continueOnError.value())
        except RuntimeError, msg:
            if msg.args[0][0:9] == "Cancelled":
                splitMsg = string.split(msg.args[0])

                msg = """Render did not complete, do you want to show the completed range?
Frame range %s contains %s frames but only %s finished.""" % (
                    self._frameRange.value(), splitMsg[3], splitMsg[1])
                if nuke.ask(msg) == False:
                    nuke.delete(fixup)
                    fixup = None
            else:
                nuke.delete(fixup)
                fixup = None
                nuke.message("Flipbook render failed:\n%s" % (msg.args[0], ))