]> git.donarmstrong.com Git - bin.git/blob - svgtune
remove convert_to_xls and .sa_bin
[bin.git] / svgtune
1 #!/usr/bin/python
2 # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
3 # vi: set ft=python sts=4 ts=4 sw=4 et:
4 """
5   Yaroslav Halchenko
6   web:     http://www.onerussian.com
7   e-mail:  yoh@onerussian.com
8
9  DESCRIPTION (NOTES):
10
11     See README.rst shipped with this tool.
12     "Homepage" for the tool is http://github.com/yarikoptic/svgtune
13
14  Copyright (C) 2009, Yaroslav Halchenko
15
16  LICENSE:
17
18   This program is free software; you can redistribute it and/or modify
19   it under the terms of the GNU General Public License as published by
20   the Free Software Foundation; either version 2 of the License, or
21   (at your option) any later version.
22
23   This program is distributed in the hope that it will be useful,
24   but WITHOUT ANY WARRANTY; without even the implied warranty of
25   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26   GNU General Public License for more details.
27
28   You should have received a copy of the GNU General Public License
29   along with this program; if not, write to the
30   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
31   MA 02110-1301, USA.
32
33  On Debian system see /usr/share/common-licenses/GPL for the full license.
34 """
35
36 __author__ = 'Yaroslav Halchenko'
37 __version__ = (0, 1, 0)
38 __copyright__ = 'Copyright (c) 2009-2010 Yaroslav Halchenko'
39 __license__ = 'GPL'
40
41 import os, re
42 from optparse import OptionParser
43
44 def split2(l, msg, sep=' '):
45     """Split l into 2 pieces using ' ' as a separator
46     """
47     p = [x.strip() for x in (l.split(sep, 1)) if x != '']
48
49     if len(p) != 2:
50         raise ValueError, msg + '. Got %s for "%s"' % (str(p), l)
51
52     return p
53
54
55 def replace_key(attr_value, key, value):
56     """Replace value for a given key
57        If key is not found, new one is added
58     """
59     v = attr_value.split(';')
60     changed = False
61     newval = '%s:%s' % (key, value)
62     for i in xrange(len(v)):
63         if v[i].startswith(key + ':'):
64             v[i] = newval
65             changed = True
66     if not changed:
67         # Wasn't found -- add one
68         v += [newval]
69     return ';'.join([x for x in v if x.strip() != ''])
70
71
72 def change_attr(el, attr, values):
73     """Change values listed within attribute attr
74     """
75     v = el.attrib.get(attr, '')
76     changed = False
77     for value in values.split(';'):
78         k, newv = split2(value, "Each value must be in the form x:y", ":")
79         v = replace_key(v, k, newv)
80     if v == '':                         # there were no such yet
81         v = "%s:%s" % (k, newv)
82     #print "Changing %s : %s, got %s" % (attr, values, str(v))
83     el.attrib[attr] = v
84
85 def verbose(level, str_):
86     if level <= options.verbose:
87         print " "*level, str_
88
89 def version():
90     print "svgtune v" + ".".join(__version__)
91     raise SystemExit
92
93 def process_options(params, options):
94     # For now simply split by space
95     option_values = params.split(' ')
96     for option_value in option_values:
97         t = option_value.split('=', 1)
98         option = t[0]
99         if len(t) > 1: value = t[1]
100         else:          value = None
101         if option == "previews":
102             # if only said "previews" assume that we want them
103             if value is None: value = True
104             options.previews = bool(value)
105         else:
106             raise ValueError, "Unknown option %s", option
107     pass
108
109
110 def load_svg(svgfile):
111     verbose(1, "Processing file %s for tuning" % svgfile)
112     svgdoc = etree.parse(svgfile)
113     svg = svgdoc.getroot()
114
115     dname = '%s_tuned' % os.path.splitext(svgfile)[0]
116     try:
117         os.mkdir(dname)
118     except:
119         pass # if directory exists or hell with everything
120     return svg, svgdoc, dname
121
122 parser = OptionParser(usage="%prog [options] inputfile.svgtune",
123                       version="%prog version "
124                               + ".".join([str(i) for i in __version__]))
125 parser.add_option("-v", action="count", dest="verbose",
126                   help="Increase verbosity with multiple -v")
127 parser.add_option("-p", "--previews", action="store_true",
128                   dest="previews", help="Store preview png's")
129
130 (options, args) = parser.parse_args()
131
132 if len(args) != 1:
133     raise SystemExit, \
134           "Error: Please provide single input file with instructions."
135
136 # Now we can load lxml
137 from lxml import etree
138
139 ifile = args[0]
140 # ifile = '/tmp/1.svgi'
141 svgfile = None
142 svg = None
143 dname = None
144
145 for line_ in open(ifile).readlines():
146     line = line_.strip()
147     if line.startswith('#') or line == '':
148         continue
149
150     # parse out first element
151     cmd, params = split2(line, "Each line must be 'command parameters'")
152
153     if cmd == '%file':
154         svg, svgdoc, dname = load_svg(params)
155         continue
156     elif cmd == "%options":
157         process_options(params, options)
158         continue
159
160     # We must have file loaded by now
161     if svg is None:
162         svgfile = os.path.splitext(ifile)[0] + '.svg'
163         try:
164             svg, svgdoc, dname = load_svg(svgfile)
165         except Exception, e:
166             raise RuntimeError, \
167                   "Tried to load from %s but failed due to %s.\n" \
168                   "Please provide %%file directive to load the file prior %s " \
169                   "or have .svg file with the same name as .svgtune." \
170                   % (svgfile, e, cmd)
171
172     if cmd == '%save':
173         ofile = '%s/%s.svg' % (dname, params)
174         verbose(1, " Storing into %s" % ofile)
175         file(ofile, 'w').write(
176             etree.tostring(svgdoc, pretty_print=True))
177         if options.previews:
178             verbose(3, "Generating preview")
179             os.system('inkscape -z -f %s -e %s -d 90 >/dev/null 2>&1' %
180                       (ofile, ofile.replace('.svg', '_preview.png')))
181         continue
182
183     #
184     # Figure out the victims for changes -- victims
185     victims = None
186     if cmd == 'layers':
187         changes = params
188         victims = svg.findall('.//{%s}g[@{%s}groupmode="layer"]'
189                               % (svg.nsmap['svg'], svg.nsmap['inkscape']))
190     elif cmd in ['layer', 'g', 'text']:
191         # parse out first element
192         identifier, changes = split2(params,
193                    "For each layer or g you must list id or label + changes")
194
195         # determine the victims
196         sid = ''
197         if cmd == 'layer':
198             sid += '[@{%s}groupmode="layer"]' % svg.nsmap['inkscape']
199
200         id1, id2 = identifier.split('=')
201         sid_re_attr = None             # either we need to do re.search
202         sid_re_str = id2
203         if id1 == 'label':
204             sid += '[@{%s}label="%s"]' % (svg.nsmap['inkscape'], id2)
205         elif id1 == 'id':
206             sid += '[@id="%s"]' % (id2)
207         elif id1 == 'href':
208             sid += '[@{%s}href="%s"]' % (svg.nsmap['xlink'], id2)
209         elif id1 == 'href:re':
210             sid += '{%s}href' % svg.nsmap['xlink']
211             print svg.nsmap['xlink']
212             print sid
213         elif id1 == 'label:re':
214             sid_re_attr = '{%s}label' % svg.nsmap['inkscape']
215         elif id1 == 'id:re':
216             sid_re_attr = 'id'
217         else:
218             raise ValueError, "Unknown identifier %s in %s" % (id1, line)
219
220         victims = svg.findall('.//{%s}g%s' % (svg.nsmap['svg'], sid))
221
222         # optionally perform search using re
223         if sid_re_attr is not None:
224             regexp = re.compile(sid_re_str)
225             victims = [v for v in victims
226                        if regexp.search(v.attrib[sid_re_attr])]
227
228         nvictims = len(victims)
229         if nvictims == 0:
230             raise ValueError, "Cannot find any victim for '%s'" % identifier
231         elif nvictims > 1 and sid_re_attr is None:
232             raise ValueError, "We should get a single victim for %s " \
233                   "but got %d of them" % (identifier, nvictims)
234     else:
235         raise ValueError, "Unknown command '%s'." % cmd
236
237     #
238     # Figure out the actual changes to take and do them
239     for change in changes.split(' '):
240         if change == '':
241             continue
242         attr, values = split2(change,
243                         'Each change should be listed as attribute=value', '=')
244         if attr == 'style':
245             func = lambda vic: change_attr(vic, attr, values)
246         else:
247             raise ValueError, "Don't yet handle attribute %s" % attr
248
249         for victim in victims:
250             func(victim)
251