Created
September 18, 2018 20:07
-
-
Save rafaelperez/f3fb3fc48688ac48cab702ba96970426 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import xml.etree.ElementTree as ET | |
import threading, re, struct, time | |
#Create the svg to roto class | |
class SvgRoto(threading.Thread): | |
def __init__(self, file, maxShapes=300, renderHidden=False): | |
threading.Thread.__init__(self) | |
#the file name | |
self.file = file | |
#list of all of the shapes | |
self.shapes = [] | |
#maximum number of shapes | |
self.maxShapes = maxShapes | |
#render hidden SVG groups | |
self.renderHidden = renderHidden | |
#load the SVG file | |
self._loadSVG() | |
#parse the SVG file | |
self._parseSVG(self.svg) | |
#update nuke progress and kill it if the bar is at 100% | |
def _updateProgress(self, progress, message=None): | |
if message: | |
self.progressBar.setMessage(message) | |
self.progressBar.setProgress(progress) | |
if progress == 100: | |
del(self.progressBar) | |
#execute in main thread | |
def execute(self, func, *kwargs): | |
nuke.executeInMainThread(func, kwargs) | |
#execute in main thread with results | |
def rexecute(self, func, *kwargs): | |
return nuke.executeInMainThreadWithResult(func, kwargs) | |
#apparently not needed as Nuke seems to accept float values for vertex positions, but will keep it here just in case something changes in the future | |
def float2Hex(self, val): | |
#return hex(struct.unpack('<I', struct.pack('f', val))[0]).replace('0x','x') | |
return str(val) | |
#draw the vector shapes | |
def draw(self): | |
#width and height of the SVG canvas | |
h = self.format.height() | |
w = self.format.width() | |
#create the RotoPaint node | |
self._createRotoNode() | |
#strings containing parts of the nodes for version 6 and for version 7 and above | |
if nuke.NUKE_VERSION_MAJOR > 6: | |
curvesStringTemplate = 'AddMode 0 0 0 0 {{v x3f99999a}\n {f 0}\n {n\n {layer Root\n {f 0}\n {t ROOT_POS_X ROOT_POS_Y}\n {a}\n SHAPE_STRINGS}}}}' | |
shapeStringTemplate = '{curvegroup SHAPE_NAME 512 bezier\n {{cc\n {f 8192}\n {px x41880000\nSHAPE_POINTS}} idem}\n {tx 0 SHAPE_POS_X SHAPE_POS_Y}\n {a vis 1 r RED g GREEN b BLUE a ALPHA str 1 ss 0}}' | |
else: | |
curvesStringTemplate = 'AddMode 0 1 0 7 Bezier1 AnimTree: "" {\n Version: 1.2\n Flag: 0\n RootNode: 1\n Node: {\n NodeName: "Root" {\n Flag: 512\n NodeType: 1\n Transform: 0 0 S 0 0 S 0 0 S 0 0 S 0 1 S 0 1 S 0 0 S 0 ROOT_POS_X S 0 ROOT_POS_Y \n NumOfAttributes: 11\n "vis" S 0 1 "opc" S 0 1 "mbo" S 0 1 "mb" S 0 1 "mbs" S 0 0.5 "fo" S 0 1 "fx" S 0 0 "fy" S 0 0 "ff" S 0 1 "ft" S 0 0 "pt" S 0 0 \n }\n NumOfChildren: NUM_SHAPES\n SHAPE_STRINGS\n }\n}' | |
shapeStringTemplate = 'Node: {\n NodeName: "SHAPE_NAME" {\n Flag: 576\n NodeType: 3\n CurveGroup: "" {\n Transform: 0 0 S 1 1 0 S 1 1 0 S 1 1 0 S 1 1 1 S 1 1 1 S 1 1 0 S 1 1 SHAPE_POS_X S 1 1 SHAPE_POS_Y \n Flag: 0\n NumOfCubicCurves: 2\n CubicCurve: "" {\n Type: 0 Flag: 8192 Dim: 2\n NumOfPoints: SHAPE_NUM_POINTS\n SHAPE_POINTS \n }\n CubicCurve: "" {\n Type: 0 Flag: 8192 Dim: 2\n NumOfPoints: SHAPE_NUM_POINTS\n FSHAPE_POINTS \n }\n NumOfAttributes: 44\n "vis" S 0 1 "r" S 0 RED "g" S 0 GREEN "b" S 0 BLUE "a" S 0 ALPHA "ro" S 0 0 "go" S 0 0 "bo" S 0 0 "ao" S 0 0 "opc" S 0 1 "bm" S 0 0 "inv" S 0 0 "mbo" S 0 0 "mb" S 0 1 "mbs" S 0 0.5 "mbsot" S 0 0 "mbso" S 0 0 "fo" S 0 1 "fx" S 0 0 "fy" S 0 0 "ff" S 0 1 "ft" S 0 0 "src" S 0 0 "stx" S 0 0 "sty" S 0 0 "str" S 0 0 "sr" S 0 0 "ssx" S 0 1 "ssy" S 0 1 "ss" S 0 0 "spx" S 0 1024 "spy" S 0 778 "stot" S 0 0 "sto" S 0 0 "sv" S 0 0 "sf" S 0 1 "sb" S 0 1 "nv" S 0 1 "view1" S 0 1 "ltn" S 0 1 "ltm" S 0 1 "ltt" S 0 0 "tt" S 0 4 "pt" S 0 0 \n }\n }\n NumOfChildren: 0\n }' | |
shapeStrings = '' | |
curvesString = curvesStringTemplate | |
cnt=0 | |
#iterate through the shapes and create the node | |
for shapeData in self.shapes: | |
shapeString = shapeStringTemplate | |
shapePoints = '' | |
fshapePoints = '' | |
#calculate the bounding box to get the center for the pivot | |
maxX = max(t[0] for t in shapeData['path'][0]) | |
minX = min(t[0] for t in shapeData['path'][0]) | |
centerX = minX+(maxX - minX)/2 | |
maxY = max(t[1] for t in shapeData['path'][0]) | |
minY = min(t[1] for t in shapeData['path'][0]) | |
centerY = h-(minY+(maxY - minY)/2) | |
#iterate through all the positions (points and tangents) and create the shape part of the node | |
for i in range(len(shapeData['path'][0])): | |
shapeData['path'][0][i] = (self.float2Hex(shapeData['path'][0][i][0]), self.float2Hex(h-shapeData['path'][0][i][1])) | |
shapeData['path'][1][i] = (self.float2Hex(shapeData['path'][1][i][0]), self.float2Hex(-shapeData['path'][1][i][1])) | |
shapeData['path'][2][i] = (self.float2Hex(shapeData['path'][2][i][0]), self.float2Hex(-shapeData['path'][2][i][1])) | |
if nuke.NUKE_VERSION_MAJOR > 6: | |
shapePoints += '\n {' + shapeData['path'][1][i][0] +' '+ shapeData['path'][1][i][1] + '}\n {' + shapeData['path'][0][i][0] +' '+ shapeData['path'][0][i][1] + '}\n {' + shapeData['path'][2][i][0] +' '+ shapeData['path'][2][i][1] + '}' | |
else: | |
shapePoints += '0 S 1 1 ' + shapeData['path'][1][i][0] +' S 1 1 '+ shapeData['path'][1][i][1] + ' 0 0 S 1 1 ' + shapeData['path'][0][i][0] +' S 1 1 '+ shapeData['path'][0][i][1] + ' 0 0 S 1 1 ' + shapeData['path'][2][i][0] +' S 1 1 '+ shapeData['path'][2][i][1] + ' 0 ' | |
fshapePoints += '0 S 1 1 ' + shapeData['path'][1][i][0] +' S 1 1 '+ shapeData['path'][1][i][1] + ' 0 0 S 1 1 0 S 1 1 0 0 0 S 1 1 ' + shapeData['path'][2][i][0] +' S 1 1 '+ shapeData['path'][2][i][1] + ' 0 ' | |
#replace all the strings (this could be replaced to use format instead of replace) | |
shapeString = shapeString.replace('SHAPE_NUM_POINTS', str(len(shapeData['path'][0])*3)) | |
shapeString = shapeString.replace('FSHAPE_POINTS', fshapePoints) | |
shapeString = shapeString.replace('SHAPE_POINTS', shapePoints) | |
shapeString = shapeString.replace('RED', self.float2Hex(shapeData['color'][0])) | |
shapeString = shapeString.replace('GREEN', self.float2Hex(shapeData['color'][1])) | |
shapeString = shapeString.replace('BLUE', self.float2Hex(shapeData['color'][2])) | |
shapeString = shapeString.replace('ALPHA', self.float2Hex(shapeData['color'][3])) | |
shapeString = shapeString.replace('SHAPE_NAME', 'Shape'+str(cnt)) | |
shapeString = shapeString.replace('SHAPE_POS_X', str(centerX)) | |
shapeString = shapeString.replace('SHAPE_POS_Y', str(centerY)) | |
shapeStrings = shapeString + shapeStrings | |
cnt += 1 | |
#replace the root node position and append the shapes | |
curvesString = curvesString.replace('ROOT_POS_X', str(w/2.0)).replace('ROOT_POS_Y', str(h/2.0)) | |
curvesString = curvesString.replace('SHAPE_STRINGS', shapeStrings) | |
curvesString = curvesString.replace('NUM_SHAPES', str(len(self.shapes))) | |
#update the progress bar | |
self._updateProgress(99, 'Creating Shapes') | |
#create the node | |
self.curves.fromScript(curvesString) | |
#set the svg format (will take into account only pixel dimensions not relative ones like pt or em) | |
def _setFormat(self): | |
format = None | |
#first try finding the width/height attributes | |
try: | |
w, h = [int(round(float(self.svg.attrib['width'].replace('px', '')))), int(round(float(self.svg.attrib['height'].replace('px', ''))))] | |
except Exception, err: | |
#if that fails, try with the viewBox | |
try: | |
view = [float(dimm) for dimm in self.svg.attrib['viewBox'].replace('px', '').split(' ')] | |
w, h = [int(round(view[2]-view[0])), int(round(view[3]-view[1]))] | |
#if that fails, put the nuke root format as format dimensions | |
except: | |
w, h = [nuke.Root().format().width(), nuke.Root().format().height()] | |
#create the format if it doesn't exist | |
for f in nuke.formats(): | |
if f.width() == w and f.height() == h: | |
format = f | |
break | |
if not format: | |
format = nuke.addFormat( str(w)+' '+str(h)+' 1.0 '+ str(w) + 'x' + str(h) ) | |
self.format = format | |
#load the SVG xml file | |
def _loadSVG(self): | |
xml = ET.parse(self.file) | |
root = xml.getroot() | |
self.xml = xml | |
self.svg = root | |
#set the svg format | |
self._setFormat() | |
#create the roto node | |
def _createRotoNode(self): | |
self.node = nuke.createNode('RotoPaint') | |
self.curves = self.node['curves'] | |
self.node['format'].setValue(self.format) | |
#convert hex color values to rgb | |
def _hex2rgb(self, value): | |
try: | |
value = value.lstrip('#') | |
lv = len(value) | |
if lv == 3: | |
value = ''.join([c*2 for c in list(value)]) | |
lv = len(value) | |
return tuple(int(value[i:i + lv // 3], 16)/255.0 for i in range(0, lv, lv // 3)) | |
except: | |
return (1,1,1) | |
#parse the SVG square shape | |
def _parseSVGSquare(self, node): | |
w = float(node.attrib['width']) | |
h = float(node.attrib['height']) | |
x = float(node.attrib['x']) if 'x' in node.keys() else 0 | |
y = float(node.attrib['y']) if 'y' in node.keys() else x | |
rx = float(node.attrib['rx']) if 'rx' in node.keys() else None | |
ry = float(node.attrib['ry']) if 'ry' in node.keys() else rx | |
if not rx: | |
rx = ry | |
#draw the SVG square shape | |
shape = self.squareShape(w, h, x, y, rx, ry) | |
#append results to the shapes list | |
self.shapes.append({'path':shape, 'color':self._getSVGNodeColor(node)}) | |
#parse the SVG circle shape | |
def _parseSVGCircle(self, node): | |
w = float(node.attrib['r']) | |
x = float(node.attrib['cx']) if 'cx' in node.keys() else 0 | |
y = float(node.attrib['cy']) if 'cy' in node.keys() else x | |
#draw the SVG circle shape | |
shape = self.ellipseShape(w, w, x=x,y=y) | |
#append results to the shapes list | |
self.shapes.append({'path':shape, 'color':self._getSVGNodeColor(node)}) | |
#parse the SVG ellipse shape | |
def _parseSVGEllipse(self, node): | |
w = float(node.attrib['rx']) | |
h = float(node.attrib['ry']) | |
x = float(node.attrib['cx']) if 'cx' in node.keys() else 0 | |
y = float(node.attrib['cy']) if 'cy' in node.keys() else x | |
#draw the SVG ellipse shape | |
shape = self.ellipseShape(w, h, x=x,y=y) | |
#append results to the shapes list | |
self.shapes.append({'path':shape, 'color':self._getSVGNodeColor(node)}) | |
#parse the SVG polygon shape | |
def _parseSVGPolygon(self, node): | |
path = self._tokenizeSVGCoords(node.attrib['points']) | |
pos = [] | |
ltan = [] | |
rtan = [] | |
for i in range(len(path)): | |
if i%2 == 0: | |
pos.append((path[i], path[i+1])) | |
ltan.append((0,0)) | |
rtan.append((0,0)) | |
#append results to the shapes list | |
self.shapes.append({'path':[pos, ltan, rtan], 'color':self._getSVGNodeColor(node)}) | |
#parse the path coordiantes and return a list of broken into commands and values | |
def _tokenizeSVGCoords(self, pathstring): | |
commands = 'MmZzLlHhVvCcSsQqTtAa' | |
commandsList = set(commands) | |
commandsRe = re.compile("(["+commands+"])") | |
valueRe = re.compile("[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?") | |
path = [] | |
for item in commandsRe.split(pathstring): | |
if item in commandsList: | |
path.append(item) | |
for value in valueRe.findall(item): | |
path.append(float(value)) | |
return path | |
#parse the SVG path shape | |
def _parseSVGPath(self, node): | |
#parse the path tokens, the arc token is not parsed, as it would take too much time to create the arc path command in nuke and it rarely used | |
#however if you want to do it feel free to write that piece of code :) | |
path = self._tokenizeSVGCoords(node.attrib['d']) | |
p0 = p1 = (0,0) | |
pos = [] | |
ltan = [] | |
rtan = [] | |
startPath = True | |
for i in range(len(path)): | |
if isinstance('m', basestring): | |
if path[i] in ['M', 'm']: | |
#start a path | |
if startPath: | |
startPath = False | |
alpha = False | |
else: | |
alpha = True | |
if path[i].istitle(): | |
p0 = (path[i+1], path[i+2]) | |
else: | |
p0 = (p0[0]+path[i+1], p0[1]+path[i+2]) | |
pos.append(p0) | |
ltan.append((0,0)) | |
rtan.append((0,0)) | |
elif path[i] in ['L', 'l']: | |
if path[i].istitle(): | |
p2 = (path[i+1], path[i+2]) | |
else: | |
p2 = (p0[0]+path[i+1], p0[1]+path[i+2]) | |
pos.append(p2) | |
ltan.append((0,0)) | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['H', 'h']: | |
if path[i].istitle(): | |
p2 = (path[i+1], p0[1]) | |
else: | |
p2 = (p0[0]+path[i+1], p0[1]) | |
pos.append(p2) | |
ltan.append((0,0)) | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['V', 'v']: | |
if path[i].istitle(): | |
p2 = (p0[0], path[i+1]) | |
else: | |
p2 = (p0[0], p0[1]+path[i+1]) | |
pos.append(p2) | |
ltan.append((0,0)) | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['C', 'c']: | |
if path[i].istitle(): | |
t1 = (path[i+1]-p0[0], path[i+2]-p0[1]) | |
p2 = (path[i+5], path[i+6]) | |
t2 = (path[i+3]-p2[0], path[i+4]-p2[1]) | |
else: | |
t1 = (path[i+1], path[i+2]) | |
p2 = (p0[0]+path[i+5], p0[1]+path[i+6]) | |
t2 = (path[i+3]-path[i+5], path[i+4]-path[i+6]) | |
pos.append(p2) | |
ltan.append(t2) | |
rtan[-1] = t1 | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['S', 's']: | |
if path[i].istitle(): | |
t1 = (-t2[0], -t2[1]) | |
p2 = (path[i+3], path[i+4]) | |
t2 = (path[i+1]-p2[0], path[i+2]-p2[1]) | |
else: | |
t1 = (-t2[0], -t2[1]) | |
p2 = (p0[0]+path[i+3], p0[1]+path[i+4]) | |
t2 = (path[i+1]-path[i+3], path[i+2]-path[i+4]) | |
pos.append(p2) | |
ltan.append(t2) | |
rtan[-1] = t1 | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['Q', 'q']: | |
if path[i].istitle(): | |
p1 = (path[i+1], path[i+2]) | |
p2 = (path[i+3], path[i+4]) | |
else: | |
p1 = (p0[0]+path[i+1], p0[1]+path[i+2]) | |
p2 = (p0[0]+path[i+3], p0[1]+path[i+4]) | |
t1x = p0[0] + 0.666 *(p1[0]-p0[0]) | |
t1y = p0[1] + 0.666 *(p1[1]-p0[1]) | |
t2x = p2[0] + 0.666 *(p1[0]-p2[0]) | |
t2y = p2[1] + 0.666 *(p1[1]-p2[1]) | |
t1 = (t1x-p0[0], t1y-p0[1]) | |
t2 = (t2x-p2[0],t2y-p2[1]) | |
pos.append(p2) | |
ltan.append(t2) | |
rtan[-1] = t1 | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['T', 't']: | |
if path[i].istitle(): | |
p2 = (path[i+1], path[i+2]) | |
else: | |
p2 = (p0[0]+path[i+1], p0[1]+path[i+2]) | |
t1 = (-t2[0], -t2[1]) | |
t2 = (-t2[1], t2[0]) | |
pos.append(p2) | |
ltan.append(t2) | |
rtan[-1] = t1 | |
rtan.append((0,0)) | |
p0 = p2 | |
elif path[i] in ['z','Z'] or i == len(path)-1: | |
self.shapes.append({'path':[pos,ltan,rtan], 'color':self._getSVGNodeColor(node, alpha=alpha)}) | |
pos = [] | |
ltan = [] | |
rtan = [] | |
if i == len(path)-1: | |
break | |
#get ellipse nuke coords | |
def ellipseShape(self, w,h, x=0,y=0): | |
pos = [(x,-h+y), (-w+x, y), (x,h+y), (w+x,y)] | |
ltan = [(w*0.55,0), (0,-h*0.55), (-w*0.55,0), (0,h*0.55)] | |
rtan = [(-w*0.55,0), (0,h*0.55), (w*0.55,0), (0,-h*0.55)] | |
return [pos, ltan, rtan] | |
#get square nuke coords | |
def squareShape(self, w,h, x=0,y=0, xr=0,yr=0): | |
if xr !=0 and yr ==0: | |
yr = xr | |
elif xr==0 and yr != 0: | |
xr = yr | |
if xr!=0 or yr!=0: | |
pos = [(x,y+yr), (x, y+h-yr), (x+xr,y+h),(x+w-xr,y+h), (x+w,y+h-yr), (x+w, y+yr), (x+w-xr, y), (x+xr, y)] | |
ltan = [(0, -yr/2), (0,0), (-xr/2, 0), (0,0), (0,yr/2), (0,0), (xr/2,0), (0,0)] | |
rtan = [(0,0), (0,yr/2), (0,0), (xr/2, 0), (0,0), (0,-yr/2), (0,0), (-xr/2,0)] | |
else: | |
pos = [(x,y), (x, y+h), (x+w,y+h), (x+w, y)] | |
ltan = [(0,0), (0,0), (0,0), (0,0), (0,0), (0,0), (0,0), (0,0)] | |
rtan = [(0,0), (0,0), (0,0), (0,0), (0,0), (0,0), (0,0), (0,0)] | |
return [pos, ltan, rtan] | |
#get svg node color, includes a list of web colors, alpha is defined based on the subpath, subpaths will have alpha to allow for holes, however the Nuke node will just make the whole through the alpha not just through the selected shape, so it will not work exactly like in the SVG file. | |
def _getSVGNodeColor(self, node, alpha = False): | |
webcolors = {'aliceblue':'#f0f8ff','antiquewhite':'#faebd7','aqua':'#00ffff','aquamarine':'#7fffd4','azure':'#f0ffff','beige':'#f5f5dc','bisque':'#ffe4c4','black':'#000000','blanchedalmond':'#ffebcd','blue':'#0000ff','blueviolet':'#8a2be2','brown':'#a52a2a','burlywood':'#deb887','cadetblue':'#5f9ea0','chartreuse':'#7fff00','chocolate':'#d2691e','coral':'#ff7f50','cornflowerblue':'#6495ed','cornsilk':'#fff8dc','crimson':'#dc143c','cyan':'#00ffff','darkblue':'#00008b','darkcyan':'#008b8b','darkgoldenrod':'#b8860b','darkgray':'#a9a9a9','darkgreen':'#006400','darkkhaki':'#bdb76b','darkmagenta':'#8b008b','darkolivegreen':'#556b2f','darkorange':'#ff8c00','darkorchid':'#9932cc','darkred':'#8b0000','darksalmon':'#e9967a','darkseagreen':'#8fbc8f','darkslateblue':'#483d8b','darkslategray':'#2f4f4f','darkturquoise':'#00ced1','darkviolet':'#9400d3','deeppink':'#ff1493','deepskyblue':'#00bfff','dimgray':'#696969','dodgerblue':'#1e90ff','firebrick':'#b22222','floralwhite':'#fffaf0','forestgreen':'#228b22','fuchsia':'#ff00ff','gainsboro':'#dcdcdc','ghostwhite':'#f8f8ff','gold':'#ffd700','goldenrod':'#daa520','gray':'#808080','green':'#008000','greenyellow':'#adff2f','honeydew':'#f0fff0','hotpink':'#ff69b4','indianred':'#cd5c5c','indigo':'#4b0082','ivory':'#fffff0','khaki':'#f0e68c','lavender':'#e6e6fa','lavenderblush':'#fff0f5','lawngreen':'#7cfc00','lemonchiffon':'#fffacd','lightblue':'#add8e6','lightcoral':'#f08080','lightcyan':'#e0ffff','lightgoldenrodyellow':'#fafad2','lightgray':'#d3d3d3','lightgreen':'#90ee90','lightpink':'#ffb6c1','lightsalmon':'#ffa07a','lightseagreen':'#20b2aa','lightskyblue':'#87cefa','lightslategray':'#778899','lightsteelblue':'#b0c4de','lightyellow':'#ffffe0','lime':'#00ff00','limegreen':'#32cd32','linen':'#faf0e6','magenta':'#ff00ff','maroon':'#800000','mediumaquamarine':'#66cdaa','mediumblue':'#0000cd','mediumorchid':'#ba55d3','mediumpurple':'#9370db','mediumseagreen':'#3cb371','mediumslateblue':'#7b68ee','mediumspringgreen':'#00fa9a','mediumturquoise':'#48d1cc','mediumvioletred':'#c71585','midnightblue':'#191970','mintcream':'#f5fffa','mistyrose':'#ffe4e1','moccasin':'#ffe4b5','navajowhite':'#ffdead','navy':'#000080','oldlace':'#fdf5e6','olive':'#808000','olivedrab':'#6b8e23','orange':'#ffa500','orangered':'#ff4500','orchid':'#da70d6','palegoldenrod':'#eee8aa','palegreen':'#98fb98','paleturquoise':'#afeeee','palevioletred':'#db7093','papayawhip':'#ffefd5','peachpuff':'#ffdab9','peru':'#cd853f','pink':'#ffc0cb','plum':'#dda0dd','powderblue':'#b0e0e6','purple':'#800080','red':'#ff0000','rosybrown':'#bc8f8f','royalblue':'#4169e1','saddlebrown':'#8b4513','salmon':'#fa8072','sandybrown':'#f4a460','seagreen':'#2e8b57','seashell':'#fff5ee','sienna':'#a0522d','silver':'#c0c0c0','skyblue':'#87ceeb','slateblue':'#6a5acd','slategray':'#708090','snow':'#fffafa','springgreen':'#00ff7f','steelblue':'#4682b4','tan':'#d2b48c','teal':'#008080','thistle':'#d8bfd8','tomato':'#ff6347','turquoise':'#40e0d0','violet':'#ee82ee','wheat':'#f5deb3','white':'#ffffff','whitesmoke':'#f5f5f5','yellow':'#ffff00','yellowgreen':'#9acd32','none':'#ffffff'} | |
val = '#000000' | |
if 'style' in node.keys(): | |
styles = dict([(style.split(':')[0].strip(), style.split(':')[1].strip()) for style in filter(None, node.attrib['style'].split(';'))]) | |
if 'fill' in styles.keys(): | |
val = styles['fill'] | |
elif 'fill' in node.keys(): | |
val = node.attrib['fill'] | |
if val.lower() in webcolors.keys(): | |
val = webcolors[val.lower()] | |
r,g,b = self._hex2rgb(val) | |
if alpha: | |
a = 0.0 | |
else: | |
a = 1.0 | |
return [r, g, b, a] | |
#set the color on the node | |
def setColor(self, shape, color): | |
try: | |
red, green, blue, alpha = color | |
shape.getAttributes().set('r', red) | |
shape.getAttributes().set('g', green) | |
shape.getAttributes().set('b', blue) | |
shape.getAttributes().set('a', alpha) | |
except Exception, err: | |
print err | |
#start parsing the SVG file | |
def _parseSVG(self, root): | |
for node in root: | |
alpha = False | |
if node.tag.split('}')[1] == 'g': | |
if 'display' in node.keys(): | |
if not node.attrib['display'] == 'none' or self.renderHidden: | |
self._parseSVG(node) | |
else: | |
self._parseSVG(node) | |
elif node.tag.split('}')[1] == 'rect': | |
self._parseSVGSquare(node) | |
elif node.tag.split('}')[1] == 'circle': | |
shape = self._parseSVGCircle(node) | |
elif node.tag.split('}')[1] == 'ellipse': | |
shape = self._parseSVGEllipse(node) | |
elif node.tag.split('}')[1] == 'polygon': | |
shape = self._parseSVGPolygon(node) | |
elif node.tag.split('}')[1] == 'path': | |
shape = self._parseSVGPath(node) | |
#run the script in a new thread | |
def run(self): | |
self.progressBar = nuke.ProgressTask('SVG RotoPaint') | |
self._updateProgress(1, 'SVG RotoPaint - Parsing the file') | |
self.rexecute( self.draw, ) | |
self._updateProgress(100, 'Finished') | |
file = nuke.getFilename('Load Svg to RotoPaint', '*.svg') | |
if file: | |
SvgRoto(file).run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment