summaryrefslogtreecommitdiffstats
path: root/share/extensions/guillotine.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions/guillotine.py')
-rw-r--r--share/extensions/guillotine.py258
1 files changed, 258 insertions, 0 deletions
diff --git a/share/extensions/guillotine.py b/share/extensions/guillotine.py
new file mode 100644
index 000000000..bda56b206
--- /dev/null
+++ b/share/extensions/guillotine.py
@@ -0,0 +1,258 @@
+#!/usr/bin/env python
+'''
+guillotine.py
+
+Copyright (C) 2010 Craig Marshall, craig9 [at] gmail.com
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+-----------------------
+
+This script slices an inkscape drawing along the guides, similarly to
+the GIMP plugin called "guillotine". It can optionally export to the
+same directory as the SVG file with the same name, but with a number
+suffix. e.g.
+
+/home/foo/drawing.svg
+
+will export to:
+
+/home/foo/drawing0.png
+/home/foo/drawing1.png
+/home/foo/drawing2.png
+/home/foo/drawing3.png
+
+etc.
+
+'''
+
+import os
+import sys
+import inkex
+import simplestyle
+import locale
+import gettext
+_ = gettext.gettext
+
+locale.setlocale(locale.LC_ALL, '')
+
+try:
+ from subprocess import Popen, PIPE
+ bsubprocess = True
+except:
+ bsubprocess = False
+
+def float_sort(a, b):
+ '''
+ This is used to sort the horizontal and vertical guide positions,
+ which are floating point numbers, but which are held as text.
+ '''
+ return cmp(float(a), float(b))
+
+class Guillotine(inkex.Effect):
+ """Exports slices made using guides"""
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("--directory", action="store",
+ type="string", dest="directory",
+ default=None, help="")
+
+ self.OptionParser.add_option("--image", action="store",
+ type="string", dest="image",
+ default=None, help="")
+
+ self.OptionParser.add_option("--ignore", action="store",
+ type="inkbool", dest="ignore",
+ default=None, help="")
+
+ def get_guides(self):
+ '''
+ Returns all guide elements as an iterable collection
+ '''
+ root = self.document.getroot()
+ guides = []
+ xpath = self.document.xpath("//sodipodi:guide",
+ namespaces=inkex.NSS)
+ for g in xpath:
+ guide = {}
+ (x, y) = g.attrib['position'].split(',')
+ if g.attrib['orientation'] == '0,1':
+ guide['orientation'] = 'horizontal'
+ guide['position'] = y
+ guides.append(guide)
+ elif g.attrib['orientation'] == '1,0':
+ guide['orientation'] = 'vertical'
+ guide['position'] = x
+ guides.append(guide)
+ return guides
+
+ def get_all_horizontal_guides(self):
+ '''
+ Returns all horizontal guides as a list of floats stored as
+ strings. Each value is the position from 0 in pixels.
+ '''
+ guides = []
+ for g in self.get_guides():
+ if g['orientation'] == 'horizontal':
+ guides.append(g['position'])
+ return guides
+
+ def get_all_vertical_guides(self):
+ '''
+ Returns all vertical guides as a list of floats stored as
+ strings. Each value is the position from 0 in pixels.
+ '''
+ guides = []
+ for g in self.get_guides():
+ if g['orientation'] == 'vertical':
+ guides.append(g['position'])
+ return guides
+
+ def get_horizontal_slice_positions(self):
+ '''
+ Make a sorted list of all horizontal guide positions,
+ including 0 and the document height, but not including
+ those outside of the canvas
+ '''
+ root = self.document.getroot()
+ horizontals = ['0']
+ height = inkex.unittouu(root.attrib['height'])
+ for h in self.get_all_horizontal_guides():
+ if h >= 0 and float(h) <= float(height):
+ horizontals.append(h)
+ horizontals.append(height)
+ horizontals.sort(cmp=float_sort)
+ return horizontals
+
+ def get_vertical_slice_positions(self):
+ '''
+ Make a sorted list of all vertical guide positions,
+ including 0 and the document width, but not including
+ those outside of the canvas.
+ '''
+ root = self.document.getroot()
+ verticals = ['0']
+ width = inkex.unittouu(root.attrib['width'])
+ for v in self.get_all_vertical_guides():
+ if v >= 0 and float(v) <= float(width):
+ verticals.append(v)
+ verticals.append(width)
+ verticals.sort(cmp=float_sort)
+ return verticals
+
+ def get_slices(self):
+ '''
+ Returns a list of all "slices" as denoted by the guides
+ on the page. Each slice is really just a 4 element list of
+ floats (stored as strings), consisting of the X and Y start
+ position and the X and Y end position.
+ '''
+ hs = self.get_horizontal_slice_positions()
+ vs = self.get_vertical_slice_positions()
+ slices = []
+ for i in range(len(hs)-1):
+ for j in range(len(vs)-1):
+ slices.append([vs[j], hs[i], vs[j+1], hs[i+1]])
+ return slices
+
+ def get_filename_parts(self):
+ '''
+ Attempts to get directory and image as passed in by the inkscape
+ dialog. If the boolean ignore flag is set, then it will ignore
+ these settings and try to use the settings from the export
+ filename.
+ '''
+
+ if self.options.ignore == False:
+ if self.options.image == "" or self.options.image is None:
+ inkex.errormsg("Please enter an image name")
+ sys.exit(0)
+ return (self.options.directory, self.options.image)
+ else:
+ '''
+ First get the export-filename from the document, if the
+ document has been exported before (TODO: Will not work if it
+ hasn't been exported yet), then uses this to return a tuple
+ consisting of the directory to export to, and the filename
+ without extension.
+ '''
+ svg = self.document.getroot()
+ att = '{http://www.inkscape.org/namespaces/inkscape}export-filename'
+ try:
+ export_file = svg.attrib[att]
+ except KeyError:
+ inkex.errormsg("To use the export hints option, you " +
+ "need to have previously exported the document. " +
+ "Otherwise no export hints exist!")
+ sys.exit(-1)
+ dirname, filename = os.path.split(export_file)
+ filename = filename.rsplit(".", 1)[0] # Without extension
+ return (dirname, filename)
+
+ def check_dir_exists(self, dir):
+ if not os.path.isdir(dir):
+ os.makedirs(dir)
+
+ def get_localised_string(self, str):
+ return locale.format("%.f", float(str), 0)
+
+ def export_slice(self, s, filename):
+ '''
+ Runs inkscape's command line interface and exports the image
+ slice from the 4 coordinates in s, and saves as the filename
+ given.
+ '''
+ svg_file = self.args[-1]
+ command = "inkscape -a %s:%s:%s:%s -e \"%s\" \"%s\" " % (self.get_localised_string(s[0]), self.get_localised_string(s[1]), self.get_localised_string(s[2]), self.get_localised_string(s[3]), filename, svg_file)
+ if bsubprocess:
+ p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)
+ return_code = p.wait()
+ f = p.stdout
+ err = p.stderr
+ else:
+ _, f, err = os.open3(command)
+ f.close()
+
+ def export_slices(self, slices):
+ '''
+ Takes the slices list and passes each one with a calculated
+ filename/directory into export_slice.
+ '''
+ dirname, filename = self.get_filename_parts()
+ output_files = list()
+ if dirname == '' or dirname == None:
+ dirname = './'
+
+ dirname = os.path.expanduser(dirname)
+ dirname = os.path.expandvars(dirname)
+ dirname = os.path.abspath(dirname)
+ if dirname[-1] != os.path.sep:
+ dirname += os.path.sep
+ self.check_dir_exists(dirname)
+ i = 0
+ for s in slices:
+ f = dirname + filename + str(i) + ".png"
+ output_files.append(f)
+ self.export_slice(s, f)
+ i += 1
+ inkex.errormsg(_("The sliced bitmaps have been saved as:") + "\n\n" + "\n".join(output_files))
+
+ def effect(self):
+ slices = self.get_slices()
+ self.export_slices(slices)
+
+if __name__ == "__main__":
+ e = Guillotine()
+ e.affect()