inkex.py revision 1d7baac718ad43ee1a8621a7c871024879e6f8e0
fa9e4066f08beec538e775443c5be79dd423fcabahrens# -*- coding: utf-8 -*-
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrockA helper module for creating Inkscape extensions
fa9e4066f08beec538e775443c5be79dd423fcabahrensCopyright (C) 2005,2010 Aaron Spike <aaron@ekips.org> and contributors
fa9e4066f08beec538e775443c5be79dd423fcabahrensContributors:
fa9e4066f08beec538e775443c5be79dd423fcabahrens Aurélio A. Heckert <aurium(a)gmail.com>
fa9e4066f08beec538e775443c5be79dd423fcabahrens Bulia Byak <buliabyak@users.sf.net>
fa9e4066f08beec538e775443c5be79dd423fcabahrens Nicolas Dufour, nicoduf@yahoo.fr
fa9e4066f08beec538e775443c5be79dd423fcabahrens Peter J. R. Moulder <pjrm@users.sourceforge.net>
fa9e4066f08beec538e775443c5be79dd423fcabahrensThis program is free software; you can redistribute it and/or modify
fa9e4066f08beec538e775443c5be79dd423fcabahrensit under the terms of the GNU General Public License as published by
fa9e4066f08beec538e775443c5be79dd423fcabahrensthe Free Software Foundation; either version 2 of the License, or
fa9e4066f08beec538e775443c5be79dd423fcabahrens(at your option) any later version.
fa9e4066f08beec538e775443c5be79dd423fcabahrensThis program is distributed in the hope that it will be useful,
fa9e4066f08beec538e775443c5be79dd423fcabahrensbut WITHOUT ANY WARRANTY; without even the implied warranty of
e6032be1b8a5a1d03081e0d62b624db95c4cf8b7marksMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fa9e4066f08beec538e775443c5be79dd423fcabahrensGNU General Public License for more details.
fa9e4066f08beec538e775443c5be79dd423fcabahrensYou should have received a copy of the GNU General Public License
fa9e4066f08beec538e775443c5be79dd423fcabahrensalong with this program; if not, write to the Free Software
fa9e4066f08beec538e775443c5be79dd423fcabahrensFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwfrom math import *
fa9e4066f08beec538e775443c5be79dd423fcabahrens#a dictionary of all of the xmlns prefixes in a standard inkscape doc
fa9e4066f08beec538e775443c5be79dd423fcabahrensu'sodipodi' :u'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
fa9e4066f08beec538e775443c5be79dd423fcabahrensu'rdf' :u'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
fa9e4066f08beec538e775443c5be79dd423fcabahrensu'inkscape' :u'http://www.inkscape.org/namespaces/inkscape',
fa9e4066f08beec538e775443c5be79dd423fcabahrens trans = gettext.translation(domain, localdir, [current_locale], fallback=True)
fa9e4066f08beec538e775443c5be79dd423fcabahrens trans = gettext.translation(domain, localdir, fallback=True)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw trans = gettext.translation(domain, localdir, fallback=True)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw trans = gettext.translation(domain, localdir, fallback=True)
fa9e4066f08beec538e775443c5be79dd423fcabahrens #sys.stderr.write(str(localdir) + "\n")
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """Intended for end-user-visible error messages.
169cdae232f15e542d6af0a9ce30c3f84222bc0fmarks (Currently just writes to stderr with an appended newline, but could do
fa9e4066f08beec538e775443c5be79dd423fcabahrens something better in future: e.g. could add markup to distinguish error
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw messages from status messages or debugging output.)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw Note that this should always be combined with translation:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw import inkex
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw inkex.localize()
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw inkex.errormsg(_("This extension requires two selected paths."))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sys.stderr.write((unicode(msg, "utf-8", errors='replace') + "\n").encode("UTF-8"))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw# third party library
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw errormsg(_("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\n\nTechnical details:\n%s" % (e,)))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw raise optparse.OptionValueError("option %s: invalid inkbool value: %s" % (opt, value))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ns!=None and len(ns)>0 and NSS.has_key(ns) and len(tag)>0 and tag[0]!='{':
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """A class for creating Inkscape SVG Effects"""
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw self.OptionParser = optparse.OptionParser(usage="usage: %prog [options] SVGfile",option_class=InkOption)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """Collect command line arguments"""
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw self.options, self.args = self.OptionParser.parse_args(args)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """Parse document in specified file or on stdin"""
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # First try to open the file from the function argument
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if filename != None:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw errormsg(_("Unable to open specified file: %s") % filename)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # If it wasn't specified, try to open the file specified as
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # an object member
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw errormsg(_("Unable to open object member file: %s") % self.svg_file)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # Finally, if the filename was not specified anywhere, use
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # standard input stream
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # defines view_center in terms of document units
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw layerattr = self.document.xpath('//sodipodi:namedview/@inkscape:current-layer', namespaces=NSS)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw layer = self.document.xpath('//svg:g[@id="%s"]' % layername, namespaces=NSS)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw xattr = self.document.xpath('//sodipodi:namedview/@inkscape:cx', namespaces=NSS)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw yattr = self.document.xpath('//sodipodi:namedview/@inkscape:cy', namespaces=NSS)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if x and y and doc_height is not None:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw self.view_center = (float(x), doc_height - float(y)) # FIXME: y-coordinate flip, eliminate it when it's gone in Inkscape
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """Collect selected nodes"""
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return None
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw docIdNodes = self.document.xpath('//@id', namespaces=NSS)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return self.document.xpath('//sodipodi:namedview', namespaces=NSS)[0]
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 'orientation': str(sin(radians(angle)))+','+str(-cos(radians(angle)))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """Serialize document into XML on stdout"""
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw """Affect an SVG document with a callback effect"""
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw new_id += random.choice('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw errormsg(_("No matching node for expression: %s") % path)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw #a dictionary of unit to user unit conversion factors
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw __uuconv = {'in':96.0, 'pt':1.33333333333, 'px':1.0, 'mm':3.77952755913, 'cm':37.7952755913,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 'm':3779.52755913, 'km':3779527.55913, 'pc':16.0, 'yd':3456.0 , 'ft':1152.0}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # Fault tolerance for lazily defined SVG
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return '0'
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # Fault tolerance for lazily defined SVG
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return '0'
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # Function returns the unit used for the values in SVG.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # For lack of an attribute in SVG that explicitly defines what units are used for SVG coordinates,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # try to calculate the unit from the SVG width and SVG viewbox.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw # Defaults to 'px' units.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw unitmatch = re.compile('(%s)$' % '|'.join(self.__uuconv.keys()))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
fa9e4066f08beec538e775443c5be79dd423fcabahrens errormsg(_("SVG Width not set correctly! Assuming width = 100"))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if len(viewboxnumbers) == 4: #check for correct number of numbers
fa9e4066f08beec538e775443c5be79dd423fcabahrens svgunitfactor = self.__uuconv[svgwidthunit] * width / viewboxwidth
fa9e4066f08beec538e775443c5be79dd423fcabahrens # try to find the svgunitfactor in the list of units known. If we don't find something, ...
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if are_near_relative(self.__uuconv[key], svgunitfactor, eps):
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw #found match!
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw '''Returns userunits given a string representation of units in another system'''
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw unit = re.compile('(%s)$' % '|'.join(self.__uuconv.keys()))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if string is not None:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return retval * (self.__uuconv[u.string[u.start():u.end()]] / self.__uuconv[self.getDocumentUnit()])
fa9e4066f08beec538e775443c5be79dd423fcabahrens else: # default assume 'px' unit
2459a9eaca6b6525c76289d22ffe4c96be1956d6marks return val / (self.__uuconv[unit] / self.__uuconv[self.getDocumentUnit()])
2459a9eaca6b6525c76289d22ffe4c96be1956d6marks ''' Add document unit when no unit is specified in the string '''
fa9e4066f08beec538e775443c5be79dd423fcabahrens# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99