Roughing in transform=matrix(...)
This commit is contained in:
parent
da6fe5f0e3
commit
dedf14ac8a
@ -55,6 +55,7 @@ class SVGPath(object):
|
|||||||
# xpath | doesn't seem to reliable work so just walk it
|
# xpath | doesn't seem to reliable work so just walk it
|
||||||
for el in self.root.iter():
|
for el in self.root.iter():
|
||||||
pb.add_path_from_element(el)
|
pb.add_path_from_element(el)
|
||||||
for path in pb.paths:
|
for path, transform in zip(pb.paths, pb.transforms):
|
||||||
|
# TODO use transform
|
||||||
parse_path(path, pen)
|
parse_path(path, pen)
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
def _prefer_non_zero(*args):
|
def _prefer_non_zero(*args):
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if arg != 0:
|
if arg != 0:
|
||||||
@ -16,12 +18,25 @@ def _strip_xml_ns(tag):
|
|||||||
return tag.split('}', 1)[1] if '}' in tag else tag
|
return tag.split('}', 1)[1] if '}' in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _transform(raw_value):
|
||||||
|
# start simple: if you aren't exactly matrix(...) then no love
|
||||||
|
match = re.match(r'matrix\((.*)\)', raw_value)
|
||||||
|
if not match:
|
||||||
|
raise NotImplementedError
|
||||||
|
matrix = tuple(float(p) for p in re.split(r'\s+|,', match.group(1)))
|
||||||
|
if len(matrix) != 6:
|
||||||
|
raise ValueError('wrong # of terms in %s' % raw_value)
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
|
||||||
class PathBuilder(object):
|
class PathBuilder(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.paths = []
|
self.paths = []
|
||||||
|
self.transforms = []
|
||||||
|
|
||||||
def _start_path(self, initial_path=''):
|
def _start_path(self, initial_path=''):
|
||||||
self.paths.append(initial_path)
|
self.paths.append(initial_path)
|
||||||
|
self.transforms.append(None)
|
||||||
|
|
||||||
def _end_path(self):
|
def _end_path(self):
|
||||||
self._add('z')
|
self._add('z')
|
||||||
@ -134,4 +149,6 @@ class PathBuilder(object):
|
|||||||
if not callable(parse_fn):
|
if not callable(parse_fn):
|
||||||
return False
|
return False
|
||||||
parse_fn(el)
|
parse_fn(el)
|
||||||
|
if 'transform' in el.attrib:
|
||||||
|
self.transforms[-1] = _transform(el.attrib['transform'])
|
||||||
return True
|
return True
|
||||||
|
@ -7,71 +7,97 @@ import pytest
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"svg_xml, expected_path",
|
"svg_xml, expected_path, expected_transform",
|
||||||
[
|
[
|
||||||
# path: direct passthrough
|
# path: direct passthrough
|
||||||
(
|
(
|
||||||
"<path d='I love kittens'/>",
|
"<path d='I love kittens'/>",
|
||||||
"I love kittens"
|
"I love kittens",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# path no @d
|
# path no @d
|
||||||
(
|
(
|
||||||
"<path duck='Mallard'/>",
|
"<path duck='Mallard'/>",
|
||||||
None
|
None,
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# rect: minimal valid example
|
# rect: minimal valid example
|
||||||
(
|
(
|
||||||
"<rect width='1' height='1'/>",
|
"<rect width='1' height='1'/>",
|
||||||
"M0,0 H1 V1 H0 V0 z",
|
"M0,0 H1 V1 H0 V0 z",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# rect: sharp corners
|
# rect: sharp corners
|
||||||
(
|
(
|
||||||
"<rect x='10' y='11' width='17' height='11'/>",
|
"<rect x='10' y='11' width='17' height='11'/>",
|
||||||
"M10,11 H27 V22 H10 V11 z",
|
"M10,11 H27 V22 H10 V11 z",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# rect: round corners
|
# rect: round corners
|
||||||
(
|
(
|
||||||
"<rect x='9' y='9' width='11' height='7' rx='2'/>",
|
"<rect x='9' y='9' width='11' height='7' rx='2'/>",
|
||||||
"M11,9 H18 A2,2 0 0 1 20,11 V14 A2,2 0 0 1 18,16 H11"
|
"M11,9 H18 A2,2 0 0 1 20,11 V14 A2,2 0 0 1 18,16 H11"
|
||||||
" A2,2 0 0 1 9,14 V11 A2,2 0 0 1 11,9 z",
|
" A2,2 0 0 1 9,14 V11 A2,2 0 0 1 11,9 z",
|
||||||
|
None
|
||||||
|
),
|
||||||
|
# rect: simple
|
||||||
|
(
|
||||||
|
"<rect x='11.5' y='16' width='11' height='2'/>",
|
||||||
|
"M11.5,16 H22.5 V18 H11.5 V16 z",
|
||||||
|
None
|
||||||
|
),
|
||||||
|
# rect: the one above plus a rotation
|
||||||
|
(
|
||||||
|
"<rect x='11.5' y='16' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -7.0416 16.9999)' width='11' height='2'/>",
|
||||||
|
"M11.5,16 H22.5 V18 H11.5 V16 z",
|
||||||
|
(0.7071, -0.7071, 0.7071, 0.7071, -7.0416, 16.9999)
|
||||||
),
|
),
|
||||||
# polygon
|
# polygon
|
||||||
(
|
(
|
||||||
"<polygon points='30,10 50,30 10,30'/>",
|
"<polygon points='30,10 50,30 10,30'/>",
|
||||||
"M30,10 50,30 10,30 z"
|
"M30,10 50,30 10,30 z",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# circle, minimal valid example
|
# circle, minimal valid example
|
||||||
(
|
(
|
||||||
"<circle r='1'/>",
|
"<circle r='1'/>",
|
||||||
"M-1,0 A1,1 0 1 1 1,0 A1,1 0 1 1 -1,0"
|
"M-1,0 A1,1 0 1 1 1,0 A1,1 0 1 1 -1,0",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# circle
|
# circle
|
||||||
(
|
(
|
||||||
"<circle cx='600' cy='200' r='100'/>",
|
"<circle cx='600' cy='200' r='100'/>",
|
||||||
"M500,200 A100,100 0 1 1 700,200 A100,100 0 1 1 500,200"
|
"M500,200 A100,100 0 1 1 700,200 A100,100 0 1 1 500,200",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# circle, decimal positioning
|
# circle, decimal positioning
|
||||||
(
|
(
|
||||||
"<circle cx='12' cy='6.5' r='1.5'></circle>",
|
"<circle cx='12' cy='6.5' r='1.5'></circle>",
|
||||||
"M10.5,6.5 A1.5,1.5 0 1 1 13.5,6.5 A1.5,1.5 0 1 1 10.5,6.5"
|
"M10.5,6.5 A1.5,1.5 0 1 1 13.5,6.5 A1.5,1.5 0 1 1 10.5,6.5",
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# ellipse
|
# ellipse
|
||||||
(
|
(
|
||||||
'<ellipse cx="100" cy="50" rx="100" ry="50"/>',
|
'<ellipse cx="100" cy="50" rx="100" ry="50"/>',
|
||||||
'M0,50 A100,50 0 1 1 200,50 A100,50 0 1 1 0,50'
|
'M0,50 A100,50 0 1 1 200,50 A100,50 0 1 1 0,50',
|
||||||
|
None
|
||||||
),
|
),
|
||||||
# ellipse, decimal positioning
|
# ellipse, decimal positioning
|
||||||
(
|
(
|
||||||
'<ellipse cx="100.5" cy="50" rx="10" ry="50.5"/>',
|
'<ellipse cx="100.5" cy="50" rx="10" ry="50.5"/>',
|
||||||
'M90.5,50 A10,50.5 0 1 1 110.5,50 A10,50.5 0 1 1 90.5,50'
|
'M90.5,50 A10,50.5 0 1 1 110.5,50 A10,50.5 0 1 1 90.5,50',
|
||||||
|
None
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_el_to_path(svg_xml, expected_path):
|
def test_el_to_path(svg_xml, expected_path, expected_transform):
|
||||||
pb = shapes.PathBuilder()
|
pb = shapes.PathBuilder()
|
||||||
pb.add_path_from_element(etree.fromstring(svg_xml))
|
pb.add_path_from_element(etree.fromstring(svg_xml))
|
||||||
if expected_path:
|
if expected_path:
|
||||||
expected = [expected_path]
|
expected_paths = [expected_path]
|
||||||
|
expected_transforms = [expected_transform]
|
||||||
else:
|
else:
|
||||||
expected = []
|
expected_paths = []
|
||||||
assert pb.paths == expected
|
expected_transforms = []
|
||||||
|
assert pb.paths == expected_paths
|
||||||
|
assert pb.transforms == expected_transforms
|
||||||
|
Loading…
x
Reference in New Issue
Block a user