summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 484639a)
raw | patch | inline | side by side (parent: 484639a)
author | JazzyNico <nicoduf@yahoo.fr> | |
Wed, 25 Aug 2010 04:43:37 +0000 (06:43 +0200) | ||
committer | JazzyNico <nicoduf@yahoo.fr> | |
Wed, 25 Aug 2010 04:43:37 +0000 (06:43 +0200) |
po/POTFILES.in | patch | blob | history | |
share/extensions/Makefile.am | patch | blob | history | |
share/extensions/guillotine.inx | [new file with mode: 0644] | patch | blob |
share/extensions/guillotine.py | [new file with mode: 0644] | patch | blob |
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0fdec6a4ebf804f2f549d9ee59bc4aaa2f5d3cae..ab7222d176da36fd37df1aa93a4764721f3feb3a 100644 (file)
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
[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
[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
index 78532f9391bea59440ba55833a1d72598a1331ac..36a25d56f84b0d6add117390aa370409a632d38e 100644 (file)
grid_cartesian.py \
grid_polar.py \
guides_creator.py \
+ guillotine.py \
handles.py \
hpgl_output.py \
ill2svg.pl \
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
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">\r
+ <_name>Guillotine</_name>\r
+ <id>org.inkscape.guillotine</id>\r
+ \r
+ <dependency type="extension">org.inkscape.output.svg.inkscape</dependency>\r
+ \r
+ <dependency type="executable" location="extensions">guillotine.py</dependency>\r
+ <dependency type="executable" location="extensions">inkex.py</dependency>\r
+ \r
+ <param name="directory" type="string" _gui-text="Directory to save images to">~/</param>\r
+ <param name="image" type="string" _gui-text="Image name (without extension)">guillotined</param>\r
+ <param name="ignore" type="boolean" _gui-text="Ignore these settings and use export hints?">false</param>\r
+ \r
+ <effect needs-live-preview="false">\r
+ <object-type>all</object-type>\r
+ <effects-menu>\r
+ <submenu _name="Export"/>\r
+ </effects-menu>\r
+ </effect>\r
+ \r
+ <script>\r
+ <command reldir="extensions" interpreter="python">guillotine.py</command>\r
+ </script>\r
+ \r
+</inkscape-extension>\r
diff --git a/share/extensions/guillotine.py b/share/extensions/guillotine.py
--- /dev/null
@@ -0,0 +1,248 @@
+#!/usr/bin/env python \r
+'''\r
+guillotine.py\r
+\r
+Copyright (C) 2010 Craig Marshall, craig9 [at] gmail.com\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+-----------------------\r
+\r
+This script slices an inkscape drawing along the guides, similarly to \r
+the GIMP plugin called "guillotine". It can optionally export to the \r
+same directory as the SVG file with the same name, but with a number\r
+suffix. e.g. \r
+\r
+/home/foo/drawing.svg\r
+\r
+will export to:\r
+\r
+/home/foo/drawing0.png\r
+/home/foo/drawing1.png\r
+/home/foo/drawing2.png\r
+/home/foo/drawing3.png\r
+\r
+etc.\r
+\r
+'''\r
+\r
+import os\r
+import sys\r
+import inkex\r
+import simplestyle\r
+import locale\r
+\r
+locale.setlocale(locale.LC_ALL, '')\r
+\r
+try:\r
+ from subprocess import Popen, PIPE\r
+ bsubprocess = True\r
+except:\r
+ bsubprocess = False\r
+\r
+def float_sort(a, b):\r
+ '''\r
+ This is used to sort the horizontal and vertical guide positions,\r
+ which are floating point numbers, but which are held as text.\r
+ '''\r
+ return cmp(float(a), float(b))\r
+\r
+class Guillotine(inkex.Effect):\r
+ """Exports slices made using guides"""\r
+ def __init__(self):\r
+ inkex.Effect.__init__(self) \r
+ self.OptionParser.add_option("--directory", action="store", \r
+ type="string", dest="directory",\r
+ default=None, help="")\r
+ \r
+ self.OptionParser.add_option("--image", action="store", \r
+ type="string", dest="image", \r
+ default=None, help="")\r
+ \r
+ self.OptionParser.add_option("--ignore", action="store", \r
+ type="inkbool", dest="ignore", \r
+ default=None, help="")\r
+ \r
+ def get_guides(self):\r
+ '''\r
+ Returns all guide elements as an iterable collection\r
+ '''\r
+ root = self.document.getroot()\r
+ guides = []\r
+ xpath = self.document.xpath("//sodipodi:guide", \r
+ namespaces=inkex.NSS)\r
+ for g in xpath:\r
+ guide = {}\r
+ (x, y) = g.attrib['position'].split(',')\r
+ if g.attrib['orientation'] == '0,1':\r
+ guide['orientation'] = 'horizontal'\r
+ guide['position'] = y\r
+ guides.append(guide)\r
+ elif g.attrib['orientation'] == '1,0':\r
+ guide['orientation'] = 'vertical'\r
+ guide['position'] = x\r
+ guides.append(guide)\r
+ return guides\r
+ \r
+ def get_all_horizontal_guides(self):\r
+ '''\r
+ Returns all horizontal guides as a list of floats stored as \r
+ strings. Each value is the position from 0 in pixels.\r
+ '''\r
+ guides = []\r
+ for g in self.get_guides():\r
+ if g['orientation'] == 'horizontal':\r
+ guides.append(g['position'])\r
+ return guides\r
+\r
+ def get_all_vertical_guides(self):\r
+ '''\r
+ Returns all vertical guides as a list of floats stored as\r
+ strings. Each value is the position from 0 in pixels.\r
+ '''\r
+ guides = []\r
+ for g in self.get_guides():\r
+ if g['orientation'] == 'vertical':\r
+ guides.append(g['position'])\r
+ return guides \r
+ \r
+ def get_horizontal_slice_positions(self):\r
+ '''\r
+ Make a sorted list of all horizontal guide positions, \r
+ including 0 and the document height, but not including\r
+ those outside of the canvas\r
+ '''\r
+ root = self.document.getroot()\r
+ horizontals = ['0']\r
+ height = inkex.unittouu(root.attrib['height'])\r
+ for h in self.get_all_horizontal_guides():\r
+ if h >= 0 and float(h) <= float(height):\r
+ horizontals.append(h)\r
+ horizontals.append(height)\r
+ horizontals.sort(cmp=float_sort) \r
+ return horizontals\r
+ \r
+ def get_vertical_slice_positions(self):\r
+ '''\r
+ Make a sorted list of all vertical guide positions,\r
+ including 0 and the document width, but not including\r
+ those outside of the canvas. \r
+ '''\r
+ root = self.document.getroot()\r
+ verticals = ['0']\r
+ width = inkex.unittouu(root.attrib['width'])\r
+ for v in self.get_all_vertical_guides():\r
+ if v >= 0 and float(v) <= float(width):\r
+ verticals.append(v)\r
+ verticals.append(width)\r
+ verticals.sort(cmp=float_sort)\r
+ return verticals\r
+ \r
+ def get_slices(self):\r
+ '''\r
+ Returns a list of all "slices" as denoted by the guides\r
+ on the page. Each slice is really just a 4 element list of \r
+ floats (stored as strings), consisting of the X and Y start \r
+ position and the X and Y end position.\r
+ '''\r
+ hs = self.get_horizontal_slice_positions()\r
+ vs = self.get_vertical_slice_positions()\r
+ slices = []\r
+ for i in range(len(hs)-1):\r
+ for j in range(len(vs)-1):\r
+ slices.append([vs[j], hs[i], vs[j+1], hs[i+1]])\r
+ return slices\r
+ \r
+ def get_filename_parts(self):\r
+ '''\r
+ Attempts to get directory and image as passed in by the inkscape \r
+ dialog. If the boolean ignore flag is set, then it will ignore\r
+ these settings and try to use the settings from the export\r
+ filename.\r
+ '''\r
+ \r
+ if self.options.ignore == False:\r
+ return (self.options.directory, self.options.image)\r
+ else:\r
+ '''\r
+ First get the export-filename from the document, if the \r
+ document has been exported before (TODO: Will not work if it\r
+ hasn't been exported yet), then uses this to return a tuple \r
+ consisting of the directory to export to, and the filename \r
+ without extension.\r
+ '''\r
+ svg = self.document.getroot()\r
+ att = '{http://www.inkscape.org/namespaces/inkscape}export-filename'\r
+ try:\r
+ export_file = svg.attrib[att]\r
+ except KeyError:\r
+ inkex.errormsg("To use the export hints option, you " +\r
+ "need to have previously exported the document. " + \r
+ "Otherwise no export hints exist!")\r
+ sys.exit(-1)\r
+ dirname, filename = os.path.split(export_file)\r
+ filename = filename.rsplit(".", 1)[0] # Without extension\r
+ return (dirname, filename) \r
+\r
+ def check_dir_exists(self, dir):\r
+ if not os.path.isdir(dir):\r
+ os.makedirs(dir)\r
+\r
+ def get_localised_string(self, str):\r
+ return locale.format("%.f", float(str), 0)\r
+\r
+ def export_slice(self, s, filename):\r
+ '''\r
+ Runs inkscape's command line interface and exports the image \r
+ slice from the 4 coordinates in s, and saves as the filename \r
+ given.\r
+ '''\r
+ svg_file = self.args[-1]\r
+ 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)\r
+ if bsubprocess:\r
+ p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)\r
+ return_code = p.wait()\r
+ f = p.stdout\r
+ err = p.stderr\r
+ else:\r
+ _, f, err = os.open3(command)\r
+ f.close()\r
+ \r
+ def export_slices(self, slices):\r
+ '''\r
+ Takes the slices list and passes each one with a calculated \r
+ filename/directory into export_slice.\r
+ '''\r
+ dirname, filename = self.get_filename_parts()\r
+ if dirname == '' or dirname == None:\r
+ dirname = './'\r
+ inkex.errormsg(dirname)\r
+ dirname = os.path.expanduser(dirname)\r
+ dirname = os.path.expandvars(dirname)\r
+ self.check_dir_exists(dirname)\r
+ i = 0\r
+ for s in slices:\r
+ f = dirname + os.path.sep + filename + str(i) + ".png"\r
+ self.export_slice(s, f)\r
+ i += 1\r
+ \r
+ def effect(self):\r
+ slices = self.get_slices()\r
+ self.export_slices(slices)\r
+ \r
+if __name__ == "__main__":\r
+ e = Guillotine()\r
+ e.affect()\r
+\r