179 lines
6.1 KiB
Python
179 lines
6.1 KiB
Python
#!/usr/bin/python
|
||
# coding: utf-8
|
||
#
|
||
# IconSvgRenderer.py - Icon rendering utility script
|
||
#
|
||
# Copyright (C)
|
||
# 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. See the file COPYING for further details.
|
||
#####################################################################
|
||
|
||
import os
|
||
import sys
|
||
import getopt
|
||
import shutil
|
||
from xml.dom import minidom
|
||
|
||
|
||
rsvgPath = "./rsvg-convert"
|
||
artworkLayerPrefix = "artwork:"
|
||
|
||
#
|
||
# 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)
|
||
#
|
||
# For the actual Cairo based SVG rendering we rely on an executable 'rsvg-convert',
|
||
# 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
|
||
#
|
||
#
|
||
|
||
|
||
def createDirectory (name):
|
||
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)
|
||
|
||
|
||
def copyMergeDirectory (src, dst):
|
||
listing = os.listdir (src)
|
||
for file_name in listing:
|
||
src_file_path = os.path.join (src, file_name)
|
||
dst_file_path = os.path.join (dst, file_name)
|
||
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):
|
||
print("Parsing " + file_path)
|
||
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
|
||
|
||
|
||
def renderSvgRsvg (file_path, out_dir, artwork_name, rectangle, _doc_size):
|
||
# Prepare a Cairo context
|
||
width = int(rectangle[2])
|
||
height = int(rectangle[3])
|
||
|
||
if not os.path.exists(rsvgPath):
|
||
print("Error: executable %s not found." % rsvgPath)
|
||
|
||
os.spawnlp(os.P_WAIT, rsvgPath, rsvgPath,
|
||
"--source-rect=%g:%g:%g:%g" % (rectangle[0], rectangle[1], width, height),
|
||
"--output=" + os.path.join(out_dir, "%gx%g/%s.png" % (width, height, artwork_name)),
|
||
file_path)
|
||
|
||
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)
|
||
|
||
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 ]
|
||
|
||
|
||
def printHelp():
|
||
print("render-icon.py SRCFILE.svg TARGETDIR")
|
||
print("An icon rendering utility script for lumiera")
|
||
|
||
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)
|
||
|
||
if not (in_path and out_dir):
|
||
print("Missing arguments in_path and out_dir.")
|
||
sys.exit(1)
|
||
|
||
if os.path.isfile(out_dir):
|
||
print("Unable to use '%s' as output directory, because it\'s a file." % out_dir)
|
||
sys.exit(1)
|
||
if not os.path.isdir(out_dir):
|
||
print("Output directory '%s' not found." % out_dir)
|
||
sys.exit(1)
|
||
|
||
# Create the icons folders
|
||
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"))
|
||
|
||
renderSvgIcon (in_path, out_dir)
|
||
|
||
|
||
|
||
|
||
if __name__=="__main__":
|
||
main(sys.argv[1:])
|
||
|