├── README
├── layer2png.inx
└── layer2png.py
/README:
--------------------------------------------------------------------------------
1 | Inkscape Layer Slicer
2 | =====================
3 |
4 | It can be useful to "slice" images and export the slices. This
5 | extension facilitates that.
6 |
7 | Here's the process I've used for slicing web layout with
8 | Inkscape. Create your webpage layout (set page units to "px",
9 | width/height appropriately and snap to 1 pixel intervals. This should
10 | allow pixel perfect alignment). Then create a new layer, naming it
11 | slices. Draw rectangles over the areas you want to slice (set
12 | x,y,width,height to whole pixel values). Name these rectangles using
13 | the Object Properties found in the right click contextual menu (the
14 | saved images name will be based on that value, so name them something
15 | like "header" instead of the default/non-useful "rect4312").
16 |
17 | What the plugin then does is iterate over all of the rectangle
18 | definitions found in the slice layer and set the opacity of the slice
19 | rectangle to 0. (That allows you to make slightly transparent slices,
20 | which are easier to deal with than invisible ones) It then creates
21 | pngs for every slice. After completing the slicing, it then sets all
22 | the slice to a different color at 25% opacity.
23 |
24 | * red - overwrote a file
25 | * green - wrote a new file
26 | * grey - skipped (not overwriting)
27 |
28 | To continue working on your design without having to deal with the
29 | slices being selected, just "lock" the slice layer and your clicks
30 | should fall through. You can also click the "eye" on the slice layer
31 | to not view it.
32 |
33 | LICENSE
34 | =======
35 |
36 | GPL2
37 |
38 | Installation
39 | ============
40 |
41 | Put the .inx file and .py file in ~/.config/inkscape/extensions/ and restart
42 | inkscape.
43 |
44 | For global installation place in /usr/share/inkscape/extensions (on
45 | gentoo, your distro may vary)
46 |
47 | For MS place in \Inkscape\share\extensions\
48 |
49 | Status
50 | ======
51 |
52 | I've used this since 2007 for simple web graphics and doing
53 | presentation images. It was submitted to Inkscape for inclusion but
54 | rejected because it clobbers existing exported files.
55 |
56 | See https://bugs.launchpad.net/inkscape/+bug/169985
57 |
58 | Note that it now includes an option to overwrite or not existing
59 | files.
60 |
61 | NEWS
62 | ======
63 |
64 | * Oct 2019 - Attempting to get into Inkscape proper again. See https://gitlab.com/inkscape/extensions/merge_requests/139
65 |
--------------------------------------------------------------------------------
/layer2png.inx:
--------------------------------------------------------------------------------
1 |
2 |
3 | <_name>Export Layer Slices
4 | org.inkscape.output.layer2png
5 | org.inkscape.output.svg.inkscape
6 | layer2png.py
7 | inkex.py
8 |
12 |
13 |
14 |
15 | 300
16 | false
17 | 128, 64, 48, 32, 24, 16
18 | slices
19 | true
20 |
21 |
22 | <_param name="slicerhelp" type="description">This effect slices images, which can be useful for webdesign. In order to use it, create a new layer on top of the image. In this layer create rectaingles that define the slices.
23 | Note:
24 | * Slices may overlap.
25 | * It is also useful to set Document Properties units to "px" and use whole integer sizes for rectangles and snap to grid.
26 | * The slice ID ("Id" field of "Object Properties" right click contextual menu) of the rectangle is used to determine the filename (the suffix of .png is added).
27 | * When invoked any color settings on the layer rectangles is ignored and the images below them are exported to the directory choosen.
28 | * If overwrite is not checked, then if an existing file with that name exists, the export will not happen.
29 | * After export all the rectangles in the export layer are set to different color (red-overwrote a file, green-wrote a new file, grey-skipped (not overwritting)).
30 | * It is useful to hide and lock the export layer while doing work so it is not distracting.
31 |
32 |
33 |
34 |
35 |
37 |
38 | all
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
--------------------------------------------------------------------------------
/layer2png.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | layer2png.py
4 |
5 | Copyright (C) 2007-2010 Matt Harrison, matthewharrison [at] gmail.com
6 |
7 | This program is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program; if not, write to the Free Software
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 |
21 |
22 |
23 | A script that slices images. It might be useful for web design.
24 |
25 | You pass it the name of a layer containing rectangles that cover
26 | the areas that you want exported (the default name for this layer
27 | is "slices"). It then sets the opacity to 0 for all the rectangles
28 | defined in that layer and exports as png whatever they covered.
29 | The output filenames are based on the "Id" field of "Object Properties"
30 | right click contextual menu of the rectangles.
31 |
32 | One side effect is that after exporting, it sets the slice rectangles
33 | to different colors with a 25% opacity. (If you want to hide them,
34 | just click on the eye next to the layer).
35 |
36 | * red - overwrote a file
37 | * green - wrote a new file
38 | * grey - skipped (not overwriting)
39 |
40 | For good pixel exports set the Document Properties, default units to "px"
41 | and the width/height to the real size. (I use 1024x768)
42 |
43 | """
44 | import os
45 | import sys
46 | import logging
47 | import tempfile
48 |
49 | try:
50 | from subprocess import Popen, PIPE
51 | bsubprocess = True
52 | except:
53 | bsubprocess = False
54 |
55 | try:
56 | import xml.etree.ElementTree as et
57 | except ImportError as e:
58 | try:
59 | from lxml import etree as et
60 | except:
61 | sys.exit(_('The fantastic lxml wrapper for libxml2 is required by inkex.py and therefore this extension. Please download and install the latest version from http://cheeseshop.python.org/pypi/lxml/, or install it through your package manager by a command like: sudo apt-get install python-lxml'))
62 |
63 | sys.path.append('/usr/share/inkscape/extensions')
64 |
65 | import inkex
66 | import simplestyle
67 |
68 | logging.basicConfig(filename=os.path.join(tempfile.gettempdir(), 'inklog.log'), level=logging.DEBUG)
69 |
70 | class ExportSlices(inkex.Effect):
71 | """Exports all rectangles in the current layer"""
72 | def __init__(self):
73 | inkex.Effect.__init__(self)
74 | self.color_map = {} # change color based on overwrite
75 | # green - new export
76 | # red - overwrite
77 | # grey - not exported (no overwrite)
78 | self.OptionParser.add_option("--tab",
79 | action="store", type="string",
80 | dest="tab", default="sampling",
81 | help="The selected UI-tab when OK was pressed")
82 | self.OptionParser.add_option("-d", "--directory",
83 | action="store", type="string",
84 | dest="directory", default=os.path.expanduser("~"),
85 | help="Existing destination directory")
86 | self.OptionParser.add_option("-l", "--layer",
87 | action="store", type="string",
88 | dest="layer_name", default="slices",
89 | help="Layer with slices (rects) in it")
90 | self.OptionParser.add_option("-i", "--iconmode",
91 | action="store", type="inkbool", default=False,
92 | help="Icon export mode")
93 | self.OptionParser.add_option("-s", "--sizes",
94 | action="store", type="string",
95 | dest="sizes", default="128, 64, 48, 32, 24, 16",
96 | help="sizes to export comma separated")
97 | self.OptionParser.add_option("-o", "--overwrite",
98 | action="store", type="inkbool", default=False,
99 | help="Overwrite existing exports?")
100 | self.OptionParser.add_option("--dpi",
101 | action="store", type="string",
102 | dest="dpi", default="300",
103 | help="Dots per inch (300 default)")
104 |
105 |
106 | def effect(self):
107 | """
108 | In addition to the command line parameters a (temp) file
109 | containing the contents of the svg is passed on the command
110 | line (self.args[-1])
111 | """
112 | if not os.path.isdir(self.options.directory):
113 | os.makedirs(self.options.directory)
114 |
115 | if not self.layer_exists(self.options.layer_name):
116 | sys.stderr.write("Export layer: '%s' does not exist. Please see 'Help' tab for instructions" % self.options.layer_name)
117 | logging.log(logging.DEBUG, "No slice layer: %s" % self.options.layer_name)
118 | return
119 |
120 | logging.log(logging.DEBUG, "COMMAND LINE %s" % sys.argv)
121 | # set opacity to zero in slices
122 | slices_found = False
123 | for node in self.get_layer_nodes(self.document, self.options.layer_name):
124 | slices_found = True
125 | self.clear_color(node)
126 |
127 | if not slices_found:
128 | sys.stderr.write("No rectangles defined in '%s' to slice. Please see 'Help' tab for instructions" % self.options.layer_name)
129 | logging.log(logging.DEBUG, "No rectangles defined in '%s' to slice" % self.options.layer_name)
130 | return
131 |
132 | # save new xml
133 | fout = open(self.args[-1], 'w')
134 | self.document.write(fout)
135 | fout.close()
136 |
137 | # in case there are overlapping rects, clear them all out before
138 | # saving any
139 | for node in self.get_layer_nodes(self.document, self.options.layer_name):
140 | if self.options.iconmode:
141 | for s in self.options.sizes.split(', '):
142 | if s.isdigit():
143 | pngSize = int(s)
144 | self.export_resized(node, pngSize, pngSize)
145 | else:
146 | self.export_original_size(node)
147 |
148 | #change slice colors to grey/green/red and set opacity to 25% in real document
149 | for node in self.get_layer_nodes(self.document, self.options.layer_name):
150 | self.change_color(node)
151 |
152 | def layer_exists(self, layer_name):
153 | layer_nodes = self.get_layer_nodes(self.document, layer_name)
154 | return layer_nodes != None
155 |
156 | def get_layer_nodes(self, document, layer_name):
157 | """
158 | given an xml document (etree), and the name of a layer one
159 | that contains the rectangles defining slices, return the nodes
160 | of the rectangles.
161 | """
162 | #get layer we intend to slice
163 | slice_node = None
164 | slice_layer = document.findall('{http://www.w3.org/2000/svg}g')
165 | for node in slice_layer:
166 | label_value = node.attrib.get('{http://www.inkscape.org/namespaces/inkscape}label', None)
167 | if label_value == layer_name:
168 | slice_node = node
169 |
170 | if slice_node is not None:
171 | return slice_node.findall('{http://www.w3.org/2000/svg}rect')
172 | return slice_node
173 |
174 | def clear_color(self, node):
175 | '''
176 | set opacity to zero, and stroke to none
177 |
178 | Node looks like this:
179 |