1
|
|
|
from SCons.Script import * |
2
|
|
|
|
3
|
|
|
from xml.dom.minidom import parse as parseXml |
4
|
|
|
|
5
|
|
|
def svg2pgf_shape(filename): |
6
|
|
|
''' |
7
|
|
|
Convert given SVG file to TiKZ code. |
8
|
|
|
''' |
9
|
|
|
xml = parseXml(filename) |
10
|
|
|
# determine size of the picture from SVG source |
11
|
|
|
svg = xml.getElementsByTagName('svg')[0] |
12
|
|
|
name = svg.attributes['id'].value |
13
|
|
|
height = int(svg.attributes['height'].value) |
14
|
|
|
width = int(svg.attributes['width'].value) |
15
|
|
|
# Define shape anchors, based on image size |
16
|
|
|
# We need double backslashes since the output is Python again |
17
|
|
|
# The SVG coordinate system is mirrored on the horizon axis, so we add a rotation command and a positional compensation |
18
|
|
|
result = ''' |
19
|
|
|
\\\\pgfdeclareshape{%(name)s}{ |
20
|
|
|
\\\\anchor{center}{\pgfpoint{%(halfwidth)u}{%(halfheight)u}} |
21
|
|
|
\\\\anchor{north}{\pgfpoint{%(halfwidth)u}{%(height)u}} |
22
|
|
|
\\\\anchor{south}{\pgfpoint{%(halfwidth)u}{0}} |
23
|
|
|
\\\\anchor{west}{\pgfpoint{0}{%(halfheight)u}} |
24
|
|
|
\\\\anchor{east}{\pgfpoint{%(width)u}{%(halfheight)u}} |
25
|
|
|
\\\\foregroundpath{ |
26
|
|
|
\\\\pgfsetlinewidth{1.4} |
27
|
|
|
\\\\pgftransformshift{\pgfpoint{%(width)u}{%(height)u}} |
28
|
|
|
\\\\pgftransformrotate{180} |
29
|
|
|
\\\\pgfsetfillcolor{white} |
30
|
|
|
'''%{'name':name, 'height':height, 'halfheight':height/2, 'width':width, 'halfwidth':width/2} |
31
|
|
|
# add all SVG path |
32
|
|
|
pathCommands = xml.getElementsByTagName('path') |
33
|
|
|
for p in pathCommands: |
34
|
|
|
# The path may have styling. We ignore everything but dashing. |
35
|
|
|
if p.attributes.has_key('style'): |
36
|
|
|
if 'stroke-dasharray' in p.attributes['style'].value: |
37
|
|
|
# http://stuff.mit.edu/afs/athena/contrib/tex-contrib/beamer/pgf-1.01/doc/generic/pgf/version-for-tex4ht/en/pgfmanualse23.html |
38
|
|
|
result += " \\\\pgfsetdash{{4.2}{1.4}}{0}\n" |
39
|
|
|
# Add the SVG path |
40
|
|
|
result +=" \\\\pgfpathsvg{%s}\n"%p.attributes['d'].value |
41
|
|
|
# add all SVG rectangle definitions |
42
|
|
|
# Add usepath after each rectangle, in order to get overlayed filled rects correctly generated |
43
|
|
|
rectCommands = xml.getElementsByTagName('rect') |
44
|
|
|
for r in rectCommands: |
45
|
|
|
rheight = float(r.attributes['height'].value) |
46
|
|
|
rwidth = float(r.attributes['width'].value) |
47
|
|
|
x = float(r.attributes['x'].value) |
48
|
|
|
y = float(r.attributes['y'].value) |
49
|
|
|
result += " \\\\pgfrect{\pgfpoint{%f}{%f}}{\pgfpoint{%f}{%f}}\n\\\\pgfusepath{stroke, fill}\n"%(x, y, rwidth, rheight) |
50
|
|
|
# add all SVG circle definitions |
51
|
|
|
circleCommands = xml.getElementsByTagName('circle') |
52
|
|
|
for c in circleCommands: |
53
|
|
|
x = float(c.attributes['cx'].value) |
54
|
|
|
y = float(c.attributes['cy'].value) |
55
|
|
|
radius = float(c.attributes['r'].value) |
56
|
|
|
result += " \\\\pgfcircle{\pgfpoint{%f}{%f}}{%f}\n\\\\pgfusepath{stroke, fill}\n"%(x,y,radius) |
57
|
|
|
# finalize TiKZ shape definition |
58
|
|
|
result += ' \\\\pgfusepath{stroke}\n}}' |
59
|
|
|
return result |
60
|
|
|
|
61
|
|
|
def build_shape_lib_recursive(sources, covered=[]): |
62
|
|
|
''' |
63
|
|
|
Build static LaTex representation for our graphical symbols as TiKZ shapes. |
64
|
|
|
Some SVGs occur multiple times in subdirectories, so we track the already |
65
|
|
|
converted ones. |
66
|
|
|
''' |
67
|
|
|
result = '' |
68
|
|
|
for f in sources: |
69
|
|
|
try: |
70
|
|
|
result += svg2pgf_shape(str(f)) |
71
|
|
|
print "Converting %s to TiKZ shape ..."%f |
72
|
|
|
except Exception, e: |
73
|
|
|
print "Error on parsing, ignoring %s ..."%f |
74
|
|
|
print e |
75
|
|
|
return result |
76
|
|
|
|
77
|
|
|
def createTikzLib(target, source, env): |
78
|
|
|
'''Builds TiKZ shape library needed for Latex export / rendedering server.''' |
79
|
|
|
print "Generating TiKZ shape library ..." |
80
|
|
|
f=open(str(target[0]),"w") |
81
|
|
|
f.write("# Auto-generated, do not change !\n") |
82
|
|
|
f.write("tikz_shapes='''") |
83
|
|
|
f.write("\n%% Start of shape library. This part remains the same for all graph exports.") |
84
|
|
|
f.write(build_shape_lib_recursive(source)) |
85
|
|
|
f.write("\n%% End of shape library. This part below is unique for all graph exports.\n") |
86
|
|
|
f.write("'''") |
87
|
|
|
f.close() |
88
|
|
|
|
89
|
|
|
tikzbuilder = Builder(action = createTikzLib) |
90
|
|
|
|
91
|
|
|
|