~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/share/extensions/inkex.py

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
"""
 
3
inkex.py
 
4
A helper module for creating Inkscape extensions
 
5
 
 
6
Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org
 
7
 
 
8
This program is free software; you can redistribute it and/or modify
 
9
it under the terms of the GNU General Public License as published by
 
10
the Free Software Foundation; either version 2 of the License, or
 
11
(at your option) any later version.
 
12
 
 
13
This program is distributed in the hope that it will be useful,
 
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
GNU General Public License for more details.
 
17
 
 
18
You should have received a copy of the GNU General Public License
 
19
along with this program; if not, write to the Free Software
 
20
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
21
"""
 
22
import sys, copy, optparse, random, re
 
23
import gettext
 
24
from math import *
 
25
_ = gettext.gettext
 
26
 
 
27
#a dictionary of all of the xmlns prefixes in a standard inkscape doc
 
28
NSS = {
 
29
u'sodipodi' :u'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
 
30
u'cc'       :u'http://creativecommons.org/ns#',
 
31
u'ccOLD'    :u'http://web.resource.org/cc/',
 
32
u'svg'      :u'http://www.w3.org/2000/svg',
 
33
u'dc'       :u'http://purl.org/dc/elements/1.1/',
 
34
u'rdf'      :u'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 
35
u'inkscape' :u'http://www.inkscape.org/namespaces/inkscape',
 
36
u'xlink'    :u'http://www.w3.org/1999/xlink',
 
37
u'xml'      :u'http://www.w3.org/XML/1998/namespace'
 
38
}
 
39
 
 
40
#a dictionary of unit to user unit conversion factors
 
41
uuconv = {'in':90.0, 'pt':1.25, 'px':1, 'mm':3.5433070866, 'cm':35.433070866, 'pc':15.0}
 
42
def unittouu(string):
 
43
    '''Returns userunits given a string representation of units in another system'''
 
44
    unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))
 
45
    param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
 
46
 
 
47
    p = param.match(string)
 
48
    u = unit.search(string)    
 
49
    if p:
 
50
        retval = float(p.string[p.start():p.end()])
 
51
    else:
 
52
        retval = 0.0
 
53
    if u:
 
54
        try:
 
55
            return retval * uuconv[u.string[u.start():u.end()]]
 
56
        except KeyError:
 
57
            pass
 
58
    return retval
 
59
 
 
60
def uutounit(val, unit):
 
61
    return val/uuconv[unit]
 
62
 
 
63
try:
 
64
    from lxml import etree
 
65
except:
 
66
    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'))
 
67
 
 
68
def debug(what):
 
69
    sys.stderr.write(str(what) + "\n")
 
70
    return what
 
71
 
 
72
def errormsg(msg):
 
73
    """Intended for end-user-visible error messages.
 
74
    
 
75
       (Currently just writes to stderr with an appended newline, but could do
 
76
       something better in future: e.g. could add markup to distinguish error
 
77
       messages from status messages or debugging output.)
 
78
      
 
79
       Note that this should always be combined with translation:
 
80
 
 
81
         import gettext
 
82
         _ = gettext.gettext
 
83
         ...
 
84
         inkex.errormsg(_("This extension requires two selected paths."))
 
85
    """
 
86
    sys.stderr.write((str(msg) + "\n").encode("UTF-8"))
 
87
 
 
88
def check_inkbool(option, opt, value):
 
89
    if str(value).capitalize() == 'True':
 
90
        return True
 
91
    elif str(value).capitalize() == 'False':
 
92
        return False
 
93
    else:
 
94
        raise optparse.OptionValueError("option %s: invalid inkbool value: %s" % (opt, value))
 
95
 
 
96
def addNS(tag, ns=None):
 
97
    val = tag
 
98
    if ns!=None and len(ns)>0 and NSS.has_key(ns) and len(tag)>0 and tag[0]!='{':
 
99
        val = "{%s}%s" % (NSS[ns], tag)
 
100
    return val
 
101
 
 
102
class InkOption(optparse.Option):
 
103
    TYPES = optparse.Option.TYPES + ("inkbool",)
 
104
    TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER)
 
105
    TYPE_CHECKER["inkbool"] = check_inkbool
 
106
 
 
107
class Effect:
 
108
    """A class for creating Inkscape SVG Effects"""
 
109
 
 
110
    def __init__(self, *args, **kwargs):
 
111
        self.document=None
 
112
        self.ctx=None
 
113
        self.selected={}
 
114
        self.doc_ids={}
 
