#!/usr/bin/env python # coding=utf-8 # # Copyright (C) 2007-2019 Matt Harrison, matthewharrison [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 # """ A script that slices images. It might be useful for web design. You pass it the name of a layer containing rectangles that cover the areas that you want exported (the default name for this layer is "slices"). It then sets the opacity to 0 for all the rectangles defined in that layer and exports as png whatever they covered. The output filenames are based on the "Id" field of "Object Properties" right click contextual menu of the rectangles. One side effect is that after exporting, it sets the slice rectangles to different colors with a 25% opacity. (If you want to hide them, just click on the eye next to the layer). * red - overwrote a file * green - wrote a new file * grey - skipped (not overwriting) For good pixel exports set the Document Properties, default units to "px" and the width/height to the real size. (I use 1024x768) Here's the process I've used for slicing web layout with Inkscape: Create your webpage layout (set page units to "px", width/height appropriately and snap to 1 pixel intervals. This should allow pixel perfect alignment). Then create a new layer, naming it slices. Draw rectangles over the areas you want to slice (set x,y,width,height to whole pixel values). Name these rectangles using the Object Properties found in the right click contextual menu (the saved images name will be based on that value, so name them something like "header" instead of the default/non-useful "rect4312"). """ import os import tempfile import inkex from inkex.command import inkscape from inkex.localization import inkex_gettext as _ class ExportSlices(inkex.EffectExtension): """Exports all rectangles in the current layer""" GREEN = "#00ff00" # new export GREY = "#555555" # not exported RED = "#ff0000" # overwrite def __init__(self): super(ExportSlices, self).__init__() self.color_map = {} # map node id to color based on overwrite def add_arguments(self, pars): pars.add_argument("--tab") pars.add_argument( "--directory", default=os.path.expanduser("~"), help="Existing destination directory", ) pars.add_argument( "--layer", default="slices", help="Layer with slices (rects) in it" ) pars.add_argument("--iconmode", type=inkex.Boolean, help="Icon export mode") pars.add_argument( "--sizes", default="128, 64, 48, 32, 24, 16", help="sizes to export comma separated", ) pars.add_argument( "--overwrite", type=inkex.Boolean, help="Overwrite existing exports?" ) pars.add_argument("--dpi", default="300", help="Dots per inch (300 default)") def effect(self): if not os.path.isdir(self.options.directory): os.makedirs(self.options.directory) nodes = self.get_layer_nodes(self.options.layer) if nodes is None: raise inkex.AbortExtension( _("Slice: '{}' does not exist.").format(self.options.layer) ) # set opacity to zero in slices for node in nodes: self.clear_color(node) # save file once now # if we have multiple slices we will make multiple calls # to inkscape (__, tmp_svg) = tempfile.mkstemp(".svg") with open(tmp_svg, "wb") as fout: fout.write(self.svg.tostring()) # in case there are overlapping rects, clear them all out before # saving any for node in nodes: if self.options.iconmode: for size in self.options.sizes.split(","): size = size.strip() if size.isdigit(): png_size = int(size) self.export_node(node, png_size, png_size) else: self.export_node(node) # change slice colors to grey/green/red and set opacity to 25% in real document for node in nodes: self.change_color(node) return self.document def get_layer_nodes(self, layer_name): """ given the name of a layer one that contains the rectangles defining slices, return the nodes of the rectangles. """ # get layer we intend to slice slice_node = None slice_layer = self.svg.findall("svg:g") for node in slice_layer: label_value = node.label if label_value == layer_name: slice_node = node if slice_node is not None: return slice_node.findall("svg:rect") return slice_node def clear_color(self, node): """ set opacity to zero, and stroke to none Node looks like this: