The svg parser will incorrectly parse colors such as 'green' and 'red' to black. This commit fixes that by using the code already written in matplotlib.colors module
584 lines
22 KiB
Python
584 lines
22 KiB
Python
import torch
|
|
import xml.etree.ElementTree as etree
|
|
import numpy as np
|
|
import diffvg
|
|
import os
|
|
import pydiffvg
|
|
import svgpathtools
|
|
import svgpathtools.parser
|
|
import re
|
|
import warnings
|
|
import cssutils
|
|
import logging
|
|
import matplotlib.colors
|
|
cssutils.log.setLevel(logging.ERROR)
|
|
|
|
def remove_namespaces(s):
|
|
"""
|
|
{...} ... -> ...
|
|
"""
|
|
return re.sub('{.*}', '', s)
|
|
|
|
def parse_style(s, defs):
|
|
style_dict = {}
|
|
for e in s.split(';'):
|
|
key_value = e.split(':')
|
|
if len(key_value) == 2:
|
|
key = key_value[0].strip()
|
|
value = key_value[1].strip()
|
|
if key == 'fill' or key == 'stroke':
|
|
# Special case: convert colors into tensor in definitions so
|
|
# that different shapes can share the same color
|
|
value = parse_color(value, defs)
|
|
style_dict[key] = value
|
|
return style_dict
|
|
|
|
def parse_hex(s):
|
|
"""
|
|
Hex to tuple
|
|
"""
|
|
s = s.lstrip('#')
|
|
if len(s) == 3:
|
|
s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2]
|
|
rgb = tuple(int(s[i:i+2], 16) for i in (0, 2, 4))
|
|
# sRGB to RGB
|
|
# return torch.pow(torch.tensor([rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0]), 2.2)
|
|
return torch.pow(torch.tensor([rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0]), 1.0)
|
|
|
|
def parse_int(s):
|
|
"""
|
|
trim alphabets
|
|
"""
|
|
return int(float(''.join(i for i in s if (not i.isalpha()))))
|
|
|
|
def parse_color(s, defs):
|
|
if s is None:
|
|
return None
|
|
if isinstance(s, torch.Tensor):
|
|
return s
|
|
s = s.lstrip(' ')
|
|
color = torch.tensor([0.0, 0.0, 0.0, 1.0])
|
|
if s[0] == '#':
|
|
color[:3] = parse_hex(s)
|
|
elif s[:3] == 'url':
|
|
# url(#id)
|
|
color = defs[s[4:-1].lstrip('#')]
|
|
elif s == 'none':
|
|
color = None
|
|
elif s[:4] == 'rgb(':
|
|
rgb = s[4:-1].split(',')
|
|
color = torch.tensor([int(rgb[0]) / 255.0, int(rgb[1]) / 255.0, int(rgb[2]) / 255.0, 1.0])
|
|
elif s == 'none':
|
|
return None
|
|
else:
|
|
try :
|
|
rgba = matplotlib.colors.to_rgba(s)
|
|
color = torch.tensor(rgba)
|
|
except ValueError :
|
|
warnings.warn('Unknown color command ' + s)
|
|
return color
|
|
|
|
# https://github.com/mathandy/svgpathtools/blob/7ebc56a831357379ff22216bec07e2c12e8c5bc6/svgpathtools/parser.py
|
|
def _parse_transform_substr(transform_substr):
|
|
type_str, value_str = transform_substr.split('(')
|
|
value_str = value_str.replace(',', ' ')
|
|
values = list(map(float, filter(None, value_str.split(' '))))
|
|
|
|
transform = np.identity(3)
|
|
if 'matrix' in type_str:
|
|
transform[0:2, 0:3] = np.array([values[0:6:2], values[1:6:2]])
|
|
elif 'translate' in transform_substr:
|
|
transform[0, 2] = values[0]
|
|
if len(values) > 1:
|
|
transform[1, 2] = values[1]
|
|
elif 'scale' in transform_substr:
|
|
x_scale = values[0]
|
|
y_scale = values[1] if (len(values) > 1) else x_scale
|
|
transform[0, 0] = x_scale
|
|
transform[1, 1] = y_scale
|
|
elif 'rotate' in transform_substr:
|
|
angle = values[0] * np.pi / 180.0
|
|
if len(values) == 3:
|
|
offset = values[1:3]
|
|
else:
|
|
offset = (0, 0)
|
|
tf_offset = np.identity(3)
|
|
tf_offset[0:2, 2:3] = np.array([[offset[0]], [offset[1]]])
|
|
tf_rotate = np.identity(3)
|
|
tf_rotate[0:2, 0:2] = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]])
|
|
tf_offset_neg = np.identity(3)
|
|
tf_offset_neg[0:2, 2:3] = np.array([[-offset[0]], [-offset[1]]])
|
|
|
|
transform = tf_offset.dot(tf_rotate).dot(tf_offset_neg)
|
|
elif 'skewX' in transform_substr:
|
|
transform[0, 1] = np.tan(values[0] * np.pi / 180.0)
|
|
elif 'skewY' in transform_substr:
|
|
transform[1, 0] = np.tan(values[0] * np.pi / 180.0)
|
|
else:
|
|
# Return an identity matrix if the type of transform is unknown, and warn the user
|
|
warnings.warn('Unknown SVG transform type: {0}'.format(type_str))
|
|
return transform
|
|
|
|
def parse_transform(transform_str):
|
|
"""
|
|
Converts a valid SVG transformation string into a 3x3 matrix.
|
|
If the string is empty or null, this returns a 3x3 identity matrix
|
|
"""
|
|
if not transform_str:
|
|
return np.identity(3)
|
|
elif not isinstance(transform_str, str):
|
|
raise TypeError('Must provide a string to parse')
|
|
|
|
total_transform = np.identity(3)
|
|
transform_substrs = transform_str.split(')')[:-1] # Skip the last element, because it should be empty
|
|
for substr in transform_substrs:
|
|
total_transform = total_transform.dot(_parse_transform_substr(substr))
|
|
|
|
return torch.from_numpy(total_transform).type(torch.float32)
|
|
|
|
def parse_linear_gradient(node, transform, defs):
|
|
begin = torch.tensor([0.0, 0.0])
|
|
end = torch.tensor([0.0, 0.0])
|
|
offsets = []
|
|
stop_colors = []
|
|
# Inherit from parent
|
|
for key in node.attrib:
|
|
if remove_namespaces(key) == 'href':
|
|
value = node.attrib[key]
|
|
parent = defs[value.lstrip('#')]
|
|
begin = parent.begin
|
|
end = parent.end
|
|
offsets = parent.offsets
|
|
stop_colors = parent.stop_colors
|
|
|
|
for attrib in node.attrib:
|
|
attrib = remove_namespaces(attrib)
|
|
if attrib == 'x1':
|
|
begin[0] = float(node.attrib['x1'])
|
|
elif attrib == 'y1':
|
|
begin[1] = float(node.attrib['y1'])
|
|
elif attrib == 'x2':
|
|
end[0] = float(node.attrib['x2'])
|
|
elif attrib == 'y2':
|
|
end[1] = float(node.attrib['y2'])
|
|
elif attrib == 'gradientTransform':
|
|
transform = transform @ parse_transform(node.attrib['gradientTransform'])
|
|
|
|
begin = transform @ torch.cat((begin, torch.ones([1])))
|
|
begin = begin / begin[2]
|
|
begin = begin[:2]
|
|
end = transform @ torch.cat((end, torch.ones([1])))
|
|
end = end / end[2]
|
|
end = end[:2]
|
|
|
|
for child in node:
|
|
tag = remove_namespaces(child.tag)
|
|
if tag == 'stop':
|
|
offset = float(child.attrib['offset'])
|
|
color = [0.0, 0.0, 0.0, 1.0]
|
|
if 'stop-color' in child.attrib:
|
|
c = parse_color(child.attrib['stop-color'], defs)
|
|
color[:3] = [c[0], c[1], c[2]]
|
|
if 'stop-opacity' in child.attrib:
|
|
color[3] = float(child.attrib['stop-opacity'])
|
|
if 'style' in child.attrib:
|
|
style = parse_style(child.attrib['style'], defs)
|
|
if 'stop-color' in style:
|
|
c = parse_color(style['stop-color'], defs)
|
|
color[:3] = [c[0], c[1], c[2]]
|
|
if 'stop-opacity' in style:
|
|
color[3] = float(style['stop-opacity'])
|
|
offsets.append(offset)
|
|
stop_colors.append(color)
|
|
if isinstance(offsets, list):
|
|
offsets = torch.tensor(offsets)
|
|
if isinstance(stop_colors, list):
|
|
stop_colors = torch.tensor(stop_colors)
|
|
|
|
return pydiffvg.LinearGradient(begin, end, offsets, stop_colors)
|
|
|
|
|
|
def parse_radial_gradient(node, transform, defs):
|
|
begin = torch.tensor([0.0, 0.0])
|
|
end = torch.tensor([0.0, 0.0])
|
|
center = torch.tensor([0.0, 0.0])
|
|
radius = torch.tensor([0.0, 0.0])
|
|
offsets = []
|
|
stop_colors = []
|
|
# Inherit from parent
|
|
for key in node.attrib:
|
|
if remove_namespaces(key) == 'href':
|
|
value = node.attrib[key]
|
|
parent = defs[value.lstrip('#')]
|
|
begin = parent.begin
|
|
end = parent.end
|
|
offsets = parent.offsets
|
|
stop_colors = parent.stop_colors
|
|
|
|
for attrib in node.attrib:
|
|
attrib = remove_namespaces(attrib)
|
|
if attrib == 'cx':
|
|
center[0] = float(node.attrib['cx'])
|
|
elif attrib == 'cy':
|
|
center[1] = float(node.attrib['cy'])
|
|
elif attrib == 'fx':
|
|
radius[0] = float(node.attrib['fx'])
|
|
elif attrib == 'fy':
|
|
radius[1] = float(node.attrib['fy'])
|
|
elif attrib == 'fr':
|
|
radius[0] = float(node.attrib['fr'])
|
|
radius[1] = float(node.attrib['fr'])
|
|
elif attrib == 'gradientTransform':
|
|
transform = transform @ parse_transform(node.attrib['gradientTransform'])
|
|
|
|
# TODO: this is incorrect
|
|
center = transform @ torch.cat((center, torch.ones([1])))
|
|
center = center / center[2]
|
|
center = center[:2]
|
|
|
|
for child in node:
|
|
tag = remove_namespaces(child.tag)
|
|
if tag == 'stop':
|
|
offset = float(child.attrib['offset'])
|
|
color = [0.0, 0.0, 0.0, 1.0]
|
|
if 'stop-color' in child.attrib:
|
|
c = parse_color(child.attrib['stop-color'], defs)
|
|
color[:3] = [c[0], c[1], c[2]]
|
|
if 'stop-opacity' in child.attrib:
|
|
color[3] = float(child.attrib['stop-opacity'])
|
|
if 'style' in child.attrib:
|
|
style = parse_style(child.attrib['style'], defs)
|
|
if 'stop-color' in style:
|
|
c = parse_color(style['stop-color'], defs)
|
|
color[:3] = [c[0], c[1], c[2]]
|
|
if 'stop-opacity' in style:
|
|
color[3] = float(style['stop-opacity'])
|
|
offsets.append(offset)
|
|
stop_colors.append(color)
|
|
if isinstance(offsets, list):
|
|
offsets = torch.tensor(offsets)
|
|
if isinstance(stop_colors, list):
|
|
stop_colors = torch.tensor(stop_colors)
|
|
|
|
return pydiffvg.RadialGradient(begin, end, offsets, stop_colors)
|
|
|
|
def parse_stylesheet(node, transform, defs):
|
|
# collect CSS classes
|
|
sheet = cssutils.parseString(node.text)
|
|
for rule in sheet:
|
|
if hasattr(rule, 'selectorText') and hasattr(rule, 'style'):
|
|
name = rule.selectorText
|
|
if len(name) >= 2 and name[0] == '.':
|
|
defs[name[1:]] = parse_style(rule.style.getCssText(), defs)
|
|
return defs
|
|
|
|
def parse_defs(node, transform, defs):
|
|
for child in node:
|
|
tag = remove_namespaces(child.tag)
|
|
if tag == 'linearGradient':
|
|
if 'id' in child.attrib:
|
|
defs[child.attrib['id']] = parse_linear_gradient(child, transform, defs)
|
|
elif tag == 'radialGradient':
|
|
if 'id' in child.attrib:
|
|
defs[child.attrib['id']] = parse_radial_gradient(child, transform, defs)
|
|
elif tag == 'style':
|
|
defs = parse_stylesheet(child, transform, defs)
|
|
return defs
|
|
|
|
def parse_common_attrib(node, transform, fill_color, defs):
|
|
attribs = {}
|
|
if 'class' in node.attrib:
|
|
attribs.update(defs[node.attrib['class']])
|
|
attribs.update(node.attrib)
|
|
|
|
name = ''
|
|
if 'id' in node.attrib:
|
|
name = node.attrib['id']
|
|
|
|
stroke_color = None
|
|
stroke_width = torch.tensor(0.5)
|
|
use_even_odd_rule = False
|
|
|
|
new_transform = transform
|
|
if 'transform' in attribs:
|
|
new_transform = transform @ parse_transform(attribs['transform'])
|
|
if 'fill' in attribs:
|
|
fill_color = parse_color(attribs['fill'], defs)
|
|
fill_opacity = 1.0
|
|
if 'fill-opacity' in attribs:
|
|
fill_opacity *= float(attribs['fill-opacity'])
|
|
if 'opacity' in attribs:
|
|
fill_opacity *= float(attribs['opacity'])
|
|
# Ignore opacity if the color is a gradient
|
|
if isinstance(fill_color, torch.Tensor):
|
|
fill_color[3] = fill_opacity
|
|
|
|
if 'fill-rule' in attribs:
|
|
if attribs['fill-rule'] == "evenodd":
|
|
use_even_odd_rule = True
|
|
elif attribs['fill-rule'] == "nonzero":
|
|
use_even_odd_rule = False
|
|
else:
|
|
warnings.warn('Unknown fill-rule: {}'.format(attribs['fill-rule']))
|
|
|
|
if 'stroke' in attribs:
|
|
stroke_color = parse_color(attribs['stroke'], defs)
|
|
|
|
if 'stroke-width' in attribs:
|
|
stroke_width = attribs['stroke-width']
|
|
if stroke_width[-2:] == 'px':
|
|
stroke_width = stroke_width[:-2]
|
|
stroke_width = torch.tensor(float(stroke_width) / 2.0)
|
|
|
|
if 'style' in attribs:
|
|
style = parse_style(attribs['style'], defs)
|
|
if 'fill' in style:
|
|
fill_color = parse_color(style['fill'], defs)
|
|
fill_opacity = 1.0
|
|
if 'fill-opacity' in style:
|
|
fill_opacity *= float(style['fill-opacity'])
|
|
if 'opacity' in style:
|
|
fill_opacity *= float(style['opacity'])
|
|
if 'fill-rule' in style:
|
|
if style['fill-rule'] == "evenodd":
|
|
use_even_odd_rule = True
|
|
elif style['fill-rule'] == "nonzero":
|
|
use_even_odd_rule = False
|
|
else:
|
|
warnings.warn('Unknown fill-rule: {}'.format(style['fill-rule']))
|
|
# Ignore opacity if the color is a gradient
|
|
if isinstance(fill_color, torch.Tensor):
|
|
fill_color[3] = fill_opacity
|
|
if 'stroke' in style:
|
|
if style['stroke'] != 'none':
|
|
stroke_color = parse_color(style['stroke'], defs)
|
|
# Ignore opacity if the color is a gradient
|
|
if isinstance(stroke_color, torch.Tensor):
|
|
if 'stroke-opacity' in style:
|
|
stroke_color[3] = float(style['stroke-opacity'])
|
|
if 'opacity' in style:
|
|
stroke_color[3] *= float(style['opacity'])
|
|
if 'stroke-width' in style:
|
|
stroke_width = style['stroke-width']
|
|
if stroke_width[-2:] == 'px':
|
|
stroke_width = stroke_width[:-2]
|
|
stroke_width = torch.tensor(float(stroke_width) / 2.0)
|
|
|
|
if isinstance(fill_color, pydiffvg.LinearGradient):
|
|
fill_color.begin = new_transform @ torch.cat((fill_color.begin, torch.ones([1])))
|
|
fill_color.begin = fill_color.begin / fill_color.begin[2]
|
|
fill_color.begin = fill_color.begin[:2]
|
|
fill_color.end = new_transform @ torch.cat((fill_color.end, torch.ones([1])))
|
|
fill_color.end = fill_color.end / fill_color.end[2]
|
|
fill_color.end = fill_color.end[:2]
|
|
if isinstance(stroke_color, pydiffvg.LinearGradient):
|
|
stroke_color.begin = new_transform @ torch.cat((stroke_color.begin, torch.ones([1])))
|
|
stroke_color.begin = stroke_color.begin / stroke_color.begin[2]
|
|
stroke_color.begin = stroke_color.begin[:2]
|
|
stroke_color.end = new_transform @ torch.cat((stroke_color.end, torch.ones([1])))
|
|
stroke_color.end = stroke_color.end / stroke_color.end[2]
|
|
stroke_color.end = stroke_color.end[:2]
|
|
if 'filter' in style:
|
|
print('*** WARNING ***: Ignoring filter for path with id "{}"'.format(name))
|
|
|
|
return new_transform, fill_color, stroke_color, stroke_width, use_even_odd_rule
|
|
|
|
def is_shape(tag):
|
|
return tag == 'path' or tag == 'polygon' or tag == 'line' or tag == 'circle' or tag == 'rect'
|
|
|
|
def parse_shape(node, transform, fill_color, shapes, shape_groups, defs):
|
|
tag = remove_namespaces(node.tag)
|
|
new_transform, new_fill_color, stroke_color, stroke_width, use_even_odd_rule = \
|
|
parse_common_attrib(node, transform, fill_color, defs)
|
|
if tag == 'path':
|
|
d = node.attrib['d']
|
|
name = ''
|
|
if 'id' in node.attrib:
|
|
name = node.attrib['id']
|
|
force_closing = new_fill_color is not None
|
|
paths = pydiffvg.from_svg_path(d, new_transform, force_closing)
|
|
for idx, path in enumerate(paths):
|
|
assert(path.points.shape[1] == 2)
|
|
path.stroke_width = stroke_width
|
|
path.source_id = name
|
|
path.id = "{}-{}".format(name,idx) if len(paths)>1 else name
|
|
prev_shapes_size = len(shapes)
|
|
shapes = shapes + paths
|
|
shape_ids = torch.tensor(list(range(prev_shapes_size, len(shapes))))
|
|
shape_groups.append(pydiffvg.ShapeGroup(\
|
|
shape_ids = shape_ids,
|
|
fill_color = new_fill_color,
|
|
stroke_color = stroke_color,
|
|
use_even_odd_rule = use_even_odd_rule,
|
|
id = name))
|
|
elif tag == 'polygon':
|
|
name = ''
|
|
if 'id' in node.attrib:
|
|
name = node.attrib['id']
|
|
force_closing = new_fill_color is not None
|
|
pts = node.attrib['points'].strip()
|
|
pts = pts.split(' ')
|
|
# import ipdb; ipdb.set_trace()
|
|
pts = [[float(y) for y in re.split(',| ', x)] for x in pts if x]
|
|
pts = torch.tensor(pts, dtype=torch.float32).view(-1, 2)
|
|
polygon = pydiffvg.Polygon(pts, force_closing)
|
|
polygon.stroke_width = stroke_width
|
|
shape_ids = torch.tensor([len(shapes)])
|
|
shapes.append(polygon)
|
|
shape_groups.append(pydiffvg.ShapeGroup(\
|
|
shape_ids = shape_ids,
|
|
fill_color = new_fill_color,
|
|
stroke_color = stroke_color,
|
|
use_even_odd_rule = use_even_odd_rule,
|
|
shape_to_canvas = new_transform,
|
|
id = name))
|
|
elif tag == 'line':
|
|
x1 = float(node.attrib['x1'])
|
|
y1 = float(node.attrib['y1'])
|
|
x2 = float(node.attrib['x2'])
|
|
y2 = float(node.attrib['y2'])
|
|
p1 = torch.tensor([x1, y1])
|
|
p2 = torch.tensor([x2, y2])
|
|
points = torch.stack((p1, p2))
|
|
line = pydiffvg.Polygon(points, False)
|
|
line.stroke_width = stroke_width
|
|
shape_ids = torch.tensor([len(shapes)])
|
|
shapes.append(line)
|
|
shape_groups.append(pydiffvg.ShapeGroup(\
|
|
shape_ids = shape_ids,
|
|
fill_color = new_fill_color,
|
|
stroke_color = stroke_color,
|
|
use_even_odd_rule = use_even_odd_rule,
|
|
shape_to_canvas = new_transform))
|
|
elif tag == 'circle':
|
|
radius = float(node.attrib['r'])
|
|
cx = float(node.attrib['cx'])
|
|
cy = float(node.attrib['cy'])
|
|
name = ''
|
|
if 'id' in node.attrib:
|
|
name = node.attrib['id']
|
|
center = torch.tensor([cx, cy])
|
|
circle = pydiffvg.Circle(radius = torch.tensor(radius),
|
|
center = center)
|
|
circle.stroke_width = stroke_width
|
|
shape_ids = torch.tensor([len(shapes)])
|
|
shapes.append(circle)
|
|
shape_groups.append(pydiffvg.ShapeGroup(\
|
|
shape_ids = shape_ids,
|
|
fill_color = new_fill_color,
|
|
stroke_color = stroke_color,
|
|
use_even_odd_rule = use_even_odd_rule,
|
|
shape_to_canvas = new_transform))
|
|
elif tag == 'ellipse':
|
|
rx = float(node.attrib['rx'])
|
|
ry = float(node.attrib['ry'])
|
|
cx = float(node.attrib['cx'])
|
|
cy = float(node.attrib['cy'])
|
|
name = ''
|
|
if 'id' in node.attrib:
|
|
name = node.attrib['id']
|
|
center = torch.tensor([cx, cy])
|
|
circle = pydiffvg.Circle(radius = torch.tensor(radius),
|
|
center = center)
|
|
circle.stroke_width = stroke_width
|
|
shape_ids = torch.tensor([len(shapes)])
|
|
shapes.append(circle)
|
|
shape_groups.append(pydiffvg.ShapeGroup(\
|
|
shape_ids = shape_ids,
|
|
fill_color = new_fill_color,
|
|
stroke_color = stroke_color,
|
|
use_even_odd_rule = use_even_odd_rule,
|
|
shape_to_canvas = new_transform))
|
|
elif tag == 'rect':
|
|
x = 0.0
|
|
y = 0.0
|
|
if x in node.attrib:
|
|
x = float(node.attrib['x'])
|
|
if y in node.attrib:
|
|
y = float(node.attrib['y'])
|
|
w = float(node.attrib['width'])
|
|
h = float(node.attrib['height'])
|
|
p_min = torch.tensor([x, y])
|
|
p_max = torch.tensor([x + w, x + h])
|
|
rect = pydiffvg.Rect(p_min = p_min, p_max = p_max)
|
|
rect.stroke_width = stroke_width
|
|
shape_ids = torch.tensor([len(shapes)])
|
|
shapes.append(rect)
|
|
shape_groups.append(pydiffvg.ShapeGroup(\
|
|
shape_ids = shape_ids,
|
|
fill_color = new_fill_color,
|
|
stroke_color = stroke_color,
|
|
use_even_odd_rule = use_even_odd_rule,
|
|
shape_to_canvas = new_transform))
|
|
return shapes, shape_groups
|
|
|
|
def parse_group(node, transform, fill_color, shapes, shape_groups, defs):
|
|
if 'transform' in node.attrib:
|
|
transform = transform @ parse_transform(node.attrib['transform'])
|
|
if 'fill' in node.attrib:
|
|
fill_color = parse_color(node.attrib['fill'], defs)
|
|
for child in node:
|
|
tag = remove_namespaces(child.tag)
|
|
if is_shape(tag):
|
|
shapes, shape_groups = parse_shape(\
|
|
child, transform, fill_color, shapes, shape_groups, defs)
|
|
elif tag == 'g':
|
|
shapes, shape_groups = parse_group(\
|
|
child, transform, fill_color, shapes, shape_groups, defs)
|
|
return shapes, shape_groups
|
|
|
|
def parse_scene(node):
|
|
canvas_width = -1
|
|
canvas_height = -1
|
|
defs = {}
|
|
shapes = []
|
|
shape_groups = []
|
|
fill_color = torch.tensor([0.0, 0.0, 0.0, 1.0])
|
|
transform = torch.eye(3)
|
|
if 'viewBox' in node.attrib:
|
|
view_box_array = node.attrib['viewBox'].split()
|
|
canvas_width = parse_int(view_box_array[2])
|
|
canvas_height = parse_int(view_box_array[3])
|
|
else:
|
|
if 'width' in node.attrib:
|
|
canvas_width = parse_int(node.attrib['width'])
|
|
else:
|
|
print('Warning: Can\'t find canvas width.')
|
|
if 'height' in node.attrib:
|
|
canvas_height = parse_int(node.attrib['height'])
|
|
else:
|
|
print('Warning: Can\'t find canvas height.')
|
|
for child in node:
|
|
tag = remove_namespaces(child.tag)
|
|
if tag == 'defs':
|
|
defs = parse_defs(child, transform, defs)
|
|
elif tag == 'style':
|
|
defs = parse_stylesheet(child, transform, defs)
|
|
elif tag == 'linearGradient':
|
|
if 'id' in child.attrib:
|
|
defs[child.attrib['id']] = parse_linear_gradient(child, transform, defs)
|
|
elif tag == 'radialGradient':
|
|
if 'id' in child.attrib:
|
|
defs[child.attrib['id']] = parse_radial_gradient(child, transform, defs)
|
|
elif is_shape(tag):
|
|
shapes, shape_groups = parse_shape(\
|
|
child, transform, fill_color, shapes, shape_groups, defs)
|
|
elif tag == 'g':
|
|
shapes, shape_groups = parse_group(\
|
|
child, transform, fill_color, shapes, shape_groups, defs)
|
|
return canvas_width, canvas_height, shapes, shape_groups
|
|
|
|
def svg_to_scene(filename):
|
|
"""
|
|
Load from a SVG file and convert to PyTorch tensors.
|
|
"""
|
|
|
|
tree = etree.parse(filename)
|
|
root = tree.getroot()
|
|
cwd = os.getcwd()
|
|
if (os.path.dirname(filename) != ''):
|
|
os.chdir(os.path.dirname(filename))
|
|
ret = parse_scene(root)
|
|
os.chdir(cwd)
|
|
return ret
|