115
        self.options=None
 
116
        self.args=None
 
117
        self.OptionParser = optparse.OptionParser(usage="usage: %prog [options] SVGfile",option_class=InkOption)
 
118
        self.OptionParser.add_option("--id",
 
119
                        action="append", type="string", dest="ids", default=[], 
 
120
                        help="id attribute of object to manipulate")
 
121
 
 
122
    def effect(self):
 
123
        pass
 
124
 
 
125
    def getoptions(self,args=sys.argv[1:]):
 
126
        """Collect command line arguments"""
 
127
        self.options, self.args = self.OptionParser.parse_args(args)
 
128
 
 
129
    def parse(self,file=None):
 
130
        """Parse document in specified file or on stdin"""
 
131
        try:
 
132
            try:
 
133
                stream = open(file,'r')
 
134
            except:
 
135
                stream = open(self.args[-1],'r')
 
136
        except:
 
137
            stream = sys.stdin
 
138
        self.document = etree.parse(stream)
 
139
        stream.close()
 
140
 
 
141
    def getposinlayer(self):
 
142
        #defaults
 
143
        self.current_layer = self.document.getroot()
 
144
        self.view_center = (0.0,0.0)
 
145
 
 
146
        layerattr = self.document.xpath('//sodipodi:namedview/@inkscape:current-layer', namespaces=NSS)
 
147
        if layerattr:
 
148
            layername = layerattr[0]
 
149
            layer = self.document.xpath('//svg:g[@id="%s"]' % layername, namespaces=NSS)
 
150
            if layer:
 
151
                self.current_layer = layer[0]
 
152
 
 
153
        xattr = self.document.xpath('//sodipodi:namedview/@inkscape:cx', namespaces=NSS)
 
154
        yattr = self.document.xpath('//sodipodi:namedview/@inkscape:cy', namespaces=NSS)
 
155
        doc_height = unittouu(self.document.getroot().get('height'))
 
156
        if xattr and yattr:
 
157
            x = xattr[0]
 
158
            y = yattr[0]
 
159
            if x and y:
 
160
                self.view_center = (float(x), doc_height - float(y)) # FIXME: y-coordinate flip, eliminate it when it's gone in Inkscape
 
161
 
 
162
    def getselected(self):
 
163
        """Collect selected nodes"""
 
164
        for i in self.options.ids:
 
165
            path = '//*[@id="%s"]' % i
 
166
            for node in self.document.xpath(path, namespaces=NSS):
 
167
                self.selected[i] = node
 
168
 
 
169
    def getdocids(self):
 
170
        docIdNodes = self.document.xpath('//@id', namespaces=NSS)
 
171
        for m in docIdNodes:
 
172
            self.doc_ids[m] = 1
 
173
 
 
174
    def getNamedView(self):
 
175
        return self.document.xpath('//sodipodi:namedview', namespaces=NSS)[0]
 
176
 
 
177
    def createGuide(self, posX, posY, angle):
 
178
        atts = {
 
179
          'position': str(posX)+','+str(posY),
 
180
          'orientation': str(sin(radians(angle)))+','+str(-cos(radians(angle)))
 
181
          }
 
182
        guide = etree.SubElement(
 
183
                  self.getNamedView(),
 
184
                  addNS('guide','sodipodi'), atts )
 
185
        return guide
 
186
 
 
187
    def output(self):
 
188
        """Serialize document into XML on stdout"""
 
189
        self.document.write(sys.stdout)
 
190
 
 
191
    def affect(self, args=sys.argv[1:], output=True):
 
192
        """Affect an SVG document with a callback effect"""
 
193
        self.getoptions(args)
 
194
        self.parse()
 
195
        self.getposinlayer()
 
196
        self.getselected()
 
197
        self.getdocids()
 
198
        self.effect()
 
199
        if output: self.output()
 
200
 
 
201
    def uniqueId(self, old_id, make_new_id = True):
 
202
        new_id = old_id
 
203
        if make_new_id:
 
204
            while new_id in self.doc_ids:
 
205
                new_id += random.choice('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
 
206
            self.doc_ids[new_id] = 1
 
207
        return new_id
 
208
 
 
209
    def xpathSingle(self, path):
 
210
        try:
 
211
            retval = self.document.xpath(path, namespaces=NSS)[0]
 
212
        except:
 
213
            errormsg(_("No matching node for expression: %s") % path)
 
214
            retval = None
 
215
        return retval
 
216
            
 
217
 
 
218
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99