#!/usr/bin/env python
# --------------------------------------------------------------------
# convert SVG to Ipe format
# --------------------------------------------------------------------
#
# Copyright (C) 2009-2014 Otfried Cheong
#
# svgtoipe is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# svgtoipe is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with svgtoipe; if not, you can find it at
# "http://www.gnu.org/copyleft/gpl.html", or write to the Free
# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# --------------------------------------------------------------------
svgtoipe_version = "20091018"
import sys
import xml.dom.minidom as xml
from xml.dom.minidom import Node
import re
import math
import base64
import cStringIO
try:
from PIL import Image
have_pil = True
except:
have_pil = False
# --------------------------------------------------------------------
color_keywords = {
"black" : "rgb(0, 0, 0)",
"green" :"rgb(0, 128, 0)",
"silver" :"rgb(192, 192, 192)",
"lime" :"rgb(0, 255, 0)",
"gray" :"rgb(128, 128, 128)",
"olive" :"rgb(128, 128, 0)",
"white" :"rgb(255, 255, 255)",
"yellow" :"rgb(255, 255, 0)",
"maroon" :"rgb(128, 0, 0)",
"navy" :"rgb(0, 0, 128)",
"red" :"rgb(255, 0, 0)",
"blue" :"rgb(0, 0, 255)",
"purple" :"rgb(128, 0, 128)",
"teal" :"rgb(0, 128, 128)",
"fuchsia" :"rgb(255, 0, 255)",
"aqua" :"rgb(0, 255, 255)",
}
attribute_names = [ "stroke",
"fill",
"stroke-opacity",
"fill-opacity",
"stroke-width",
"fill-rule",
"stroke-linecap",
"stroke-linejoin",
"stroke-dasharray",
"stroke-dashoffset",
"stroke-miterlimit",
"opacity",
"font-size" ]
def printAttributes(n):
a = n.attributes
for i in range(a.length):
name = a.item(i).name
if name[:9] != "sodipodi:" and name[:9] != "inkscape:":
print " ", name, n.getAttribute(name)
def parse_float(txt):
if not txt:
return None
if txt.endswith('px') or txt.endswith('pt'):
return float(txt[:-2])
elif txt.endswith('pc'):
return 12 * float(txt[:-2])
elif txt.endswith('mm'):
return 72.0 * float(txt[:-2]) / 25.4
elif txt.endswith('cm'):
return 72.0 * float(txt[:-2]) / 2.54
elif txt.endswith('in'):
return 72.0 * float(txt[:-2])
else:
return float(txt)
def parse_opacity(txt):
if not txt:
return None
m = int(10 * (float(txt) + 0.05))
if m == 0: m = 1
return 10 * m
def parse_list(string):
return re.findall("([A-Za-z]|-?[0-9]+\.?[0-9]*(?:e-?[0-9]*)?)", string)
def parse_style(string):
sdict = {}
for item in string.split(';'):
if ':' in item:
key, value = item.split(':')
sdict[key.strip()] = value.strip()
return sdict
def parse_color_component(txt):
if txt.endswith("%"):
return float(txt[:-1]) / 100.0
else:
return int(txt) / 255.0
def parse_color(c):
if not c or c == 'none':
return None
if c in color_keywords:
c = color_keywords[c]
m = re.match(r"rgb\(([0-9\.]+%?),\s*([0-9\.]+%?),\s*([0-9\.]+%?)\s*\)", c)
if m:
r = parse_color_component(m.group(1))
g = parse_color_component(m.group(2))
b = parse_color_component(m.group(3))
return (r, g, b)
m = re.match(r"#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$", c)
if m:
r = int(m.group(1), 16) / 15.0
g = int(m.group(2), 16) / 15.0
b = int(m.group(3), 16) / 15.0
return (r, g, b)
m = re.match(r"#([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])"
+ r"([0-9a-fA-F][0-9a-fA-F])$", c)
if m:
r = int(m.group(1), 16) / 255.0
g = int(m.group(2), 16) / 255.0
b = int(m.group(3), 16) / 255.0
return (r, g, b)
sys.stderr.write("Unknown color: %s\n" % c)
return None
def pnext(d, n):
l = []
while n > 0:
l.append(float(d.pop(0)))
n -= 1
return tuple(l)
def parse_path(out, d):
d = re.findall("([A-Za-z]|-?[0-9]+\.?[0-9]*(?:e-?[0-9]*)?)", d)
x, y = 0.0, 0.0
xs, ys = 0.0, 0.0
while d:
if not d[0][0] in "01234567890.-":
opcode = d.pop(0)
if opcode == 'M':
x, y = pnext(d, 2)
out.write("%g %g m\n" % (x, y))
opcode = 'L'
elif opcode == 'm':
x1, y1 = pnext(d, 2)
x += x1
y += y1
out.write("%g %g m\n" % (x, y))
opcode = 'l'
elif opcode == 'L':
x, y = pnext(d, 2)
out.write("%g %g l\n" % (x, y))
elif opcode == 'l':
x1, y1 = pnext(d, 2)
x += x1
y += y1
out.write("%g %g l\n" % (x, y))
elif opcode == 'H':
x = pnext(d, 1)[0]
out.write("%g %g l\n" % (x, y))
elif opcode == 'h':
x += pnext(d, 1)[0]
out.write("%g %g l\n" % (x, y))
elif opcode == 'V':
y = pnext(d, 1)[0]
out.write("%g %g l\n" % (x, y))
elif opcode == 'v':
y += pnext(d, 1)[0]
out.write("%g %g l\n" % (x, y))
elif opcode == 'C':
x1, y1, xs, ys, x, y = pnext(d, 6)
out.write("%g %g %g %g %g %g c\n" % (x1, y1, xs, ys, x, y))
elif opcode == 'c':
x1, y1, xs, ys, xf, yf = pnext(d, 6)
x1 += x; y1 += y
xs += x; ys += y
x += xf; y += yf
out.write("%g %g %g %g %g %g c\n" % (x1, y1, xs, ys, x, y))
elif opcode == 'S' or opcode == 's':
x2, y2, xf, yf = pnext(d, 4)
if opcode == 's':
x2 += x; y2 += y
xf += x; yf += y
x1 = x + (x - xs); y1 = y + (y - ys)
out.write("%g %g %g %g %g %g c\n" % (x1, y1, x2, y2, xf, yf))
xs, ys = x2, y2
x, y = xf, yf
elif opcode == 'Q':
xs, ys, x, y = pnext(d, 4)
out.write("%g %g %g %g q\n" % (xs, ys, x, y))
elif opcode == 'q':
xs, ys, xf, yf = pnext(d, 4)
xs += x; ys += y
x += xf; y += yf
out.write("%g %g %g %g q\n" % (xs, ys, x, y))
elif opcode == 'T' or opcode == 't':
xf, yf = pnext(d, 2)
if opcode == 't':
xf += x; yf += y
x1 = x + (x - xs); y1 = y + (y - ys)
out.write("%g %g %g %g q\n" % (x1, y1, xf, yf))
xs, ys = x1, y1
x, y = xf, yf
elif opcode == 'A' or opcode == 'a':
rx, ry, phi, large_arc, sweep, x2, y2 = pnext(d, 7)
if opcode == 'a':
x2 += x; y2 += y
draw_arc(out, x, y, rx, ry, phi, large_arc, sweep, x2, y2)
x, y = x2, y2
elif opcode in 'zZ':
out.write("h\n")
else:
sys.stderr.write("Unrecognised opcode: %s\n" % opcode)
def parse_transformation(txt):
d = re.findall("[a-zA-Z]+\([^)]*\)", txt)
m = Matrix()
while d:
m1 = Matrix(d.pop(0))
m = m * m1
return m
def get_gradientTransform(n):
if n.hasAttribute("gradientTransform"):
return parse_transformation(n.getAttribute("gradientTransform"))
return Matrix()
def parse_transform(n):
if n.hasAttribute("transform"):
return parse_transformation(n.getAttribute("transform"))
return None
# Convert from endpoint to center parameterization
# www.w3.org/TR/2003/REC-SVG11-20030114/implnote.html#ArcImplementationNotes
def draw_arc(out, x1, y1, rx, ry, phi, large_arc, sweep, x2, y2):
phi = math.pi * phi / 180.0
cp = math.cos(phi); sp = math.sin(phi)
dx = .5 * (x1 - x2); dy = .5 * (y1 - y2)
x1p = cp * dx + sp * dy; y1p = -sp * dx + cp * dy
r2 = (((rx * ry)**2 - (rx * y1p)**2 - (ry * x1p)**2)/
((rx * y1p)**2 + (ry * x1p)**2))
if r2 < 0: r2 = 0
r = math.sqrt(r2)
if large_arc == sweep:
r = -r
cxp = r * rx * y1p / ry; cyp = -r * ry * x1p / rx
cx = cp * cxp - sp * cyp + .5 * (x1 + x2)
cy = sp * cxp + cp * cyp + .5 * (y1 + y2)
m = Matrix([rx, 0, 0, ry, 0, 0])
m = Matrix([cp, sp, -sp, cp, cx, cy]) * m
if sweep == 0:
m = m * Matrix([1, 0, 0, -1, 0, 0])
out.write("%s %g %g a\n" % (str(m), x2, y2))
# --------------------------------------------------------------------
class Matrix(object):
# Default is identity matrix
def __init__(self, string = None):
self.values = [1, 0, 0, 1, 0, 0]
if not string or string == "":
return
if isinstance(string, list):
self.values = string
return
mat = re.match(r"([a-zA-Z]+)\(([^)]*)\)$", string)
if not mat:
sys.stderr.write("Unknown transform: %s\n" % string)
op = mat.group(1)
d = [float(x) for x in parse_list(mat.group(2))]
if op == "matrix":
self.values = d
elif op == "translate":
if len(d) == 1: d.append(0.0)
self.values = [1, 0, 0, 1, d[0], d[1]]
elif op == "scale":
if len(d) == 1: d.append(d[0])
sx, sy = d
self.values = [sx, 0, 0, sy, 0, 0]
elif op == "rotate":
phi = math.pi * d[0] / 180.0
self.values = [math.cos(phi), math.sin(phi),
-math.sin(phi), math.cos(phi), 0, 0]
elif op == "skewX":
tphi = math.tan(math.pi * d[0] / 180.0)
self.values = [1, 0, tphi, 1, 0, 0]
elif op == "skewY":
tphi = math.tan(math.pi * d[0] / 180.0)
self.values = [1, tphi, 0, 1, 0, 0]
else:
sys.stderr.write("Unknown transform: %s\n" % string)
def __call__(self, other):
return (self.values[0]*other[0] + self.values[2]*other[1] + self.values[4],
self.values[1]*other[0] + self.values[3]*other[1] + self.values[5])
def inverse(self):
d = float(self.values[0]*self.values[3] - self.values[1]*self.values[2])
return Matrix([self.values[3]/d, -self.values[1]/d,
-self.values[2]/d, self.values[0]/d,
(self.values[2]*self.values[5] -
self.values[3]*self.values[4])/d,
(self.values[1]*self.values[4] -
self.values[0]*self.values[5])/d])
def __mul__(self, other):
a, b, c, d, e, f = self.values
u, v, w, x, y, z = other.values
return Matrix([a*u + c*v, b*u + d*v, a*w + c*x,
b*w + d*x, a*y + c*z + e, b*y + d*z + f])
def __str__(self):
a, b, c, d, e, f = self.values
return "%g %g %g %g %g %g" % (a, b, c, d, e, f)
# --------------------------------------------------------------------
class Svg():
def __init__(self, fname):
self.dom = xml.parse(fname)
attr = { }
for a in attribute_names:
attr[a] = None
self.attributes = [ attr ]
self.defs = { }
for n in self.dom.childNodes:
if n.nodeType == Node.ELEMENT_NODE and n.tagName == "svg":
if n.hasAttribute("viewBox"):
x, y, w, h = [float(x) for x in parse_list(n.getAttribute("viewBox"))]
self.width = w
self.height = h
self.origin = (x, y)
else:
self.width = parse_float(n.getAttribute("width"))
self.height = parse_float(n.getAttribute("height"))
self.origin = (0, 0)
self.root = n
return
# --------------------------------------------------------------------
def parse_svg(self, outname):
self.out = open(outname, "w")
self.out.write('\n')
self.out.write('\n')
self.out.write('\n' %
svgtoipe_version)
self.out.write('\n')
self.out.write(('\n') %
(self.width, self.height, self.width, self.height))
for t in range(10, 100, 10):
self.out.write('\n' % (t, t))
# set SVG defaults
self.out.write('\n')
self.out.write('\n')
# collect definitions
for n in self.root.childNodes:
if n.nodeType != Node.ELEMENT_NODE:
continue
if hasattr(self, "def_" + n.tagName):
getattr(self, "def_" + n.tagName)(n)
# write definitions into stylesheet
if len(self.defs) > 0:
self.out.write('\n')
for k in self.defs:
if self.defs[k][0] == "linearGradient":
self.write_linear_gradient(k)
elif self.defs[k][0] == "radialGradient":
self.write_radial_gradient(k)
self.out.write('\n')
# start real data
self.out.write('\n')
m = Matrix([1, 0, 0, 1, 0, self.height / 2.0])
m = m * Matrix([1, 0, 0, -1, 0, 0])
m = m * Matrix([1, 0, 0, 1,
-self.origin[0], -(self.origin[1] + self.height / 2.0)])
self.out.write('\n' % str(m))
for n in self.root.childNodes:
if n.nodeType != Node.ELEMENT_NODE:
continue
if hasattr(self, "node_" + n.tagName):
getattr(self, "node_" + n.tagName)(n)
else:
sys.stderr.write("Unhandled node: %s\n" % n.tagName)
self.out.write('\n')
self.out.write('\n')
self.out.write('\n')
self.out.close()
# --------------------------------------------------------------------
def write_linear_gradient(self, k):
typ, x1, x2, y1, y2, stops, matrix = self.defs[k]
self.out.write('\n' % (x1, y1, x2, y2))
for s in stops:
offset, color = s
self.out.write(' \n' %
(offset, color[0], color[1], color[2]))
self.out.write('\n')
def write_radial_gradient(self, k):
typ, cx, cy, r, fx, fy, stops, matrix = self.defs[k]
self.out.write('\n' % (fx, fy, 0, cx, cy, r))
for s in stops:
offset, color = s
self.out.write(' \n' %
(offset, color[0], color[1], color[2]))
self.out.write('\n')
def get_stops(self, n):
stops = []
for m in n.childNodes:
if m.nodeType != Node.ELEMENT_NODE:
continue
if m.tagName != "stop":
continue # should not happen
offs = m.getAttribute("offset")
if offs.endswith("%"):
offs = float(offs[:-1]) / 100.0
else:
offs = float(offs)
color = parse_color(m.getAttribute("stop-color"))
if m.hasAttribute("style"):
sdict = parse_style(m.getAttribute("style"))
if "stop-color" in sdict:
color = parse_color(sdict["stop-color"])
stops.append((offs, color))
if len(stops) == 0:
if n.hasAttribute("xlink:href"):
ref = n.getAttribute("xlink:href")
if ref.startswith("#") and ref[1:] in self.defs:
stops = self.defs[ref[1:]][5]
return stops
def def_linearGradient(self, n):
#printAttributes(n)
kid = n.getAttribute("id")
x1 = 0; y1 = 0
x2 = self.width; y2 = self.height
if n.hasAttribute("x1"):
s = n.getAttribute("x1")
if s.endswith("%"):
x1 = self.width * float(s[:-1]) / 100.0
else:
x1 = parse_float(s)
if n.hasAttribute("x2"):
s = n.getAttribute("x2")
if s.endswith("%"):
x2 = self.width * float(s[:-1]) / 100.0
else:
x2 = parse_float(s)
if n.hasAttribute("y1"):
s = n.getAttribute("y1")
if s.endswith("%"):
y1 = self.width * float(s[:-1]) / 100.0
else:
y1 = parse_float(s)
if n.hasAttribute("y2"):
s = n.getAttribute("y2")
if s.endswith("%"):
y2 = self.width * float(s[:-1]) / 100.0
else:
y2 = parse_float(s)
matrix = get_gradientTransform(n)
stops = self.get_stops(n)
self.defs[kid] = ("linearGradient", x1, x2, y1, y2, stops, matrix)
def def_radialGradient(self, n):
#printAttributes(n)
kid = n.getAttribute("id")
cx = "50%"; cy = "50%"; r = "50%"
if n.hasAttribute("cx"):
cx = n.getAttribute("cx")
if cx.endswith("%"):
cx = self.width * float(cx[:-1]) / 100.0
else:
cx = parse_float(cx)
if n.hasAttribute("cy"):
cy = n.getAttribute("cy")
if cy.endswith("%"):
cy = self.width * float(cy[:-1]) / 100.0
else:
cy = parse_float(cy)
if n.hasAttribute("r"):
r = n.getAttribute("r")
if r.endswith("%"):
r = self.width * float(r[:-1]) / 100.0
else:
r = parse_float(r)
if n.hasAttribute("fx"):
s = n.getAttribute("fx")
if s.endswith("%"):
fx = self.width * float(s[:-1]) / 100.0
else:
fx = parse_float(s)
else:
fx = cx
if n.hasAttribute("fy"):
s = n.getAttribute("fy")
if s.endswith("%"):
fy = self.width * float(s[:-1]) / 100.0
else:
fy = parse_float(s)
else:
fy = cy
matrix = get_gradientTransform(n)
stops = self.get_stops(n)
self.defs[kid] = ("radialGradient", cx, cy, r, fx, fy, stops, matrix)
def def_clipPath(self, node):
kid = node.getAttribute("id")
# only a single path is implemented
for n in node.childNodes:
if n.nodeType != Node.ELEMENT_NODE or n.tagName != "path":
continue
m = parse_transform(n)
d = n.getAttribute("d")
output = cStringIO.StringIO()
parse_path(output, d)
path = output.getvalue()
output.close()
self.defs[kid] = ("clipPath", m, path)
return
def def_g(self, group):
for n in group.childNodes:
if n.nodeType != Node.ELEMENT_NODE:
continue
if hasattr(self, "def_" + n.tagName):
getattr(self, "def_" + n.tagName)(n)
def def_defs(self, node):
self.def_g(node)
# --------------------------------------------------------------------
def parse_attributes(self, n):
pattr = self.attributes[-1]
attr = { }
for a in attribute_names:
if n.hasAttribute(a):
attr[a] = n.getAttribute(a)
else:
attr[a] = pattr[a]
if n.hasAttribute("style"):
sdict = parse_style(n.getAttribute("style"))
for a in attribute_names:
if a in sdict:
attr[a] = sdict[a]
return attr
def write_pathattributes(self, a):
stroke = parse_color(a["stroke"])
if stroke:
self.out.write(' stroke="%g %g %g"' % stroke)
fill = a["fill"]
if fill and fill.startswith("url("):
mat = re.match("url\(#([^)]+)\).*", fill)
if mat:
grad = mat.group(1)
if grad in self.defs and (self.defs[grad][0] == "linearGradient" or
self.defs[grad][0] == "radialGradient"):
self.out.write(' fill="1" gradient="g%s"' % grad)
else:
fill = parse_color(a["fill"])
if fill:
self.out.write(' fill="%g %g %g"' % fill)
opacity = parse_opacity(a["opacity"])
fill_opacity = parse_opacity(a["fill-opacity"])
stroke_opacity = parse_opacity(a["stroke-opacity"])
if fill and fill_opacity:
opacity = fill_opacity
if not fill and stroke and stroke_opacity:
opacity = stroke_opacity
if opacity and opacity != 100:
self.out.write(' opacity="%d%%"' % opacity)
stroke_width = parse_float(a["stroke-width"])
if a["stroke-width"]:
self.out.write(' pen="%g"' % stroke_width)
if a["fill-rule"] == "nonzero":
self.out.write(' fillrule="wind"')
k = {"butt" : 0, "round" : 1, "square" : 2 }
if a["stroke-linecap"] in k:
self.out.write(' cap="%d"' % k[a["stroke-linecap"]])
k = {"miter" : 0, "round" : 1, "bevel" : 2 }
if a["stroke-linejoin"] in k:
self.out.write(' join="%d"' % k[a["stroke-linejoin"]])
dasharray = a["stroke-dasharray"]
dashoffset = a["stroke-dashoffset"]
if dasharray and dashoffset and dasharray != "none":
d = parse_list(dasharray)
off = parse_float(dashoffset)
self.out.write(' dash="[%s] %g"' % (" ".join(d), off))
# --------------------------------------------------------------------
def node_g(self, group):
# printAttributes(group)
attr = self.parse_attributes(group)
self.attributes.append(attr)
self.out.write('\n')
for n in group.childNodes:
if n.nodeType != Node.ELEMENT_NODE:
continue
if hasattr(self, "node_" + n.tagName):
getattr(self, "node_" + n.tagName)(n)
else:
sys.stderr.write("Unhandled node: %s\n" % n.tagName)
self.out.write('\n')
self.attributes.pop()
def collect_text(self, root):
for n in root.childNodes:
if n.nodeType == Node.TEXT_NODE:
self.text += n.data
if n.nodeType != Node.ELEMENT_NODE:
continue
if n.tagName == "tspan": # recurse
self.collect_text(n)
def node_text(self, t):
if not t.hasAttribute("x") or not t.hasAttribute("y"):
sys.stderr.write("Text without coordinates ignored\n")
return
x = float(t.getAttribute("x"))
y = float(t.getAttribute("y"))
attr = self.parse_attributes(t)
self.out.write('%s\n' % self.text.encode("UTF-8"))
def node_image(self, node):
if not have_pil:
sys.stderr.write("No Python image library, ignored\n")
return
href = node.getAttribute("xlink:href")
if not href.startswith("data:image/png;base64,"):
sys.stderr.write("Image ignored, href = %s...\n" % href[:40])
return
x = float(node.getAttribute("x"))
y = float(node.getAttribute("y"))
w = float(node.getAttribute("width"))
h = float(node.getAttribute("height"))
clipped = False
if node.hasAttribute("clip-path"):
mat = re.match("url\(#([^)]+)\).*", node.getAttribute("clip-path"))
if mat:
cp = mat.group(1)
if cp in self.defs and self.defs[cp][0] == "clipPath":
cp, m, path = self.defs[cp]
clipped = True
self.out.write('\n' % (str(m), path))
self.out.write('\n' % str(m.inverse()))
self.out.write(' \n')
if True:
data = cStringIO.StringIO()
for pixel in image.getdata():
data.write("%c%c%c" % pixel[:3])
self.out.write(base64.b64encode(data.getvalue()))
data.close()
else:
count = 0
for pixel in image.getdata():
self.out.write("%02x%02x%02x" % pixel[:3])
count += 1
if count == 10:
self.out.write("\n")
count = 0
fin.close()
self.out.write('\n')
if clipped:
self.out.write('\n\n')
# handled in def pass
def node_linearGradient(self, n):
pass
def node_radialGradient(self, n):
pass
def node_rect(self, n):
attr = self.parse_attributes(n)
self.out.write('\n')
x = float(n.getAttribute("x"))
y = float(n.getAttribute("y"))
w = float(n.getAttribute("width"))
h = float(n.getAttribute("height"))
self.out.write("%g %g m %g %g l %g %g l %g %g l h\n" %
(x, y, x + w, y, x + w, y + h, x, y + h))
self.out.write('\n')
def node_circle(self, n):
self.out.write('\n')
cx = float(n.getAttribute("cx"))
cy = float(n.getAttribute("cy"))
r = float(n.getAttribute("r"))
self.out.write("%g 0 0 %g %g %g e\n" % (r, r, cx, cy))
self.out.write('\n')
def node_ellipse(self, n):
self.out.write('\n')
cx = 0
cy = 0
if n.hasAttribute("cx"):
cx = float(n.getAttribute("cx"))
if n.hasAttribute("cy"):
cy = float(n.getAttribute("cy"))
rx = float(n.getAttribute("rx"))
ry = float(n.getAttribute("ry"))
self.out.write("%g 0 0 %g %g %g e\n" % (rx, ry, cx, cy))
self.out.write('\n')
def node_line(self, n):
self.out.write('\n')
x1 = 0; y1 = 0; x2 = 0; y2 = 0
if n.hasAttribute("x1"):
x1 = float(n.getAttribute("x1"))
if n.hasAttribute("y1"):
y1 = float(n.getAttribute("y1"))
if n.hasAttribute("x2"):
x2 = float(n.getAttribute("x2"))
if n.hasAttribute("y2"):
y2 = float(n.getAttribute("y2"))
self.out.write("%g %g m %g %g l\n" % (x1, y1, x2, y2))
self.out.write('\n')
def node_polyline(self, n):
self.polygon(n, closed=False)
def node_polygon(self, n):
self.polygon(n, closed=True)
def polygon(self, n, closed):
self.out.write('\n')
d = parse_list(n.getAttribute("points"))
op = "m"
while d:
x = float(d.pop(0))
y = float(d.pop(0))
self.out.write("%g %g %s\n" % (x, y, op))
op = "l"
if closed:
self.out.write("h\n")
self.out.write('\n')
def node_path(self, n):
self.out.write('\n')
d = n.getAttribute("d")
parse_path(self.out, d)
self.out.write('\n')
# --------------------------------------------------------------------
def main():
if len(sys.argv) != 2 and len(sys.argv) != 3:
sys.stderr.write("Usage: svgtoipe [ ]\n")
return
fname = sys.argv[1]
if len(sys.argv) > 2:
outname = sys.argv[2]
else:
if fname[-4:].lower() == ".svg":
outname = fname[:-4] + ".ipe"
else:
outname = fname + ".ipe"
svg = Svg(fname)
svg.parse_svg(outname)
if __name__ == '__main__':
main()
# --------------------------------------------------------------------