diff options
Diffstat (limited to 'support/dxf_export/inkex.py')
-rwxr-xr-x | support/dxf_export/inkex.py | 211 |
1 files changed, 170 insertions, 41 deletions
diff --git a/support/dxf_export/inkex.py b/support/dxf_export/inkex.py index e487822..19e860b 100755 --- a/support/dxf_export/inkex.py +++ b/support/dxf_export/inkex.py @@ -1,9 +1,16 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- """ inkex.py A helper module for creating Inkscape extensions -Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org +Copyright (C) 2005,2010 Aaron Spike <aaron@ekips.org> and contributors + +Contributors: + Aurélio A. Heckert <aurium(a)gmail.com> + Bulia Byak <buliabyak@users.sf.net> + Nicolas Dufour, nicoduf@yahoo.fr + Peter J. R. Moulder <pjrm@users.sourceforge.net> 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 @@ -19,10 +26,14 @@ 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 """ -import sys, copy, optparse, random, re +import copy import gettext +import optparse +import os +import random +import re +import sys from math import * -_ = gettext.gettext #a dictionary of all of the xmlns prefixes in a standard inkscape doc NSS = { @@ -37,34 +48,35 @@ u'xlink' :u'http://www.w3.org/1999/xlink', u'xml' :u'http://www.w3.org/XML/1998/namespace' } -#a dictionary of unit to user unit conversion factors -uuconv = {'in':90.0, 'pt':1.25, 'px':1, 'mm':3.5433070866, 'cm':35.433070866, 'm':3543.3070866, - 'km':3543307.0866, 'pc':15.0, 'yd':3240 , 'ft':1080} -def unittouu(string): - '''Returns userunits given a string representation of units in another system''' - unit = re.compile('(%s)$' % '|'.join(uuconv.keys())) - param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') - - p = param.match(string) - u = unit.search(string) - if p: - retval = float(p.string[p.start():p.end()]) +def localize(): + domain = 'inkscape' + if sys.platform.startswith('win'): + import locale + current_locale, encoding = locale.getdefaultlocale() + os.environ['LANG'] = current_locale + try: + localdir = os.environ['INKSCAPE_LOCALEDIR']; + trans = gettext.translation(domain, localdir, [current_locale], fallback=True) + except KeyError: + trans = gettext.translation(domain, fallback=True) + elif sys.platform.startswith('darwin'): + try: + localdir = os.environ['INKSCAPE_LOCALEDIR']; + trans = gettext.translation(domain, localdir, fallback=True) + except KeyError: + try: + localdir = os.environ['PACKAGE_LOCALE_DIR']; + trans = gettext.translation(domain, localdir, fallback=True) + except KeyError: + trans = gettext.translation(domain, fallback=True) else: - retval = 0.0 - if u: try: - return retval * uuconv[u.string[u.start():u.end()]] + localdir = os.environ['PACKAGE_LOCALE_DIR']; + trans = gettext.translation(domain, localdir, fallback=True) except KeyError: - pass - return retval - -def uutounit(val, unit): - return val/uuconv[unit] - -try: - from lxml import etree -except: - 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')) + trans = gettext.translation(domain, fallback=True) + #sys.stderr.write(str(localdir) + "\n") + trans.install() def debug(what): sys.stderr.write(str(what) + "\n") @@ -79,13 +91,31 @@ def errormsg(msg): Note that this should always be combined with translation: - import gettext - _ = gettext.gettext + import inkex + inkex.localize() ... inkex.errormsg(_("This extension requires two selected paths.")) """ - sys.stderr.write((unicode(msg) + "\n").encode("UTF-8")) + if isinstance(msg, unicode): + sys.stderr.write(msg.encode("UTF-8") + "\n") + else: + sys.stderr.write((unicode(msg, "utf-8", errors='replace') + "\n").encode("UTF-8")) + +def are_near_relative(a, b, eps): + if (a-b <= a*eps) and (a-b >= -a*eps): + return True + else: + return False + +# third party library +try: + from lxml import etree +except Exception, e: + localize() + 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,))) + sys.exit() + def check_inkbool(option, opt, value): if str(value).capitalize() == 'True': return True @@ -128,20 +158,37 @@ class Effect: """Collect command line arguments""" self.options, self.args = self.OptionParser.parse_args(args) - def parse(self,file=None): + def parse(self, filename=None): """Parse document in specified file or on stdin""" - try: + + # First try to open the file from the function argument + if filename != None: try: - stream = open(file,'r') - except: - stream = open(self.svg_file,'r') - except: + stream = open(filename, 'r') + except Exception: + errormsg(_("Unable to open specified file: %s") % filename) + sys.exit() + + # If it wasn't specified, try to open the file specified as + # an object member + elif self.svg_file != None: + try: + stream = open(self.svg_file, 'r') + except Exception: + errormsg(_("Unable to open object member file: %s") % self.svg_file) + sys.exit() + + # Finally, if the filename was not specified anywhere, use + # standard input stream + else: stream = sys.stdin + p = etree.XMLParser(huge_tree=True) self.document = etree.parse(stream, parser=p) self.original_document = copy.deepcopy(self.document) stream.close() + # defines view_center in terms of document units def getposinlayer(self): #defaults self.current_layer = self.document.getroot() @@ -156,10 +203,10 @@ class Effect: xattr = self.document.xpath('//sodipodi:namedview/@inkscape:cx', namespaces=NSS) yattr = self.document.xpath('//sodipodi:namedview/@inkscape:cy', namespaces=NSS) - doc_height = unittouu(self.document.getroot().get('height')) if xattr and yattr: - x = xattr[0] - y = yattr[0] + x = self.unittouu( xattr[0] + 'px' ) + y = self.unittouu( yattr[0] + 'px') + doc_height = self.unittouu(self.document.getroot().get('height')) if x and y: self.view_center = (float(x), doc_height - float(y)) # FIXME: y-coordinate flip, eliminate it when it's gone in Inkscape @@ -236,6 +283,88 @@ class Effect: errormsg(_("No matching node for expression: %s") % path) retval = None return retval + + #a dictionary of unit to user unit conversion factors + __uuconv = {'in':96.0, 'pt':1.33333333333, 'px':1.0, 'mm':3.77952755913, 'cm':37.7952755913, + 'm':3779.52755913, 'km':3779527.55913, 'pc':16.0, 'yd':3456.0 , 'ft':1152.0} + + # Function returns the unit used for the values in SVG. + # For lack of an attribute in SVG that explicitly defines what units are used for SVG coordinates, + # try to calculate the unit from the SVG width and SVG viewbox. + # Defaults to 'px' units. + def getDocumentUnit(self): + svgunit = 'px' #default to pixels + + svgwidth = self.document.getroot().get('width') + viewboxstr = self.document.getroot().get('viewBox') + if viewboxstr: + unitmatch = re.compile('(%s)$' % '|'.join(self.__uuconv.keys())) + param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') + + p = param.match(svgwidth) + u = unitmatch.search(svgwidth) + width = 100 #default + viewboxwidth = 100 #default + svgwidthunit = 'px' #default assume 'px' unit + if p: + width = float(p.string[p.start():p.end()]) + else: + errormsg(_("SVG Width not set correctly! Assuming width = 100")) + if u: + svgwidthunit = u.string[u.start():u.end()] + + viewboxnumbers = [] + for t in viewboxstr.split(): + try: + viewboxnumbers.append(float(t)) + except ValueError: + pass + if len(viewboxnumbers) == 4: #check for correct number of numbers + viewboxwidth = viewboxnumbers[2] + + svgunitfactor = self.__uuconv[svgwidthunit] * width / viewboxwidth + + # try to find the svgunitfactor in the list of units known. If we don't find something, ... + eps = 0.01 #allow 1% error in factor + for key in self.__uuconv: + if are_near_relative(self.__uuconv[key], svgunitfactor, eps): + #found match! + svgunit = key; + + return svgunit + + + def unittouu(self, string): + '''Returns userunits given a string representation of units in another system''' + unit = re.compile('(%s)$' % '|'.join(self.__uuconv.keys())) + param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') + + p = param.match(string) + u = unit.search(string) + if p: + retval = float(p.string[p.start():p.end()]) + else: + retval = 0.0 + if u: + try: + return retval * (self.__uuconv[u.string[u.start():u.end()]] / self.__uuconv[self.getDocumentUnit()]) + except KeyError: + pass + else: # default assume 'px' unit + return retval / self.__uuconv[self.getDocumentUnit()] + + return retval + + def uutounit(self, val, unit): + return val / (self.__uuconv[unit] / self.__uuconv[self.getDocumentUnit()]) + + def addDocumentUnit(self, value): + ''' Add document unit when no unit is specified in the string ''' + try: + float(value) + return value + self.getDocumentUnit() + except ValueError: + return value -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 |