2008-07-29 00:45:20 +02:00
|
|
|
#!/usr/bin/python
|
2008-11-07 19:13:58 +01:00
|
|
|
#
|
2012-01-10 04:02:29 +01:00
|
|
|
# IconSvgRenderer.py - Icon rendering utility script
|
2008-07-29 00:45:20 +02:00
|
|
|
#
|
|
|
|
|
# Copyright (C) Lumiera.org
|
|
|
|
|
# 2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
|
|
|
#
|
|
|
|
|
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
2012-01-10 04:02:29 +01:00
|
|
|
import os
|
2008-08-04 13:06:24 +02:00
|
|
|
import sys
|
|
|
|
|
import getopt
|
2008-07-29 00:45:20 +02:00
|
|
|
import shutil
|
2012-01-10 04:02:29 +01:00
|
|
|
from xml.dom import minidom
|
|
|
|
|
|
2008-07-29 00:45:20 +02:00
|
|
|
|
2008-08-12 23:13:26 +02:00
|
|
|
rsvgPath = "./rsvg-convert"
|
2008-07-29 00:45:20 +02:00
|
|
|
artworkLayerPrefix = "artwork:"
|
|
|
|
|
|
2011-02-07 11:36:06 +01:00
|
|
|
#
|
|
|
|
|
# 2/2011 some notes by Ichthyo
|
|
|
|
|
# The purpose of this python script is
|
|
|
|
|
# - to parse a SVG
|
|
|
|
|
# - to invoke Inkscape to render this SVG into a raster image (icon)
|
|
|
|
|
#
|
2012-01-10 05:15:45 +01:00
|
|
|
# For the actual Cairo based SVG rendering we rely on an executable 'rsvg-convert',
|
2011-02-07 11:36:06 +01:00
|
|
|
# which is built during the Lumiera build process.
|
|
|
|
|
#
|
|
|
|
|
# Judging from the code and the actual SVGs, this seems to work as follows:
|
|
|
|
|
# The SVG contains a design to be rendered into raster images of various sizes.
|
|
|
|
|
# These sizes are determined by special rectangles, which act as bounding box and
|
|
|
|
|
# are placed on a special 'plate' layer, which is a child layer of the main
|
|
|
|
|
# 'artwork:' layer. The grid of the SVG is setup such as to result in pixel sizes
|
|
|
|
|
# suitable for icon generation. The actual size of the generated icons are then
|
|
|
|
|
# parsed from the height and width attributes of the mentioned bounding box
|
|
|
|
|
# rectangles.
|
|
|
|
|
#
|
|
|
|
|
# The parser seems to be rather simplistic; the sizes and positions need to be
|
|
|
|
|
# integral numbers. In one instance we had a float number in the y coordinate,
|
|
|
|
|
# which resulted in an invalid, zero sized output icon
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
2008-07-29 00:45:20 +02:00
|
|
|
def createDirectory( name ):
|
2008-12-22 05:00:02 +01:00
|
|
|
try:
|
|
|
|
|
if os.path.isfile(name):
|
|
|
|
|
os.remove(name)
|
|
|
|
|
if not os.path.exists(name):
|
|
|
|
|
os.mkdir(name)
|
|
|
|
|
except:
|
|
|
|
|
print 'WARNING: createDirectory("%s") failed. Permission problems?' % name
|
|
|
|
|
|
2008-11-07 19:13:58 +01:00
|
|
|
|
2008-07-29 00:45:20 +02:00
|
|
|
def copyMergeDirectory( src, dst ):
|
|
|
|
|
listing = os.listdir(src)
|
|
|
|
|
for file_name in listing:
|
2008-12-16 22:29:35 +01:00
|
|
|
src_file_path = os.path.join(src, file_name)
|
|
|
|
|
dst_file_path = os.path.join(dst, file_name)
|
2008-07-29 00:45:20 +02:00
|
|
|
shutil.copyfile(src_file_path, dst_file_path)
|
|
|
|
|
|
|
|
|
|
def getDocumentSize( svg_element ):
|
|
|
|
|
width = float(svg_element.getAttribute("width"))
|
|
|
|
|
height = float(svg_element.getAttribute("height"))
|
|
|
|
|
return [width, height]
|
|
|
|
|
|
|
|
|
|
def findChildLayerElement( parent_element ):
|
|
|
|
|
for node in parent_element.childNodes:
|
|
|
|
|
if node.nodeType == minidom.Node.ELEMENT_NODE:
|
|
|
|
|
if node.tagName == "g":
|
|
|
|
|
if node.getAttribute("inkscape:groupmode") == "layer":
|
|
|
|
|
return node
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def parsePlateLayer( layer ):
|
|
|
|
|
rectangles = []
|
|
|
|
|
for node in layer.childNodes:
|
|
|
|
|
if node.nodeType == minidom.Node.ELEMENT_NODE:
|
|
|
|
|
if node.tagName == "rect":
|
|
|
|
|
x = float(node.getAttribute("x"))
|
|
|
|
|
y = float(node.getAttribute("y"))
|
|
|
|
|
width = float(node.getAttribute("width"))
|
|
|
|
|
height = float(node.getAttribute("height"))
|
|
|
|
|
rectangles.append([x, y, width, height])
|
|
|
|
|
return rectangles
|
|
|
|
|
|
|
|
|
|
def parseSVG( file_path ):
|
2008-08-19 05:03:29 +02:00
|
|
|
print "Parsing " + file_path
|
2008-07-29 00:45:20 +02:00
|
|
|
svgdoc = minidom.parse(file_path)
|
|
|
|
|
for root_node in svgdoc.childNodes:
|
|
|
|
|
if root_node.nodeType == minidom.Node.ELEMENT_NODE:
|
|
|
|
|
if root_node.tagName == "svg":
|
|
|
|
|
size = getDocumentSize( root_node )
|
|
|
|
|
layer = findChildLayerElement( root_node )
|
|
|
|
|
if layer != None:
|
|
|
|
|
layer_name = layer.getAttribute("inkscape:label")
|
|
|
|
|
if layer_name[:len(artworkLayerPrefix)] == artworkLayerPrefix:
|
|
|
|
|
artwork_name = layer_name[len(artworkLayerPrefix):]
|
|
|
|
|
plate = findChildLayerElement( layer )
|
|
|
|
|
if plate != None:
|
|
|
|
|
return artwork_name, size, parsePlateLayer( plate )
|
|
|
|
|
return None
|
|
|
|
|
|
2008-08-04 13:06:24 +02:00
|
|
|
def renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size):
|
|
|
|
|
# Prepare a Cairo context
|
|
|
|
|
width = int(rectangle[2])
|
|
|
|
|
height = int(rectangle[3])
|
2008-08-19 05:03:29 +02:00
|
|
|
|
|
|
|
|
if not os.path.exists(rsvgPath):
|
|
|
|
|
print "Error: executable %s not found." % rsvgPath
|
2008-08-12 23:13:26 +02:00
|
|
|
|
|
|
|
|
os.spawnlp(os.P_WAIT, rsvgPath, rsvgPath,
|
|
|
|
|
"--source-rect=%g:%g:%g:%g" % (rectangle[0], rectangle[1], rectangle[2], rectangle[3]),
|
|
|
|
|
"--output=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name)),
|
|
|
|
|
file_path)
|
2008-08-04 13:06:24 +02:00
|
|
|
|
|
|
|
|
def renderSvgIcon(file_path, out_dir):
|
|
|
|
|
artwork_name, doc_size, rectangles = parseSVG(file_path)
|
|
|
|
|
for rectangle in rectangles:
|
|
|
|
|
renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size)
|
|
|
|
|
|
2008-08-19 05:03:29 +02:00
|
|
|
def getTargetNames(file_path):
|
|
|
|
|
"""get a list of target names to be rendered from the given source SVG
|
|
|
|
|
usable to setup the build targets for SCons
|
|
|
|
|
"""
|
|
|
|
|
artwork_name, _ , rectangles = parseSVG(file_path)
|
|
|
|
|
return ["%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name) for rectangle in rectangles ]
|
|
|
|
|
|
2008-08-04 13:06:24 +02:00
|
|
|
|
|
|
|
|
def printHelp():
|
2008-08-19 05:03:29 +02:00
|
|
|
print "render-icon.py SRCFILE.svg TARGETDIR"
|
|
|
|
|
print "An icon rendering utility script for lumiera"
|
2008-08-04 13:06:24 +02:00
|
|
|
|
|
|
|
|
def parseArguments(argv):
|
|
|
|
|
optlist, args = getopt.getopt(argv, "")
|
|
|
|
|
|
|
|
|
|
if len(args) == 2:
|
|
|
|
|
return args[0], args[1]
|
|
|
|
|
|
|
|
|
|
printHelp()
|
|
|
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
def main(argv):
|
|
|
|
|
in_path, out_dir = parseArguments(argv)
|
2008-07-29 00:45:20 +02:00
|
|
|
|
2008-11-07 19:13:58 +01:00
|
|
|
if not (in_path and out_dir):
|
|
|
|
|
print "Missing arguments in_path and out_dir."
|
|
|
|
|
sys.exit(1)
|
2008-07-29 00:45:20 +02:00
|
|
|
|
2008-12-16 22:29:35 +01:00
|
|
|
if os.path.isfile(out_dir):
|
2008-11-07 19:13:58 +01:00
|
|
|
print "Unable to use '%s' as output directory, because it\'s a file." % out_dir
|
|
|
|
|
sys.exit(1)
|
2008-12-16 22:29:35 +01:00
|
|
|
if not os.path.isdir(out_dir):
|
2008-11-07 19:13:58 +01:00
|
|
|
print "Output directory '%s' not found." % out_dir
|
|
|
|
|
sys.exit(1)
|
2008-08-04 13:06:24 +02:00
|
|
|
|
|
|
|
|
# Create the icons folders
|
2008-12-16 22:29:35 +01:00
|
|
|
createDirectory(os.path.join(out_dir, "48x48"))
|
|
|
|
|
createDirectory(os.path.join(out_dir, "32x32"))
|
|
|
|
|
createDirectory(os.path.join(out_dir, "24x24"))
|
|
|
|
|
createDirectory(os.path.join(out_dir, "22x22"))
|
|
|
|
|
createDirectory(os.path.join(out_dir, "16x16"))
|
2008-08-04 13:06:24 +02:00
|
|
|
|
|
|
|
|
renderSvgIcon(in_path, out_dir)
|
|
|
|
|
|
2008-07-29 00:45:20 +02:00
|
|
|
# Copy in prerendered icons
|
2008-08-04 13:06:24 +02:00
|
|
|
#copyPrerenderedIcons()
|
2008-07-29 00:45:20 +02:00
|
|
|
|
|
|
|
|
if __name__=="__main__":
|
2008-08-04 13:06:24 +02:00
|
|
|
main(sys.argv[1:])
|
2008-07-29 00:45:20 +02:00
|
|
|
|