From 2bdad40a35b3ea713a74f5606b646a13b672aaf3 Mon Sep 17 00:00:00 2001 From: JazzyNico Date: Wed, 25 Aug 2010 06:43:37 +0200 Subject: [PATCH] Extensions. New guillotine extension (testing). --- po/POTFILES.in | 2 + share/extensions/Makefile.am | 2 + share/extensions/guillotine.inx | 26 ++++ share/extensions/guillotine.py | 248 ++++++++++++++++++++++++++++++++ 4 files changed, 278 insertions(+) create mode 100644 share/extensions/guillotine.inx create mode 100644 share/extensions/guillotine.py diff --git a/po/POTFILES.in b/po/POTFILES.in index 0fdec6a4e..ab7222d17 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -58,6 +58,7 @@ [type: gettext/xml] share/extensions/grid_cartesian.inx [type: gettext/xml] share/extensions/grid_polar.inx [type: gettext/xml] share/extensions/guides_creator.inx +[type: gettext/xml] share/extensions/guillotine.inx [type: gettext/xml] share/extensions/handles.inx [type: gettext/xml] share/extensions/hpgl_output.inx [type: gettext/xml] share/extensions/inkscape_help_askaquestion.inx @@ -510,6 +511,7 @@ share/extensions/web-transmit-att.py [type: gettext/xml] share/extensions/grid_cartesian.inx [type: gettext/xml] share/extensions/grid_polar.inx [type: gettext/xml] share/extensions/guides_creator.inx +[type: gettext/xml] share/extensions/guillotine.inx [type: gettext/xml] share/extensions/handles.inx [type: gettext/xml] share/extensions/hpgl_output.inx [type: gettext/xml] share/extensions/inkscape_help_askaquestion.inx diff --git a/share/extensions/Makefile.am b/share/extensions/Makefile.am index 78532f939..36a25d56f 100644 --- a/share/extensions/Makefile.am +++ b/share/extensions/Makefile.am @@ -67,6 +67,7 @@ extensions = \ grid_cartesian.py \ grid_polar.py \ guides_creator.py \ + guillotine.py \ handles.py \ hpgl_output.py \ ill2svg.pl \ @@ -221,6 +222,7 @@ modules = \ grid_cartesian.inx \ grid_polar.inx \ guides_creator.inx \ + guillotine.inx \ handles.inx \ hpgl_output.inx \ inkscape_help_askaquestion.inx \ diff --git a/share/extensions/guillotine.inx b/share/extensions/guillotine.inx new file mode 100644 index 000000000..ba88f668c --- /dev/null +++ b/share/extensions/guillotine.inx @@ -0,0 +1,26 @@ + + + <_name>Guillotine + org.inkscape.guillotine + + org.inkscape.output.svg.inkscape + + guillotine.py + inkex.py + + ~/ + guillotined + false + + + all + + + + + + + + diff --git a/share/extensions/guillotine.py b/share/extensions/guillotine.py new file mode 100644 index 000000000..7c43daa6d --- /dev/null +++ b/share/extensions/guillotine.py @@ -0,0 +1,248 @@ +#!/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 + +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: + 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() + if dirname == '' or dirname == None: + dirname = './' + inkex.errormsg(dirname) + dirname = os.path.expanduser(dirname) + dirname = os.path.expandvars(dirname) + self.check_dir_exists(dirname) + i = 0 + for s in slices: + f = dirname + os.path.sep + filename + str(i) + ".png" + self.export_slice(s, f) + i += 1 + + def effect(self): + slices = self.get_slices() + self.export_slices(slices) + +if __name__ == "__main__": + e = Guillotine() + e.affect() + -- 2.30.2