|
| 1 | +import nuke |
| 2 | +import os |
| 3 | +import re |
| 4 | + |
| 5 | + |
| 6 | +class RenderWrite(object): |
| 7 | + def __init__(self, path=''): |
| 8 | + self.path = path |
| 9 | + |
| 10 | + def read_path(self): |
| 11 | + nuke.createNode("Read").knob("file").setValue(self.path) |
| 12 | + |
| 13 | + def search_for_in_string(self, string, searchPattern): |
| 14 | + # Look for %04d |
| 15 | + reMatch = re.search(searchPattern, string) |
| 16 | + # if reMatch: |
| 17 | + # print('reMatch for ' + string + ': ' + str(reMatch) ) |
| 18 | + |
| 19 | + return reMatch |
| 20 | + |
| 21 | + def evaluate_filepath(self): |
| 22 | + # Fetch the filename as-is (possibly containing expressions) |
| 23 | + selectedNodeFilePathRAW = nuke.selectedNode()['file'].getValue() |
| 24 | + padding = '%04d' |
| 25 | + file_extension = os.path.splitext(selectedNodeFilePathRAW)[1] |
| 26 | + filepath_to_evaluate = '' |
| 27 | + |
| 28 | + # Are we using a padding? - if so, lets not evaluate that |
| 29 | + padding_in_use = False |
| 30 | + if padding in selectedNodeFilePathRAW: |
| 31 | + padding_in_use = True |
| 32 | + |
| 33 | + if padding_in_use: |
| 34 | + # Temporarily remove padding and file type extension from Write node |
| 35 | + filepath_to_evaluate = selectedNodeFilePathRAW[: selectedNodeFilePathRAW.rfind(padding)] |
| 36 | + nuke.selectedNode()['file'].setValue(filepath_to_evaluate) |
| 37 | + |
| 38 | + # Evaluate filepath in Write node |
| 39 | + filepath_evaluated = nuke.selectedNode()['file'].evaluate() |
| 40 | + |
| 41 | + if padding_in_use: |
| 42 | + # Put back padding and file type extension into evaluated filepath of Write node |
| 43 | + filepath_evaluated = filepath_evaluated + padding + file_extension |
| 44 | + nuke.selectedNode()['file'].setValue(filepath_evaluated) |
| 45 | + |
| 46 | + return filepath_evaluated |
| 47 | + |
| 48 | + def check_for_fileknob(self): |
| 49 | + try: |
| 50 | + selectedNodeFilePath = nuke.selectedNode()['file'].evaluate() |
| 51 | + error = False |
| 52 | + except ValueError: |
| 53 | + error = True |
| 54 | + nuke.message('No (Write) node selected.') |
| 55 | + except NameError: |
| 56 | + error = True |
| 57 | + nuke.message('You must select a Write node.') |
| 58 | + |
| 59 | + return error |
| 60 | + |
| 61 | + # Creates a Read node from the selected Write node |
| 62 | + def read_from_write(self): |
| 63 | + # Check for a file knob... |
| 64 | + error = self.check_for_fileknob() |
| 65 | + |
| 66 | + # If a Write node has been selected, let's go on! |
| 67 | + if not error: |
| 68 | + |
| 69 | + # Grab the interesting stuff from the write node and double check we actually selected a Write node... |
| 70 | + selectedNodeName = nuke.selectedNode().name() |
| 71 | + selectedNodeFilePath = self.evaluate_filepath() |
| 72 | + selectedNodePremult = str(nuke.selectedNode()['premultiplied'].getValue()) |
| 73 | + selectedNodeXpos = nuke.selectedNode().xpos() |
| 74 | + selectedNodeYpos = nuke.selectedNode().ypos() |
| 75 | + |
| 76 | + # Split filepath into list |
| 77 | + filePathSplitted = str.split(selectedNodeFilePath, '/') |
| 78 | + |
| 79 | + # Get filetype |
| 80 | + filePathSplittedDots = str.split(selectedNodeFilePath, '.') |
| 81 | + filetype = filePathSplittedDots[len(filePathSplittedDots) - 1] |
| 82 | + |
| 83 | + filePath = '' |
| 84 | + # File path to write node's target folder |
| 85 | + for i in range(0, len(filePathSplitted) - 1): |
| 86 | + filePath = filePath + filePathSplitted[i] + '/' |
| 87 | + |
| 88 | + # Filename taken from Write node |
| 89 | + filename = filePathSplitted[len(filePathSplitted) - 1] |
| 90 | + |
| 91 | + # Debug |
| 92 | + # print('Write node says: ' + filename) |
| 93 | + |
| 94 | + # Let's look for #### or %04d |
| 95 | + searchPattern = '(#+)|(%\d\d?d)' |
| 96 | + frameRangeFound = self.search_for_in_string(filename, searchPattern) |
| 97 | + |
| 98 | + # If framerange was not found we assume we are dealing with a movie file or a single image file |
| 99 | + if not frameRangeFound: |
| 100 | + # Create the read node |
| 101 | + node = nuke.createNode("Read", "file " + selectedNodeFilePath) |
| 102 | + |
| 103 | + # Nicely placement of nodes |
| 104 | + node.setXpos(selectedNodeXpos) |
| 105 | + node.setYpos(selectedNodeYpos + 60) |
| 106 | + |
| 107 | + # Was it premultiplied? |
| 108 | + node.knob('premultiplied').fromScript(selectedNodePremult) |
| 109 | + |
| 110 | + |
| 111 | + |
| 112 | + # If framerange was found, we need to start getting clever |
| 113 | + else: |
| 114 | + |
| 115 | + # Split the filname into what's before and after the framerange |
| 116 | + sourcePrefix, sourceSuffix = filename.split('.%04d.') |
| 117 | + |
| 118 | + # Debug |
| 119 | + # print('We are looking for: ' + sourcePrefix + ' of type ' + filetype) |
| 120 | + # print('Look for them in directory: ' + filePath) |
| 121 | + |
| 122 | + |
| 123 | + # See if we can list the folder's files |
| 124 | + if os.path.exists(nuke.callbacks.filenameFilter(filePath)): |
| 125 | + # List the contents of the folder |
| 126 | + files = os.listdir(nuke.callbacks.filenameFilter(filePath)) |
| 127 | + else: |
| 128 | + nuke.message('Folder path not found:\n' + filePath) |
| 129 | + error = True |
| 130 | + |
| 131 | + # Setting some defaults |
| 132 | + framerangeFound = False |
| 133 | + firstFrame = 'Not set' |
| 134 | + lastFrame = 'Not set' |
| 135 | + fileFound = False |
| 136 | + |
| 137 | + if error == False: |
| 138 | + |
| 139 | + for file in files: |
| 140 | + |
| 141 | + # Search for the occurance of a four digit number surrounded by period signs |
| 142 | + reMatch = re.search('\.[0-9][0-9][0-9][0-9]\.', file) |
| 143 | + if reMatch: |
| 144 | + # print('reMatch for ' + file + ': ' + str(reMatch) + ': ' + reMatch.group(0) ) |
| 145 | + targetPrefix, targetSuffix = file.split(reMatch.group(0)) |
| 146 | + |
| 147 | + if sourcePrefix == targetPrefix: |
| 148 | + fileFound = True |
| 149 | + framerangeFound = True |
| 150 | + # print(file + ' seems to be related to filename ' + sourcePrefix + '.####.' + sourceSuffix) |
| 151 | + |
| 152 | + dump, frame, dump = reMatch.group(0).split('.') |
| 153 | + |
| 154 | + if firstFrame == 'Not set': |
| 155 | + firstFrame = frame |
| 156 | + else: |
| 157 | + lastFrame = frame |
| 158 | + |
| 159 | + if fileFound == True: |
| 160 | + |
| 161 | + # Change %04d to #### |
| 162 | + selectedNodeFilePath = str.replace(selectedNodeFilePath, '%04d', '####') |
| 163 | + |
| 164 | + # Create the Read node |
| 165 | + node = nuke.createNode("Read", "file " + selectedNodeFilePath) |
| 166 | + |
| 167 | + # Check for framerange, and if not found use the frameranges from the project settings |
| 168 | + if framerangeFound == False: |
| 169 | + # Long shot guess for framerange (from settings) |
| 170 | + firstFrame = str(int(nuke.root()['first_frame'].getValue())) |
| 171 | + lastFrame = str(int(nuke.root()['last_frame'].getValue())) |
| 172 | + node.knob('first').fromScript(firstFrame) |
| 173 | + node.knob('last').fromScript(lastFrame) |
| 174 | + |
| 175 | + # Set the framerange |
| 176 | + node.knob('first').fromScript(firstFrame) |
| 177 | + node.knob('last').fromScript(lastFrame) |
| 178 | + |
| 179 | + # Nicely placement of nodes |
| 180 | + node.setXpos(selectedNodeXpos) |
| 181 | + node.setYpos(selectedNodeYpos + 60) |
| 182 | + |
| 183 | + # Was it premultiplied? |
| 184 | + node.knob('premultiplied').fromScript(selectedNodePremult) |
| 185 | + |
| 186 | + # Debug |
| 187 | + # print('Read node created for ' + filename) |
| 188 | + |
| 189 | + # Some warning messages |
| 190 | + |
| 191 | + # If the Write node has not rendered any files to load |
| 192 | + if fileFound == False: |
| 193 | + nuke.message('Render file/s not found, seems like you forgot to render them out.') |
| 194 | + |
| 195 | + # If no framerange was found from an image sequence |
| 196 | + elif framerangeFound == False: |
| 197 | + nuke.message( |
| 198 | + 'I was unable to figure out the frame range and guessed it was ' + firstFrame + '-' + lastFrame + ', based on the project settings. Please check it manually.') |
0 commit comments