summaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authorArcadie M. Cracan <acracan@gmail.com>2009-12-27 11:31:36 +0000
committerArcadie M. Cracan <acracan@gmail.com>2009-12-27 11:31:36 +0000
commit30eaa4a74569f4fc5ee802ee3883201379c18235 (patch)
treeaf9d0af2df52735f67a9f4af1a821f6d2fe2f242 /share
parentConnector tool: make connectors avoid the convex hull of shapes. (diff)
parentWarning cleanup (diff)
downloadinkscape-30eaa4a74569f4fc5ee802ee3883201379c18235.tar.gz
inkscape-30eaa4a74569f4fc5ee802ee3883201379c18235.zip
Connector tool: make connectors avoid the convex hull of shapes.
(bzr r8857.1.2)
Diffstat (limited to 'share')
-rw-r--r--share/extensions/Barcode/EAN13.py10
-rw-r--r--share/extensions/Barcode/EAN5.py67
-rw-r--r--share/extensions/Barcode/Makefile.am1
-rw-r--r--share/extensions/Barcode/UPCA.py4
-rw-r--r--share/extensions/Barcode/UPCE.py4
-rw-r--r--share/extensions/Barcode/__init__.py3
-rw-r--r--share/extensions/Makefile.am4
-rw-r--r--share/extensions/embedimage.py7
-rwxr-xr-xshare/extensions/inkex.py5
-rw-r--r--share/extensions/measure.py23
-rw-r--r--share/extensions/render_alphabetsoup.py924
-rw-r--r--share/extensions/render_barcode.inx53
-rw-r--r--share/extensions/render_barcode_datamatrix.inx20
-rw-r--r--share/extensions/render_barcode_datamatrix.py654
-rw-r--r--share/extensions/wireframe_sphere.inx24
-rw-r--r--share/extensions/wireframe_sphere.py220
-rw-r--r--share/icons/Makefile.am7
-rw-r--r--share/icons/application/16x16/Makefile.am5
-rw-r--r--share/icons/application/16x16/inkscape.pngbin0 -> 989 bytes
-rw-r--r--share/icons/application/22x22/Makefile.am5
-rw-r--r--share/icons/application/22x22/inkscape.pngbin0 -> 1452 bytes
-rw-r--r--share/icons/application/24x24/Makefile.am5
-rw-r--r--share/icons/application/24x24/inkscape.pngbin0 -> 1473 bytes
-rw-r--r--share/icons/application/256x256/Makefile.am5
-rw-r--r--share/icons/application/256x256/inkscape.pngbin0 -> 40270 bytes
-rw-r--r--share/icons/application/32x32/Makefile.am5
-rw-r--r--share/icons/application/32x32/inkscape.pngbin0 -> 2155 bytes
-rw-r--r--share/icons/application/48x48/Makefile.am5
-rw-r--r--share/icons/application/48x48/inkscape.pngbin0 -> 3818 bytes
-rw-r--r--share/icons/application/Makefile.am15
-rw-r--r--share/icons/color-management-icon.pngbin0 -> 2720 bytes
-rw-r--r--share/icons/out-of-gamut-icon.pngbin0 -> 1016 bytes
-rw-r--r--share/icons/out-of-gamut-icon.svg22
-rw-r--r--share/icons/too-much-ink-icon.pngbin0 -> 655 bytes
-rw-r--r--share/icons/too-much-ink-icon.svg70
35 files changed, 1644 insertions, 523 deletions
diff --git a/share/extensions/Barcode/EAN13.py b/share/extensions/Barcode/EAN13.py
index 3450893fc..c79b7749d 100644
--- a/share/extensions/Barcode/EAN13.py
+++ b/share/extensions/Barcode/EAN13.py
@@ -42,8 +42,8 @@ class Object(Barcode):
if len(number) == 12:
number = number + self.getChecksum(number)
else:
- if not self.varifyChecksum(number):
- sys.stderr.write("EAN13 Checksum not correct for this barcode, omit last charicter to generate new checksum.\n")
+ if not self.verifyChecksum(number):
+ sys.stderr.write("EAN13 Checksum not correct for this barcode, omit last character to generate new checksum.\n")
return
result = result + guardBar
@@ -83,9 +83,9 @@ class Object(Barcode):
return str(z)
- def varifyChecksum(self, number):
- new = self.getChecksum(number[:12])
- existing = number[12]
+ def verifyChecksum(self, number):
+ new = self.getChecksum(number[:-1])
+ existing = number[-1]
return new == existing
def getStyle(self, index):
diff --git a/share/extensions/Barcode/EAN5.py b/share/extensions/Barcode/EAN5.py
new file mode 100644
index 000000000..9113566a3
--- /dev/null
+++ b/share/extensions/Barcode/EAN5.py
@@ -0,0 +1,67 @@
+'''
+Copyright (C) 2007 Martin Owens
+Copyright (C) 2009 Aaron C Spike
+
+Thanks to Lineaire Chez of Inkbar ( www.inkbar.lineaire.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
+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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+'''
+
+from Base import Barcode
+import sys
+
+mapLeftFamily = [
+ [ "0001101","0011001","0010011","0111101","0100011","0110001","0101111","0111011","0110111","0001011" ], #L
+ [ "0100111","0110011","0011011","0100001","0011101","0111001","0000101","0010001","0001001","0010111" ], #G
+]
+mapFamily = [ '11000','10100','10010','10001','01100','00110','00011','01010','01001','00101' ]
+
+startBar = '01011';
+sepBar = '01';
+
+class Object(Barcode):
+ def encode(self, number):
+ result = []
+ self.x += 110.0 # horizontal offset so it does not overlap EAN13
+ self.y -= self.height + 5 # move the text to the top
+ if len(number) != 5 or not number.isdigit():
+ sys.stderr.write("Can not encode '" + number + "' into EAN5 Barcode, Size must be 5 numbers only\n")
+ return
+
+ check = self.getChecksum(number)
+ family = mapFamily[check]
+
+ for i in range(5):
+ mapLeft = mapLeftFamily[int(family[i])]
+ result.append(mapLeft[int(number[i])])
+
+ self.label = number[0]
+ for i in range(1,5):
+ self.label += ' ' + number[i]
+ self.inclabel = self.label
+ return startBar + '01'.join(result)
+
+ def getChecksum(self, number):
+ return sum([int(n)*int(m) for n,m in zip(number, '39393')]) % 10
+
+ def getStyle(self, index):
+ result = { 'width' : '1', 'top' : int(self.y) + self.height + 5 + int(self.fontSize()), 'write' : True }
+ if index==0: # White Space
+ result['write'] = False
+ elif index==1: # Black Bar
+ result['height'] = int(self.height)
+ elif index==2: # Guide Bar
+ result['height'] = int(self.height) + 5
+ return result
diff --git a/share/extensions/Barcode/Makefile.am b/share/extensions/Barcode/Makefile.am
index 338c01c10..fd5f1663b 100644
--- a/share/extensions/Barcode/Makefile.am
+++ b/share/extensions/Barcode/Makefile.am
@@ -9,6 +9,7 @@ barcode_SCRIPTS = \
Code93.py \
EAN13.py \
EAN8.py \
+ EAN5.py \
__init__.py \
RM4CC.py \
UPCA.py \
diff --git a/share/extensions/Barcode/UPCA.py b/share/extensions/Barcode/UPCA.py
index b67d0830b..89c97eed6 100644
--- a/share/extensions/Barcode/UPCA.py
+++ b/share/extensions/Barcode/UPCA.py
@@ -33,8 +33,8 @@ class Object(EAN13.Object):
if len(number) == 11:
number = number + self.getChecksum(number)
else:
- if not self.varifyChecksum(number):
- sys.stderr.write("EAN13 Checksum not correct for this barcode, omit last charicter to generate new checksum.\n")
+ if not self.verifyChecksum(number):
+ sys.stderr.write("UPC-A Checksum not correct for this barcode, omit last character to generate new checksum.\n")
return
result = result + guardBar
diff --git a/share/extensions/Barcode/UPCE.py b/share/extensions/Barcode/UPCE.py
index 0ad518680..b41e94e8c 100644
--- a/share/extensions/Barcode/UPCE.py
+++ b/share/extensions/Barcode/UPCE.py
@@ -47,8 +47,8 @@ class Object(EAN13.Object):
if not echeck:
echeck = self.getChecksum(number)
else:
- if not self.varifyChecksum(number + echeck):
- sys.stderr.write("UPC-E Checksum not correct for this barcode, omit last charicter to generate new checksum.\n")
+ if not self.verifyChecksum(number + echeck):
+ sys.stderr.write("UPC-E Checksum not correct for this barcode, omit last character to generate new checksum.\n")
return
number = self.ConvertAtoE(number)
diff --git a/share/extensions/Barcode/__init__.py b/share/extensions/Barcode/__init__.py
index a455c3b7c..b2257ebcb 100644
--- a/share/extensions/Barcode/__init__.py
+++ b/share/extensions/Barcode/__init__.py
@@ -74,6 +74,9 @@ def getBarcode(format, param={}):
elif format in ['ean13', 'ucc13','jan']:
import EAN13
return EAN13.Object(param)
+ elif format == 'ean5':
+ import EAN5
+ return EAN5.Object(param)
elif format in ['ean8', 'ucc8']:
import EAN8
return EAN8.Object(param)
diff --git a/share/extensions/Makefile.am b/share/extensions/Makefile.am
index 14238ad31..1650923e0 100644
--- a/share/extensions/Makefile.am
+++ b/share/extensions/Makefile.am
@@ -96,6 +96,7 @@ extensions = \
radiusrand.py \
restack.py \
render_barcode.py \
+ render_barcode_datamatrix.py \
render_alphabetsoup.py \
render_alphabetsoup_config.py \
rtree.py \
@@ -131,6 +132,7 @@ extensions = \
web-set-att.py \
web-transmit-att.py \
whirl.py \
+ wireframe_sphere.py \
wmf_output.py \
yocto_css.py
@@ -222,6 +224,7 @@ modules = \
ps_input.inx \
radiusrand.inx \
render_barcode.inx \
+ render_barcode_datamatrix.inx \
render_alphabetsoup.inx \
restack.inx \
rubberstretch.inx \
@@ -249,6 +252,7 @@ modules = \
web-set-att.inx \
web-transmit-att.inx \
whirl.inx \
+ wireframe_sphere.inx \
wmf_input.inx \
wmf_output.inx \
xaml2svg.inx
diff --git a/share/extensions/embedimage.py b/share/extensions/embedimage.py
index 16439223b..f73ceb358 100644
--- a/share/extensions/embedimage.py
+++ b/share/extensions/embedimage.py
@@ -56,9 +56,8 @@ class Embedder(inkex.Effect):
if xlink is None or xlink[:5] != 'data:':
absref=node.get(inkex.addNS('absref','sodipodi'))
url=urlparse.urlparse(xlink)
- href=urllib.unquote(url.path)
- if os.name == 'nt' and href[0] == '/':
- href = href[1:]
+ href=urllib.url2pathname(url.path)
+
path=''
#path selection strategy:
# 1. href if absolute
@@ -70,6 +69,8 @@ class Embedder(inkex.Effect):
if (absref != None):
path=absref
+ path=unicode(path, "utf-8")
+
if (not os.path.isfile(path)):
inkex.errormsg(_('No xlink:href or sodipodi:absref attributes found, or they do not point to an existing file! Unable to embed image.'))
if path:
diff --git a/share/extensions/inkex.py b/share/extensions/inkex.py
index b7e3e0e63..1a70c25d6 100755
--- a/share/extensions/inkex.py
+++ b/share/extensions/inkex.py
@@ -38,7 +38,8 @@ 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, 'pc':15.0}
+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()))
@@ -83,7 +84,7 @@ def errormsg(msg):
...
inkex.errormsg(_("This extension requires two selected paths."))
"""
- sys.stderr.write((str(msg) + "\n").encode("UTF-8"))
+ sys.stderr.write((unicode(msg) + "\n").encode("UTF-8"))
def check_inkbool(option, opt, value):
if str(value).capitalize() == 'True':
diff --git a/share/extensions/measure.py b/share/extensions/measure.py
index 8eacd40c6..68586530b 100644
--- a/share/extensions/measure.py
+++ b/share/extensions/measure.py
@@ -126,28 +126,7 @@ class Length(inkex.Effect):
p = cubicsuperpath.parsePath(node.get('d'))
num = 1
slengths, stotal = csplength(p)
- ''' Wio: Umrechnung in unit '''
- if self.options.unit=="mm":
- factor=25.4/90.0 # px->mm
- elif self.options.unit=="pt":
- factor=0.80 # px->pt
- elif self.options.unit=="cm":
- factor=25.4/900.0 # px->cm
- elif self.options.unit=="m":
- factor=25.4/90000.0 # px->m
- elif self.options.unit=="km":
- factor=25.4/90000000.0 # px->km
- elif self.options.unit=="in":
- factor=1.0/90.0 # px->in
- elif self.options.unit=="ft":
- factor=1.0/90.0/12.0 # px->ft
- elif self.options.unit=="yd":
- factor=1.0/90.0/36.0 # px->yd
- else :
- ''' Default unit is px'''
- factor=1
- self.options.unit="px"
-
+ factor = 1.0/inkex.unittouu('1'+self.options.unit)
# Format the length as string
lenstr = locale.format("%(len)25."+str(prec)+"f",{'len':round(stotal*factor*self.options.scale,prec)}).strip()
self.addTextOnPath(self.group,0, 0,lenstr+' '+self.options.unit, id, self.options.offset)
diff --git a/share/extensions/render_alphabetsoup.py b/share/extensions/render_alphabetsoup.py
index 6bc38459b..7e4009328 100644
--- a/share/extensions/render_alphabetsoup.py
+++ b/share/extensions/render_alphabetsoup.py
@@ -1,461 +1,463 @@
-#!/usr/bin/env python
-'''
-Copyright (C) 2001-2002 Matt Chisholm matt@theory.org
-Copyright (C) 2008 Joel Holdsworth joel@airwebreathe.org.uk
- for AP
-
-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-'''
-
-import copy
-import inkex
-import simplestyle
-import math
-import cmath
-import string
-import random
-import render_alphabetsoup_config
-import bezmisc
-import simplepath
-import os
-import sys
-
-syntax = render_alphabetsoup_config.syntax
-alphabet = render_alphabetsoup_config.alphabet
-units = render_alphabetsoup_config.units
-font = render_alphabetsoup_config.font
-
-# Loads a super-path from a given SVG file
-def loadPath( svgPath ):
- extensionDir = os.path.normpath(
- os.path.join( os.getcwd(), os.path.dirname(__file__) )
- )
- # __file__ is better then sys.argv[0] because this file may be a module
- # for another one.
- tree = inkex.etree.parse( extensionDir + "/" + svgPath )
- root = tree.getroot()
- pathElement = root.find('{http://www.w3.org/2000/svg}path')
- if pathElement == None:
- return None, 0, 0
- d = pathElement.get("d")
- width = float(root.get("width"))
- height = float(root.get("height"))
- return simplepath.parsePath(d), width, height # Currently we only support a single path
-
-def combinePaths( pathA, pathB ):
- if pathA == None and pathB == None:
- return None
- elif pathA == None:
- return pathB
- elif pathB == None:
- return pathA
- else:
- return pathA + pathB
-
-def flipLeftRight( sp, width ):
- for cmd,params in sp:
- defs = simplepath.pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'x':
- params[i] = width - params[i]
-
-def flipTopBottom( sp, height ):
- for cmd,params in sp:
- defs = simplepath.pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'y':
- params[i] = height - params[i]
-
-def solveQuadratic(a, b, c):
- det = b*b - 4.0*a*c
- if det >= 0: # real roots
- sdet = math.sqrt(det)
- else: # complex roots
- sdet = cmath.sqrt(det)
- return (-b + sdet) / (2*a), (-b - sdet) / (2*a)
-
-def cbrt(x):
- if x >= 0:
- return x**(1.0/3.0)
- else:
- return -((-x)**(1.0/3.0))
-
-def findRealRoots(a,b,c,d):
- if a != 0:
- a, b, c, d = 1, b/float(a), c/float(a), d/float(a) # Divide through by a
- t = b / 3.0
- p, q = c - 3 * t**2, d - c * t + 2 * t**3
- u, v = solveQuadratic(1, q, -(p/3.0)**3)
- if type(u) == type(0j): # Complex Cubic Root
- r = math.sqrt(u.real**2 + u.imag**2)
- w = math.atan2(u.imag, u.real)
- y1 = 2 * cbrt(r) * math.cos(w / 3.0)
- else: # Complex Real Root
- y1 = cbrt(u) + cbrt(v)
-
- y2, y3 = solveQuadratic(1, y1, p + y1**2)
-
- if type(y2) == type(0j): # Are y2 and y3 complex?
- return [y1 - t]
- return [y1 - t, y2 - t, y3 - t]
- elif b != 0:
- det=c*c - 4.0*b*d
- if det >= 0:
- return [(-c + math.sqrt(det))/(2.0*b),(-c - math.sqrt(det))/(2.0*b)]
- elif c != 0:
- return [-d/c]
- return []
-
-def getPathBoundingBox( sp ):
-
- box = None
- last = None
- lostctrl = None
-
- for cmd,params in sp:
-
- segmentBox = None
-
- if cmd == 'M':
- # A move cannot contribute to the bounding box
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'L':
- if last:
- segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'C':
- if last:
- segmentBox = (min(params[4], last[0]), max(params[4], last[0]), min(params[5], last[1]), max(params[5], last[1]))
-
- bx0, by0 = last[:]
- bx1, by1, bx2, by2, bx3, by3 = params[:]
-
- # Compute the x limits
- a = (-bx0 + 3*bx1 - 3*bx2 + bx3)*3
- b = (3*bx0 - 6*bx1 + 3*bx2)*2
- c = (-3*bx0 + 3*bx1)
- ts = findRealRoots(0, a, b, c)
- for t in ts:
- if t >= 0 and t <= 1:
- x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \
- (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \
- (-3*bx0 + 3*bx1)*t + \
- bx0
- segmentBox = (min(segmentBox[0], x), max(segmentBox[1], x), segmentBox[2], segmentBox[3])
-
- # Compute the y limits
- a = (-by0 + 3*by1 - 3*by2 + by3)*3
- b = (3*by0 - 6*by1 + 3*by2)*2
- c = (-3*by0 + 3*by1)
- ts = findRealRoots(0, a, b, c)
- for t in ts:
- if t >= 0 and t <= 1:
- y = (-by0 + 3*by1 - 3*by2 + by3)*(t**3) + \
- (3*by0 - 6*by1 + 3*by2)*(t**2) + \
- (-3*by0 + 3*by1)*t + \
- by0
- segmentBox = (segmentBox[0], segmentBox[1], min(segmentBox[2], y), max(segmentBox[3], y))
-
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'Q':
- # Provisional
- if last:
- segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'A':
- # Provisional
- if last:
- segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
- last = params[-2:]
- lastctrl = params[2:4]
-
- if segmentBox:
- if box:
- box = (min(segmentBox[0],box[0]), max(segmentBox[1],box[1]), min(segmentBox[2],box[2]), max(segmentBox[3],box[3]))
- else:
- box = segmentBox
- return box
-
-def mxfm( image, width, height, stack ): # returns possibly transformed image
- tbimage = image
- if ( stack[0] == "-" ): # top-bottom flip
- flipTopBottom(tbimage, height)
- stack.pop( 0 )
-
- lrimage = tbimage
- if ( stack[0] == "|" ): # left-right flip
- flipLeftRight(tbimage, width)
- stack.pop( 0 )
- return lrimage
-
-def comparerule( rule, nodes ): # compare node list to nodes in rule
- for i in range( 0, len(nodes)): # range( a, b ) = (a, a+1, a+2 ... b-2, b-1)
- if (nodes[i] == rule[i][0]):
- pass
- else: return 0
- return 1
-
-def findrule( state, nodes ): # find the rule which generated this subtree
- ruleset = syntax[state][1]
- nodelen = len(nodes)
- for rule in ruleset:
- rulelen = len(rule)
- if ((rulelen == nodelen) and (comparerule( rule, nodes ))):
- return rule
- return
-
-def generate( state ): # generate a random tree (in stack form)
- stack = [ state ]
- if ( len(syntax[state]) == 1 ): # if this is a stop symbol
- return stack
- else:
- stack.append( "[" )
- path = random.randint(0, (len(syntax[state][1])-1)) # choose randomly from next states
- for symbol in syntax[state][1][path]: # recurse down each non-terminal
- if ( symbol != 0 ): # 0 denotes end of list ###
- substack = generate( symbol[0] ) # get subtree
- for elt in substack:
- stack.append( elt )
- if (symbol[3]):stack.append( "-" ) # top-bottom flip
- if (symbol[4]):stack.append( "|" ) # left-right flip
- #else:
- #inkex.debug("found end of list in generate( state =", state, ")") # this should be deprecated/never happen
- stack.append("]")
- return stack
-
-def draw( stack ): # draw a character based on a tree stack
- state = stack.pop(0)
- #print state,
-
- image, width, height = loadPath( font+syntax[state][0] ) # load the image
- if (stack[0] != "["): # terminal stack element
- if (len(syntax[state]) == 1): # this state is a terminal node
- return image, width, height
- else:
- substack = generate( state ) # generate random substack
- return draw( substack ) # draw random substack
- else:
- #inkex.debug("[")
- stack.pop(0)
- images = [] # list of daughter images
- nodes = [] # list of daughter names
- while (stack[0] != "]"): # for all nodes in stack
- newstate = stack[0] # the new state
- newimage, width, height = draw( stack ) # draw the daughter state
- if (newimage):
- tfimage = mxfm( newimage, width, height, stack ) # maybe transform daughter state
- images.append( [tfimage, width, height] ) # list of daughter images
- nodes.append( newstate ) # list of daughter nodes
- else:
- #inkex.debug(("recurse on",newstate,"failed")) # this should never happen
- return None, 0, 0
- rule = findrule( state, nodes ) # find the rule for this subtree
-
- for i in range( 0, len(images)):
- currimg, width, height = images[i]
-
- if currimg:
- #box = getPathBoundingBox(currimg)
- dx = rule[i][1]*units
- dy = rule[i][2]*units
- #newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy))
- simplepath.translatePath(currimg, dx, dy)
- image = combinePaths( image, currimg )
-
- stack.pop( 0 )
- return image, width, height
-
-def draw_crop_scale( stack, zoom ): # draw, crop and scale letter image
- image, width, height = draw(stack)
- bbox = getPathBoundingBox(image)
- simplepath.translatePath(image, -bbox[0], 0)
- simplepath.scalePath(image, zoom/units, zoom/units)
- return image, bbox[1] - bbox[0], bbox[3] - bbox[2]
-
-def randomize_input_string( str, zoom ): # generate list of images based on input string
- imagelist = []
-
- for i in range(0,len(str)):
- char = str[i]
- #if ( re.match("[a-zA-Z0-9?]", char)):
- if ( alphabet.has_key(char)):
- if ((i > 0) and (char == str[i-1])): # if this letter matches previous letter
- imagelist.append(imagelist[len(stack)-1])# make them the same image
- else: # generate image for letter
- stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-1))] , "." )
- #stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-2))] , "." )
- imagelist.append( draw_crop_scale( stack, zoom ))
- elif( char == " "): # add a " " space to the image list
- imagelist.append( " " )
- else: # this character is not in config.alphabet, skip it
- print "bad character", char
- return imagelist
-
-def optikern( image, width, zoom ): # optical kerning algorithm
- left = []
- right = []
-
- for i in range( 0, 36 ):
- y = 0.5 * (i + 0.5) * zoom
- xmin = None
- xmax = None
-
- for cmd,params in image:
-
- segmentBox = None
-
- if cmd == 'M':
- # A move cannot contribute to the bounding box
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'L':
- if (y >= last[1] and y <= params[1]) or (y >= params[1] and y <= last[1]):
- if params[0] == last[0]:
- x = params[0]
- else:
- a = (params[1] - last[1]) / (params[0] - last[0])
- b = last[1] - a * last[0]
- if a != 0:
- x = (y - b) / a
- else: x = None
-
- if x:
- if xmin == None or x < xmin: xmin = x
- if xmax == None or x > xmax: xmax = x
-
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'C':
- if last:
- bx0, by0 = last[:]
- bx1, by1, bx2, by2, bx3, by3 = params[:]
-
- d = by0 - y
- c = -3*by0 + 3*by1
- b = 3*by0 - 6*by1 + 3*by2
- a = -by0 + 3*by1 - 3*by2 + by3
-
- ts = findRealRoots(a, b, c, d)
-
- for t in ts:
- if t >= 0 and t <= 1:
- x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \
- (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \
- (-3*bx0 + 3*bx1)*t + \
- bx0
- if xmin == None or x < xmin: xmin = x
- if xmax == None or x > xmax: xmax = x
-
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'Q':
- # Quadratic beziers are ignored
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'A':
- # Arcs are ignored
- last = params[-2:]
- lastctrl = params[2:4]
-
-
- if xmin != None and xmax != None:
- left.append( xmin ) # distance from left edge of region to left edge of bbox
- right.append( width - xmax ) # distance from right edge of region to right edge of bbox
- else:
- left.append( width )
- right.append( width )
-
- return (left, right)
-
-def layoutstring( imagelist, zoom ): # layout string of letter-images using optical kerning
- kernlist = []
- length = zoom
- for entry in imagelist:
- if (entry == " "): # leaving room for " " space characters
- length = length + (zoom * render_alphabetsoup_config.space)
- else:
- image, width, height = entry
- length = length + width + zoom # add letter length to overall length
- kernlist.append( optikern(image, width, zoom) ) # append kerning data for this image
-
- workspace = None
-
- position = zoom
- for i in range(0, len(kernlist)):
- while(imagelist[i] == " "):
- position = position + (zoom * render_alphabetsoup_config.space )
- imagelist.pop(i)
- image, width, height = imagelist[i]
-
- # set the kerning
- if i == 0: kern = 0 # for first image, kerning is zero
- else:
- kerncompare = [] # kerning comparison array
- for j in range( 0, len(kernlist[i][0])):
- kerncompare.append( kernlist[i][0][j]+kernlist[i-1][1][j] )
- kern = min( kerncompare )
-
- position = position - kern # move position back by kern amount
- thisimage = copy.deepcopy(image)
- simplepath.translatePath(thisimage, position, 0)
- workspace = combinePaths(workspace, thisimage)
- position = position + width + zoom # advance position by letter width
-
- return workspace
-
-class AlphabetSoup(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-t", "--text",
- action="store", type="string",
- dest="text", default="Inkscape",
- help="The text for alphabet soup")
- self.OptionParser.add_option("-z", "--zoom",
- action="store", type="float",
- dest="zoom", default="8.0",
- help="The zoom on the output graphics")
- self.OptionParser.add_option("-s", "--seed",
- action="store", type="int",
- dest="seed", default="0",
- help="The random seed for the soup")
-
- def effect(self):
- zoom = self.options.zoom
- random.seed(self.options.seed)
-
- imagelist = randomize_input_string(self.options.text, zoom)
- image = layoutstring( imagelist, zoom )
-
- if image:
- s = { 'stroke': 'none', 'fill': '#000000' }
-
- new = inkex.etree.Element(inkex.addNS('path','svg'))
- new.set('style', simplestyle.formatStyle(s))
-
- new.set('d', simplepath.formatPath(image))
- self.current_layer.append(new)
-
-if __name__ == '__main__':
- e = AlphabetSoup()
- e.affect()
-
+#!/usr/bin/env python
+'''
+Copyright (C) 2001-2002 Matt Chisholm matt@theory.org
+Copyright (C) 2008 Joel Holdsworth joel@airwebreathe.org.uk
+ for AP
+
+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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+'''
+
+import copy
+import inkex
+import simplestyle
+import math
+import cmath
+import string
+import random
+import render_alphabetsoup_config
+import bezmisc
+import simplepath
+import os
+import sys
+import gettext
+_ = gettext.gettext
+
+syntax = render_alphabetsoup_config.syntax
+alphabet = render_alphabetsoup_config.alphabet
+units = render_alphabetsoup_config.units
+font = render_alphabetsoup_config.font
+
+# Loads a super-path from a given SVG file
+def loadPath( svgPath ):
+ extensionDir = os.path.normpath(
+ os.path.join( os.getcwd(), os.path.dirname(__file__) )
+ )
+ # __file__ is better then sys.argv[0] because this file may be a module
+ # for another one.
+ tree = inkex.etree.parse( extensionDir + "/" + svgPath )
+ root = tree.getroot()
+ pathElement = root.find('{http://www.w3.org/2000/svg}path')
+ if pathElement == None:
+ return None, 0, 0
+ d = pathElement.get("d")
+ width = float(root.get("width"))
+ height = float(root.get("height"))
+ return simplepath.parsePath(d), width, height # Currently we only support a single path
+
+def combinePaths( pathA, pathB ):
+ if pathA == None and pathB == None:
+ return None
+ elif pathA == None:
+ return pathB
+ elif pathB == None:
+ return pathA
+ else:
+ return pathA + pathB
+
+def flipLeftRight( sp, width ):
+ for cmd,params in sp:
+ defs = simplepath.pathdefs[cmd]
+ for i in range(defs[1]):
+ if defs[3][i] == 'x':
+ params[i] = width - params[i]
+
+def flipTopBottom( sp, height ):
+ for cmd,params in sp:
+ defs = simplepath.pathdefs[cmd]
+ for i in range(defs[1]):
+ if defs[3][i] == 'y':
+ params[i] = height - params[i]
+
+def solveQuadratic(a, b, c):
+ det = b*b - 4.0*a*c
+ if det >= 0: # real roots
+ sdet = math.sqrt(det)
+ else: # complex roots
+ sdet = cmath.sqrt(det)
+ return (-b + sdet) / (2*a), (-b - sdet) / (2*a)
+
+def cbrt(x):
+ if x >= 0:
+ return x**(1.0/3.0)
+ else:
+ return -((-x)**(1.0/3.0))
+
+def findRealRoots(a,b,c,d):
+ if a != 0:
+ a, b, c, d = 1, b/float(a), c/float(a), d/float(a) # Divide through by a
+ t = b / 3.0
+ p, q = c - 3 * t**2, d - c * t + 2 * t**3
+ u, v = solveQuadratic(1, q, -(p/3.0)**3)
+ if type(u) == type(0j): # Complex Cubic Root
+ r = math.sqrt(u.real**2 + u.imag**2)
+ w = math.atan2(u.imag, u.real)
+ y1 = 2 * cbrt(r) * math.cos(w / 3.0)
+ else: # Complex Real Root
+ y1 = cbrt(u) + cbrt(v)
+
+ y2, y3 = solveQuadratic(1, y1, p + y1**2)
+
+ if type(y2) == type(0j): # Are y2 and y3 complex?
+ return [y1 - t]
+ return [y1 - t, y2 - t, y3 - t]
+ elif b != 0:
+ det=c*c - 4.0*b*d
+ if det >= 0:
+ return [(-c + math.sqrt(det))/(2.0*b),(-c - math.sqrt(det))/(2.0*b)]
+ elif c != 0:
+ return [-d/c]
+ return []
+
+def getPathBoundingBox( sp ):
+
+ box = None
+ last = None
+ lostctrl = None
+
+ for cmd,params in sp:
+
+ segmentBox = None
+
+ if cmd == 'M':
+ # A move cannot contribute to the bounding box
+ last = params[:]
+ lastctrl = params[:]
+ elif cmd == 'L':
+ if last:
+ segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
+ last = params[:]
+ lastctrl = params[:]
+ elif cmd == 'C':
+ if last:
+ segmentBox = (min(params[4], last[0]), max(params[4], last[0]), min(params[5], last[1]), max(params[5], last[1]))
+
+ bx0, by0 = last[:]
+ bx1, by1, bx2, by2, bx3, by3 = params[:]
+
+ # Compute the x limits
+ a = (-bx0 + 3*bx1 - 3*bx2 + bx3)*3
+ b = (3*bx0 - 6*bx1 + 3*bx2)*2
+ c = (-3*bx0 + 3*bx1)
+ ts = findRealRoots(0, a, b, c)
+ for t in ts:
+ if t >= 0 and t <= 1:
+ x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \
+ (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \
+ (-3*bx0 + 3*bx1)*t + \
+ bx0
+ segmentBox = (min(segmentBox[0], x), max(segmentBox[1], x), segmentBox[2], segmentBox[3])
+
+ # Compute the y limits
+ a = (-by0 + 3*by1 - 3*by2 + by3)*3
+ b = (3*by0 - 6*by1 + 3*by2)*2
+ c = (-3*by0 + 3*by1)
+ ts = findRealRoots(0, a, b, c)
+ for t in ts:
+ if t >= 0 and t <= 1:
+ y = (-by0 + 3*by1 - 3*by2 + by3)*(t**3) + \
+ (3*by0 - 6*by1 + 3*by2)*(t**2) + \
+ (-3*by0 + 3*by1)*t + \
+ by0
+ segmentBox = (segmentBox[0], segmentBox[1], min(segmentBox[2], y), max(segmentBox[3], y))
+
+ last = params[-2:]
+ lastctrl = params[2:4]
+
+ elif cmd == 'Q':
+ # Provisional
+ if last:
+ segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
+ last = params[-2:]
+ lastctrl = params[2:4]
+
+ elif cmd == 'A':
+ # Provisional
+ if last:
+ segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
+ last = params[-2:]
+ lastctrl = params[2:4]
+
+ if segmentBox:
+ if box:
+ box = (min(segmentBox[0],box[0]), max(segmentBox[1],box[1]), min(segmentBox[2],box[2]), max(segmentBox[3],box[3]))
+ else:
+ box = segmentBox
+ return box
+
+def mxfm( image, width, height, stack ): # returns possibly transformed image
+ tbimage = image
+ if ( stack[0] == "-" ): # top-bottom flip
+ flipTopBottom(tbimage, height)
+ stack.pop( 0 )
+
+ lrimage = tbimage
+ if ( stack[0] == "|" ): # left-right flip
+ flipLeftRight(tbimage, width)
+ stack.pop( 0 )
+ return lrimage
+
+def comparerule( rule, nodes ): # compare node list to nodes in rule
+ for i in range( 0, len(nodes)): # range( a, b ) = (a, a+1, a+2 ... b-2, b-1)
+ if (nodes[i] == rule[i][0]):
+ pass
+ else: return 0
+ return 1
+
+def findrule( state, nodes ): # find the rule which generated this subtree
+ ruleset = syntax[state][1]
+ nodelen = len(nodes)
+ for rule in ruleset:
+ rulelen = len(rule)
+ if ((rulelen == nodelen) and (comparerule( rule, nodes ))):
+ return rule
+ return
+
+def generate( state ): # generate a random tree (in stack form)
+ stack = [ state ]
+ if ( len(syntax[state]) == 1 ): # if this is a stop symbol
+ return stack
+ else:
+ stack.append( "[" )
+ path = random.randint(0, (len(syntax[state][1])-1)) # choose randomly from next states
+ for symbol in syntax[state][1][path]: # recurse down each non-terminal
+ if ( symbol != 0 ): # 0 denotes end of list ###
+ substack = generate( symbol[0] ) # get subtree
+ for elt in substack:
+ stack.append( elt )
+ if (symbol[3]):stack.append( "-" ) # top-bottom flip
+ if (symbol[4]):stack.append( "|" ) # left-right flip
+ #else:
+ #inkex.debug("found end of list in generate( state =", state, ")") # this should be deprecated/never happen
+ stack.append("]")
+ return stack
+
+def draw( stack ): # draw a character based on a tree stack
+ state = stack.pop(0)
+ #print state,
+
+ image, width, height = loadPath( font+syntax[state][0] ) # load the image
+ if (stack[0] != "["): # terminal stack element
+ if (len(syntax[state]) == 1): # this state is a terminal node
+ return image, width, height
+ else:
+ substack = generate( state ) # generate random substack
+ return draw( substack ) # draw random substack
+ else:
+ #inkex.debug("[")
+ stack.pop(0)
+ images = [] # list of daughter images
+ nodes = [] # list of daughter names
+ while (stack[0] != "]"): # for all nodes in stack
+ newstate = stack[0] # the new state
+ newimage, width, height = draw( stack ) # draw the daughter state
+ if (newimage):
+ tfimage = mxfm( newimage, width, height, stack ) # maybe transform daughter state
+ images.append( [tfimage, width, height] ) # list of daughter images
+ nodes.append( newstate ) # list of daughter nodes
+ else:
+ #inkex.debug(("recurse on",newstate,"failed")) # this should never happen
+ return None, 0, 0
+ rule = findrule( state, nodes ) # find the rule for this subtree
+
+ for i in range( 0, len(images)):
+ currimg, width, height = images[i]
+
+ if currimg:
+ #box = getPathBoundingBox(currimg)
+ dx = rule[i][1]*units
+ dy = rule[i][2]*units
+ #newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy))
+ simplepath.translatePath(currimg, dx, dy)
+ image = combinePaths( image, currimg )
+
+ stack.pop( 0 )
+ return image, width, height
+
+def draw_crop_scale( stack, zoom ): # draw, crop and scale letter image
+ image, width, height = draw(stack)
+ bbox = getPathBoundingBox(image)
+ simplepath.translatePath(image, -bbox[0], 0)
+ simplepath.scalePath(image, zoom/units, zoom/units)
+ return image, bbox[1] - bbox[0], bbox[3] - bbox[2]
+
+def randomize_input_string( str, zoom ): # generate list of images based on input string
+ imagelist = []
+
+ for i in range(0,len(str)):
+ char = str[i]
+ #if ( re.match("[a-zA-Z0-9?]", char)):
+ if ( alphabet.has_key(char)):
+ if ((i > 0) and (char == str[i-1])): # if this letter matches previous letter
+ imagelist.append(imagelist[len(stack)-1])# make them the same image
+ else: # generate image for letter
+ stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-1))] , "." )
+ #stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-2))] , "." )
+ imagelist.append( draw_crop_scale( stack, zoom ))
+ elif( char == " "): # add a " " space to the image list
+ imagelist.append( " " )
+ else: # this character is not in config.alphabet, skip it
+ inkex.errormsg(_("bad character") + " = 0x%x" % ord(char))
+ return imagelist
+
+def optikern( image, width, zoom ): # optical kerning algorithm
+ left = []
+ right = []
+
+ for i in range( 0, 36 ):
+ y = 0.5 * (i + 0.5) * zoom
+ xmin = None
+ xmax = None
+
+ for cmd,params in image:
+
+ segmentBox = None
+
+ if cmd == 'M':
+ # A move cannot contribute to the bounding box
+ last = params[:]
+ lastctrl = params[:]
+ elif cmd == 'L':
+ if (y >= last[1] and y <= params[1]) or (y >= params[1] and y <= last[1]):
+ if params[0] == last[0]:
+ x = params[0]
+ else:
+ a = (params[1] - last[1]) / (params[0] - last[0])
+ b = last[1] - a * last[0]
+ if a != 0:
+ x = (y - b) / a
+ else: x = None
+
+ if x:
+ if xmin == None or x < xmin: xmin = x
+ if xmax == None or x > xmax: xmax = x
+
+ last = params[:]
+ lastctrl = params[:]
+ elif cmd == 'C':
+ if last:
+ bx0, by0 = last[:]
+ bx1, by1, bx2, by2, bx3, by3 = params[:]
+
+ d = by0 - y
+ c = -3*by0 + 3*by1
+ b = 3*by0 - 6*by1 + 3*by2
+ a = -by0 + 3*by1 - 3*by2 + by3
+
+ ts = findRealRoots(a, b, c, d)
+
+ for t in ts:
+ if t >= 0 and t <= 1:
+ x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \
+ (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \
+ (-3*bx0 + 3*bx1)*t + \
+ bx0
+ if xmin == None or x < xmin: xmin = x
+ if xmax == None or x > xmax: xmax = x
+
+ last = params[-2:]
+ lastctrl = params[2:4]
+
+ elif cmd == 'Q':
+ # Quadratic beziers are ignored
+ last = params[-2:]
+ lastctrl = params[2:4]
+
+ elif cmd == 'A':
+ # Arcs are ignored
+ last = params[-2:]
+ lastctrl = params[2:4]
+
+
+ if xmin != None and xmax != None:
+ left.append( xmin ) # distance from left edge of region to left edge of bbox
+ right.append( width - xmax ) # distance from right edge of region to right edge of bbox
+ else:
+ left.append( width )
+ right.append( width )
+
+ return (left, right)
+
+def layoutstring( imagelist, zoom ): # layout string of letter-images using optical kerning
+ kernlist = []
+ length = zoom
+ for entry in imagelist:
+ if (entry == " "): # leaving room for " " space characters
+ length = length + (zoom * render_alphabetsoup_config.space)
+ else:
+ image, width, height = entry
+ length = length + width + zoom # add letter length to overall length
+ kernlist.append( optikern(image, width, zoom) ) # append kerning data for this image
+
+ workspace = None
+
+ position = zoom
+ for i in range(0, len(kernlist)):
+ while(imagelist[i] == " "):
+ position = position + (zoom * render_alphabetsoup_config.space )
+ imagelist.pop(i)
+ image, width, height = imagelist[i]
+
+ # set the kerning
+ if i == 0: kern = 0 # for first image, kerning is zero
+ else:
+ kerncompare = [] # kerning comparison array
+ for j in range( 0, len(kernlist[i][0])):
+ kerncompare.append( kernlist[i][0][j]+kernlist[i-1][1][j] )
+ kern = min( kerncompare )
+
+ position = position - kern # move position back by kern amount
+ thisimage = copy.deepcopy(image)
+ simplepath.translatePath(thisimage, position, 0)
+ workspace = combinePaths(workspace, thisimage)
+ position = position + width + zoom # advance position by letter width
+
+ return workspace
+
+class AlphabetSoup(inkex.Effect):
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-t", "--text",
+ action="store", type="string",
+ dest="text", default="Inkscape",
+ help="The text for alphabet soup")
+ self.OptionParser.add_option("-z", "--zoom",
+ action="store", type="float",
+ dest="zoom", default="8.0",
+ help="The zoom on the output graphics")
+ self.OptionParser.add_option("-s", "--seed",
+ action="store", type="int",
+ dest="seed", default="0",
+ help="The random seed for the soup")
+
+ def effect(self):
+ zoom = self.options.zoom
+ random.seed(self.options.seed)
+
+ imagelist = randomize_input_string(self.options.text, zoom)
+ image = layoutstring( imagelist, zoom )
+
+ if image:
+ s = { 'stroke': 'none', 'fill': '#000000' }
+
+ new = inkex.etree.Element(inkex.addNS('path','svg'))
+ new.set('style', simplestyle.formatStyle(s))
+
+ new.set('d', simplepath.formatPath(image))
+ self.current_layer.append(new)
+
+if __name__ == '__main__':
+ e = AlphabetSoup()
+ e.affect()
+
diff --git a/share/extensions/render_barcode.inx b/share/extensions/render_barcode.inx
index 610c8bf19..91dd1bbe4 100644
--- a/share/extensions/render_barcode.inx
+++ b/share/extensions/render_barcode.inx
@@ -1,29 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>Barcode</_name>
- <id>org.inkscape.render.barcode</id>
- <dependency type="executable" location="extensions">inkex.py</dependency>
- <dependency type="executable" location="extensions">render_barcode.py</dependency>
- <param name="type" type="enum" _gui-text="Barcode Type:">
- <item value="ean8">EAN8</item>
- <item value="ean13">EAN13</item>
- <item value="upca">UPC-A</item>
- <item value="upce">UPC-E</item>
- <item value="code39">Code39</item>
- <item value="code39ext">Code39Ext</item>
- <item value="code93">Code93</item>
- <item value="code128">Code128</item>
- <item value="rm4scc">RM4CC / RM4SCC</item>
- </param>
- <param name="text" type="string" _gui-text="Barcode Data:"></param>
- <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param>
- <effect>
- <object-type>all</object-type>
- <effects-menu>
- <submenu _name="Render"/>
- </effects-menu>
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">render_barcode.py</command>
- </script>
+ <_name>Barcode</_name>
+ <id>org.inkscape.render.barcode</id>
+ <dependency type="executable" location="extensions">inkex.py</dependency>
+ <dependency type="executable" location="extensions">render_barcode.py</dependency>
+ <param name="type" type="enum" _gui-text="Barcode Type:">
+ <item value="ean8">EAN8</item>
+ <item value="ean13">EAN13</item>
+ <item value="ean5">EAN5</item>
+ <item value="upca">UPC-A</item>
+ <item value="upce">UPC-E</item>
+ <item value="code39">Code39</item>
+ <item value="code39ext">Code39Ext</item>
+ <item value="code93">Code93</item>
+ <item value="code128">Code128</item>
+ <item value="rm4scc">RM4CC / RM4SCC</item>
+ </param>
+ <param name="text" type="string" _gui-text="Barcode Data:"></param>
+ <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param>
+ <effect>
+ <object-type>all</object-type>
+ <effects-menu>
+ <submenu _name="Render"/>
+ </effects-menu>
+ </effect>
+ <script>
+ <command reldir="extensions" interpreter="python">render_barcode.py</command>
+ </script>
</inkscape-extension>
diff --git a/share/extensions/render_barcode_datamatrix.inx b/share/extensions/render_barcode_datamatrix.inx
new file mode 100644
index 000000000..ea2aa4705
--- /dev/null
+++ b/share/extensions/render_barcode_datamatrix.inx
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
+ <_name>Barcode - Datamatrix</_name>
+ <id>il.datamatrix</id>
+ <dependency type="executable" location="extensions">render_barcode_datamatrix.py</dependency>
+ <dependency type="executable" location="extensions">inkex.py</dependency>
+ <param name="text" type="string" _gui-text="Text">Inkscape</param>
+ <param name="rows" type="int" min="8" max="144" _gui-text="Rows">10</param>
+ <param name="cols" type="int" min="10" max="144" _gui-text="Cols">10</param>
+ <param name="size" type="int" min="1" max="1000" _gui-text="Square Size / px">4</param>
+ <effect>
+ <object-type>all</object-type>
+ <effects-menu>
+ <submenu _name="Render"/>
+ </effects-menu>
+ </effect>
+ <script>
+ <command reldir="extensions" interpreter="python">render_barcode_datamatrix.py</command>
+ </script>
+</inkscape-extension>
diff --git a/share/extensions/render_barcode_datamatrix.py b/share/extensions/render_barcode_datamatrix.py
new file mode 100644
index 000000000..5db552d91
--- /dev/null
+++ b/share/extensions/render_barcode_datamatrix.py
@@ -0,0 +1,654 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+'''
+Copyright (C) 2009 John Beard john.j.beard@gmail.com
+
+######DESCRIPTION######
+
+This extension renders a DataMatrix 2D barcode, as specified in
+BS ISO/IEC 16022:2006. Only ECC200 codes are considered, as these are the only
+ones recommended for an "open" system.
+
+The size of the DataMatrix is variable between 10x10 to 144x144
+
+The absolute size of the DataMatrix modules (the little squares) is also
+variable.
+
+If more data is given than can be contained in one DataMatrix,
+more than one DataMatrices will be produced.
+
+Text is encoded as ASCII (the standard provides for other options, but these are
+not implemented). Consecutive digits are encoded in a compressed form, halving
+the space required to store them.
+
+The basis processing flow is;
+ * Convert input string to codewords (modified ASCII and compressed digits)
+ * Split codewords into blocks of the right size for Reed-Solomon coding
+ * Interleave the blocks if required
+ * Apply Reed-Solomon coding
+ * De-interleave the blocks if required
+ * Place the codewords into the matrix bit by bit
+ * Render the modules in the matrix as squares
+
+######LICENCE#######
+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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+######VERSION HISTORY#####
+ Ver. Date Notes
+
+ 0.50 2009-10-25 Full functionality, up to 144x144.
+ ASCII and compressed digit encoding only.
+'''
+
+import inkex, simplestyle
+
+import gettext
+_ = gettext.gettext
+
+#ENCODING ROUTINES ===================================================
+# Take an input string and convert it to a sequence (or sequences)
+# of codewords as specified in ISO/IEC 16022:2006 (section 5.2.3)
+#=====================================================================
+
+#create a 2d list corresponding to the 1's and 0s of the DataMatrix
+def encode(text, (nrow, ncol) ):
+ #retreive the parameters of this size of DataMatrix
+ data_nrow, data_ncol, reg_row, reg_col, nd, nc, inter = get_parameters( nrow, ncol )
+
+ if not ((nrow == 144) and (ncol == 144)): #we have a regular datamatrix
+ size144 = False
+ else: #special handling will be required by get_codewords()
+ size144 = True
+
+ #generate the codewords including padding and ECC
+ codewords = get_codewords( text, nd, nc, inter, size144 )
+
+ # break up into separate arrays if more than one DataMatrix is needed
+ module_arrays = []
+ for codeword_stream in codewords: #for each datamatrix
+ bit_array = place_bits(codeword_stream, (data_nrow*reg_row, data_ncol*reg_col)) #place the codewords' bits across the array as modules
+ module_arrays.append(add_finder_pattern( bit_array, data_nrow, data_ncol, reg_row, reg_col )) #add finder patterns around the modules
+
+ return module_arrays
+
+#return parameters for the selected datamatrix size
+# data_nrow number of rows in each data region
+# data_ncol number of cols in each data region
+# reg_row number of rows of data regions
+# reg_col number of cols of data regions
+# nd number of data codewords per reed-solomon block
+# nc number of ECC codewords per reed-solomon block
+# inter number of interleaved Reed-Solomon blocks
+def get_parameters(nrow, ncol):
+
+ #SQUARE SYMBOLS
+ if ( nrow == 10 and ncol == 10 ):
+ return 8, 8, 1, 1, 3, 5, 1
+ elif ( nrow == 12 and ncol == 12 ):
+ return 10, 10, 1, 1, 5, 7, 1
+ elif ( nrow == 14 and ncol == 14 ):
+ return 12, 12, 1, 1, 8, 10, 1
+ elif ( nrow == 16 and ncol == 16 ):
+ return 14, 14, 1, 1, 12, 12, 1
+ elif ( nrow == 18 and ncol == 18 ):
+ return 16, 16, 1, 1, 18, 14, 1
+ elif ( nrow == 20 and ncol == 20 ):
+ return 18, 18, 1, 1, 22, 18, 1
+ elif ( nrow == 22 and ncol == 22 ):
+ return 18, 18, 1, 1, 30, 20, 1
+ elif ( nrow == 24 and ncol == 24 ):
+ return 22, 22, 1, 1, 36, 24, 1
+ elif ( nrow == 26 and ncol == 26 ):
+ return 24, 24, 1, 1, 44, 28, 1
+ elif ( nrow == 32 and ncol == 32 ):
+ return 14, 14, 2, 2, 62, 36, 1
+ elif ( nrow == 36 and ncol == 36 ):
+ return 16, 16, 2, 2, 86, 42, 1
+ elif ( nrow == 40 and ncol == 40):
+ return 18, 18, 2, 2, 114, 48, 1
+ elif ( nrow == 44 and ncol == 44):
+ return 20, 20, 2, 2, 144, 56, 1
+ elif ( nrow == 48 and ncol == 48 ):
+ return 22, 22, 2, 2, 174, 68, 1
+
+ elif ( nrow == 52 and ncol == 52 ):
+ return 24, 24, 2, 2, 102, 42, 2
+ elif ( nrow == 64 and ncol == 64 ):
+ return 16, 16, 4, 4, 140, 56, 2
+
+ elif ( nrow == 72 and ncol == 72 ):
+ return 16, 16, 4, 4, 92, 36, 4
+ elif ( nrow == 80 and ncol == 80 ):
+ return 18, 18, 4, 4, 114, 48, 4
+ elif ( nrow == 88 and ncol == 88 ):
+ return 20, 20, 4, 4, 144, 56, 4
+ elif ( nrow == 96 and ncol == 96 ):
+ return 22, 22, 4, 4, 174, 68, 4
+
+ elif ( nrow == 104 and ncol == 104 ):
+ return 24, 24, 4, 4, 136, 56, 6
+ elif ( nrow == 120 and ncol == 120):
+ return 18, 18, 6, 6, 175, 68, 6
+
+ elif ( nrow == 132 and ncol == 132):
+ return 20, 20, 6, 6, 163, 62, 8
+
+ elif (nrow == 144 and ncol == 144):
+ return 22, 22, 6, 6, 0, 0, 0 #there are two separate sections of the data matrix with
+ #different interleaving and reed-solomon parameters.
+ #this will be handled separately
+
+ #RECTANGULAR SYMBOLS
+ elif ( nrow == 8 and ncol == 18 ):
+ return 6, 16, 1, 1, 5, 7, 1
+ elif ( nrow == 8 and ncol == 32 ):
+ return 6, 14, 1, 2, 10, 11, 1
+ elif ( nrow == 12 and ncol == 26 ):
+ return 10, 24, 1, 1, 16, 14, 1
+ elif ( nrow == 12 and ncol == 36 ):
+ return 10, 16, 1, 2, 22, 18, 1
+ elif ( nrow == 16 and ncol == 36 ):
+ return 14, 16, 1, 2, 32, 24, 1
+ elif ( nrow == 16 and ncol == 48 ):
+ return 14, 22, 1, 2, 49, 28, 1
+
+ #RETURN ERROR
+ else:
+ inkex.errormsg(_('Unrecognised DataMatrix size'))
+
+ return None
+
+# CODEWORD STREAM GENERATION =========================================
+#take the text input and return the codewords,
+#including the Reed-Solomon error-correcting codes.
+#=====================================================================
+
+def get_codewords( text, nd, nc, inter, size144 ):
+ #convert the data to the codewords
+ data = encode_to_ascii( text )
+
+ if not size144: #render a "normal" datamatrix
+ data_blocks = partition_data(data, nd*inter) #partition into data blocks of length nd*inter -> inter Reed-Solomon block
+
+ data_blocks = interleave( data_blocks, inter) # interleave consecutive inter blocks if required
+
+ data_blocks = reed_solomon(data_blocks, nd, nc) #generate and append the Reed-Solomon codewords
+
+ data_blocks = combine_interleaved(data_blocks, inter, nd, nc, False) #concatenate Reed-Solomon blocks bound for the same datamatrix
+
+ else: #we have a 144x144 datamatrix
+ data_blocks = partition_data(data, 1558) #partition the data into datamtrix-sized chunks (1558 =156*8 + 155*2 )
+
+ for i in range(len(data_blocks)): #for each datamtrix
+
+
+ inter = 8
+ nd = 156
+ nc = 62
+ block1 = data_blocks[i][0:156*8]
+ block1 = interleave( [block1], inter) # interleave into 8 blocks
+ block1 = reed_solomon(block1, nd, nc) #generate and append the Reed-Solomon codewords
+
+ inter = 2
+ nd = 155
+ nc = 62
+ block2 = data_blocks[i][156*8:]
+ block2 = interleave( [block2], inter) # interleave into 2 blocks
+ block2 = reed_solomon(block2, nd, nc) #generate and append the Reed-Solomon codewords
+
+ blocks = block1
+ blocks.extend(block2)
+
+ blocks = combine_interleaved(blocks, 10, nd, nc, True)
+
+ data_blocks[i] = blocks[0]
+
+
+ return data_blocks
+
+
+#Takes a codeword stream and splits up into "inter" blocks.
+#eg interleave( [1,2,3,4,5,6], 2 ) -> [1,3,5], [2,4,6]
+def interleave( blocks, inter):
+
+ if inter == 1: # if we don't have to interleave, just return the blocks
+ return blocks
+ else:
+ result = []
+ for block in blocks: #for each codeword block in the stream
+ block_length = len(block)/inter #length of each interleaved block
+ inter_blocks = [[0] * block_length for i in xrange(inter)] #the interleaved blocks
+
+ for i in range(block_length): #for each element in the interleaved blocks
+ for j in range(inter): #for each interleaved block
+ inter_blocks[j][i] = block[ i*inter + j ]
+
+ result.extend(inter_blocks) #add the interleaved blocks to the output
+
+ return result
+
+#Combine interleaved blocks into the groups for the same datamatrix
+#
+#e.g combine_interleaved( [[d1, d3, d5, e1, e3, e5], [d2, d4, d6, e2, e4, e6]], 2, 3, 3 )
+# --> [[d1, d2, d3, d4, d5, d6, e1, e2, e3, e4, e5, e6]]
+def combine_interleaved( blocks, inter, nd, nc, size144):
+ if inter == 1: #the blocks aren't interleaved
+ return blocks
+ else:
+ result = []
+ for i in range( len(blocks) / inter ): #for each group of "inter" blocks -> one full datamatrix
+ data_codewords = [] #interleaved data blocks
+
+ if size144:
+ nd_range = 1558 #1558 = 156*8 + 155*2
+ nc_range = 620 #620 = 62*8 + 62*2
+ else:
+ nd_range = nd*inter
+ nc_range = nc*inter
+
+ for j in range(nd_range): #for each codeword in the final list
+ data_codewords.append( blocks[i*inter + j%inter][j/inter] )
+
+ for j in range(nc_range): #for each block, add the ecc codewords
+ data_codewords.append( blocks[i*inter + j%inter][nd + j/inter] )
+
+ result.append(data_codewords)
+ return result
+
+#checks if an ASCII character is a digit from 0 - 9
+def is_digit( char ):
+
+ if ord(char) >= 48 and ord(char) <= 57:
+ return True
+ else:
+ return False
+
+def encode_to_ascii( text):
+
+ ascii = []
+ i = 0
+ while i < len(text):
+ #check for double digits
+ if is_digit( text[i] ) and ( i < len(text)-1) and is_digit( text[i+1] ): #if the next char is also a digit
+
+ codeword = int( text[i] + text[i+1] ) + 130
+ ascii.append( codeword )
+ i = i + 2 #move on 2 characters
+ else: #encode as a normal ascii,
+ ascii.append( ord(text[i] ) + 1 ) #codeword is ASCII value + 1 (ISO 16022:2006 5.2.3)
+ i = i + 1 #next character
+
+ return ascii
+
+
+#partition data into blocks of the appropriate size to suit the
+#Reed-Solomon block being used.
+#e.g. partition_data([1,2,3,4,5], 3) -> [[1,2,3],[4,5,PAD]]
+def partition_data( data , rs_data):
+
+ PAD_VAL = 129 # PAD codeword (ISO 16022:2006 5.2.3)
+ data_blocks = []
+ i = 0
+ while i < len(data):
+ if len(data) >= i+rs_data: #we have a whole block in our data
+ data_blocks.append( data[i:i+rs_data] )
+ i = i + rs_data
+ else: #pad out with the pad codeword
+ data_block = data[i:len(data)] #add any remaining data
+ pad_pos = len(data)
+ padded = False
+ while len(data_block) < rs_data:#and then pad with randomised pad codewords
+ if not padded:
+ data_block.append( PAD_VAL ) #add a normal pad codeword
+ padded = True
+ else:
+ data_block.append( randomise_pad_253( PAD_VAL, pad_pos) )
+ pad_pos = pad_pos + 1
+ data_blocks.append( data_block)
+ break
+
+ return data_blocks
+
+#Pad character randomisation, to prevent regular patterns appearing
+#in the data matrix
+def randomise_pad_253(pad_value, pad_position ):
+ pseudo_random_number = ( ( 149 * pad_position ) % 253 )+ 1
+ randomised = pad_value + pseudo_random_number
+ if ( randomised <= 254 ):
+ return randomised
+ else:
+ return randomised - 254
+
+# REED-SOLOMON ENCODING ROUTINES =====================================
+
+# "prod(x,y,log,alog,gf)" returns the product "x" times "y"
+def prod(x, y, log, alog, gf):
+
+ if ( x==0 or y==0):
+ return 0
+ else:
+ result = alog[ ( log[x] + log[y] ) % (gf - 1) ]
+ return result
+
+# generate the log & antilog lists:
+def gen_log_alog(gf, pp):
+ log = [0]*gf
+ alog = [0]*gf
+
+ log[0] = 1-gf
+ alog[0] = 1
+
+ for i in range(1,gf):
+ alog[i] = alog[i-1] * 2
+
+ if (alog[i] >= gf):
+ alog[i] = alog[i] ^ pp
+
+ log[alog[i]] = i
+
+ return log, alog
+
+# generate the generator polynomial coefficients:
+def gen_poly_coeffs(nc, log, alog, gf):
+ c = [0] * (nc+1)
+ c[0] = 1
+
+ for i in range(1,nc+1):
+ c[i] = c[i-1]
+
+ j = i-1
+ while j >= 1:
+ c[j] = c[j-1] ^ prod(c[j],alog[i],log,alog,gf)
+ j = j - 1
+
+ c[0] = prod(c[0],alog[i],log,alog,gf)
+
+ return c
+
+# "ReedSolomon(wd,nd,nc)" takes "nd" data codeword values in wd[]
+# and adds on "nc" check codewords, all within GF(gf) where "gf" is a
+# power of 2 and "pp" is the value of its prime modulus polynomial */
+def reed_solomon(data, nd, nc):
+ #parameters of the polynomial arithmetic
+ gf = 256 #operating on 8-bit codewords -> Galois field = 2^8 = 256
+ pp = 301 #prime modulus polynomial for ECC-200 is 0b100101101 = 301 (ISO 16022:2006 5.7.1)
+
+ log, alog = gen_log_alog(gf,pp)
+ c = gen_poly_coeffs(nc, log, alog, gf)
+
+ for block in data: #for each block of data codewords
+
+ block.extend( [0]*(nc+1) ) #extend to make space for the error codewords
+
+ #generate "nc" checkwords in the list block
+ for i in range(0, nd):
+ k = block[nd] ^ block[i]
+
+ for j in range(0,nc):
+ block[nd+j] = block[nd+j+1] ^ prod(k,c[nc-j-1],log, alog,gf)
+
+ block.pop()
+
+ return data
+
+#MODULE PLACEMENT ROUTINES===========================================
+# These routines take a steam of codewords, and place them into the
+# DataMatrix in accordance with Annex F of BS ISO/IEC 16022:2006
+
+# bit() returns the bit'th bit of the byte
+def bit(byte, bit):
+ #the MSB is bit 1, LSB is bit 8
+ return ( byte >> (8-bit) ) %2
+
+# "module" places a given bit with appropriate wrapping within array
+def module(array, nrow, ncol, row, col, bit) :
+ if (row < 0) :
+ row = row + nrow
+ col = col + 4 - ((nrow+4)%8)
+
+ if (col < 0):
+ col = col + ncol
+ row = row + 4 - ((ncol+4)%8)
+
+ array[row][col] = bit
+
+def corner1(array, nrow, ncol, char):
+ module(array, nrow, ncol, nrow-1, 0, bit(char,1));
+ module(array, nrow, ncol, nrow-1, 1, bit(char,2));
+ module(array, nrow, ncol, nrow-1, 2, bit(char,3));
+ module(array, nrow, ncol, 0, ncol-2, bit(char,4));
+ module(array, nrow, ncol, 0, ncol-1, bit(char,5));
+ module(array, nrow, ncol, 1, ncol-1, bit(char,6));
+ module(array, nrow, ncol, 2, ncol-1, bit(char,7));
+ module(array, nrow, ncol, 3, ncol-1, bit(char,8));
+
+def corner2(array, nrow, ncol, char):
+ module(array, nrow, ncol, nrow-3, 0, bit(char,1));
+ module(array, nrow, ncol, nrow-2, 0, bit(char,2));
+ module(array, nrow, ncol, nrow-1, 0, bit(char,3));
+ module(array, nrow, ncol, 0, ncol-4, bit(char,4));
+ module(array, nrow, ncol, 0, ncol-3, bit(char,5));
+ module(array, nrow, ncol, 0, ncol-2, bit(char,6));
+ module(array, nrow, ncol, 0, ncol-1, bit(char,7));
+ module(array, nrow, ncol, 1, ncol-1, bit(char,8));
+
+def corner3(array, nrow, ncol, char):
+ module(array, nrow, ncol, nrow-3, 0, bit(char,1));
+ module(array, nrow, ncol, nrow-2, 0, bit(char,2));
+ module(array, nrow, ncol, nrow-1, 0, bit(char,3));
+ module(array, nrow, ncol, 0, ncol-2, bit(char,4));
+ module(array, nrow, ncol, 0, ncol-1, bit(char,5));
+ module(array, nrow, ncol, 1, ncol-1, bit(char,6));
+ module(array, nrow, ncol, 2, ncol-1, bit(char,7));
+ module(array, nrow, ncol, 3, ncol-1, bit(char,8));
+
+def corner4(array, nrow, ncol, char):
+ module(array, nrow, ncol, nrow-1, 0, bit(char,1));
+ module(array, nrow, ncol, nrow-1, ncol-1, bit(char,2));
+ module(array, nrow, ncol, 0, ncol-3, bit(char,3));
+ module(array, nrow, ncol, 0, ncol-2, bit(char,4));
+ module(array, nrow, ncol, 0, ncol-1, bit(char,5));
+ module(array, nrow, ncol, 1, ncol-3, bit(char,6));
+ module(array, nrow, ncol, 1, ncol-2, bit(char,7));
+ module(array, nrow, ncol, 1, ncol-1, bit(char,8));
+
+#"utah" places the 8 bits of a utah-shaped symbol character in ECC200
+def utah(array, nrow, ncol, row, col, char):
+ module(array, nrow, ncol,row-2, col-2, bit(char,1))
+ module(array, nrow, ncol,row-2, col-1, bit(char,2))
+ module(array, nrow, ncol,row-1, col-2, bit(char,3))
+ module(array, nrow, ncol,row-1, col-1, bit(char,4))
+ module(array, nrow, ncol,row-1, col, bit(char,5))
+ module(array, nrow, ncol,row, col-2, bit(char,6))
+ module(array, nrow, ncol,row, col-1, bit(char,7))
+ module(array, nrow, ncol,row, col, bit(char,8))
+
+#"place_bits" fills an nrow x ncol array with the bits from the
+# codewords in data.
+def place_bits(data, (nrow, ncol)):
+# First, fill the array[] with invalid entries */
+ INVALID = 2
+ array = [[INVALID] * ncol for i in xrange(nrow)] #initialise and fill with -1's (invalid value)
+# Starting in the correct location for character #1, bit 8,...
+ char = 0
+ row = 4
+ col = 0
+ while True:
+
+ #first check for one of the special corner cases, then...
+ if ((row == nrow) and (col == 0)):
+ corner1(array, nrow, ncol, data[char])
+ char = char + 1
+ if ((row == nrow-2) and (col == 0) and (ncol%4)) :
+ corner2(array, nrow, ncol, data[char])
+ char = char + 1
+ if ((row == nrow-2) and (col == 0) and (ncol%8 == 4)):
+ corner3(array, nrow, ncol, data[char])
+ char = char + 1
+ if ((row == nrow+4) and (col == 2) and ((ncol%8) == 0)):
+ corner4(array, nrow, ncol, data[char])
+ char = char + 1
+
+ #sweep upward diagonally, inserting successive characters,...
+ while True:
+ if ((row < nrow) and (col >= 0) and (array[row][col] == INVALID)) :
+ utah(array, nrow, ncol,row,col,data[char])
+ char = char+1
+ row = row - 2
+ col = col + 2
+
+ if not((row >= 0) and (col < ncol)):
+ break
+
+ row = row + 1
+ col = col + 3
+
+ # & then sweep downward diagonally, inserting successive characters,...
+ while True:
+ if ((row >= 0) and (col < ncol) and (array[row][col] == INVALID)) :
+ utah(array, nrow, ncol,row,col,data[char])
+ char = char + 1
+ row = row + 2
+ col = col - 2
+
+ if not((row < nrow) and (col >= 0)):
+ break
+
+ row = row + 3
+ col = col + 1
+
+ #... until the entire array is scanned
+ if not((row < nrow) or (col < ncol)):
+ break
+
+ # Lastly, if the lower righthand corner is untouched, fill in fixed pattern */
+ if (array[nrow-1][ncol-1] == INVALID):
+ array[nrow-1][ncol-2] = 0
+ array[nrow-1][ncol-1] = 1
+ array[nrow-2][ncol-1] = 0
+ array[nrow-2][ncol-2] = 1
+
+ return array #return the array of 1's and 0's
+
+
+def add_finder_pattern( array, data_nrow, data_ncol, reg_row, reg_col ):
+
+ #get the total size of the datamatrix
+ nrow = (data_nrow+2) * reg_row
+ ncol = (data_ncol+2) * reg_col
+
+ datamatrix = [[0] * ncol for i in xrange(nrow)] #initialise and fill with 0's
+
+ for i in range( reg_col ): #for each column of data regions
+ for j in range(nrow):
+ datamatrix[j][i*(data_ncol+2)] = 1 #vertical black bar on left
+ datamatrix[j][i*(data_ncol+2)+data_ncol+1] = (j)%2 # alternating blocks
+
+ for i in range( reg_row): # for each row of data regions
+ for j in range(ncol):
+ datamatrix[i*(data_nrow+2)+data_nrow+1][j] = 1 #horizontal black bar at bottom
+ datamatrix[i*(data_nrow+2)][j] = (j+1)%2 # alternating blocks
+
+ for i in range( data_nrow*reg_row ):
+ for j in range( data_ncol* reg_col ):
+ dest_col = j + 1 + 2*(j/(data_ncol)) #offset by 1, plus two for every addition block
+ dest_row = i + 1 + 2*(i/(data_nrow))
+
+ datamatrix[dest_row][dest_col] = array[i][j] #transfer from the plain bit array
+
+ return datamatrix
+
+#RENDERING ROUTINES ==================================================
+# Take the array of 1's and 0's and render as a series of black
+# squares. A binary 1 is a filled square
+#=====================================================================
+
+#SVG element generation routine
+def draw_SVG_square((w,h), (x,y), parent):
+
+ style = { 'stroke' : 'none',
+ 'width' : '1',
+ 'fill' : '#000000'
+ }
+
+ attribs = {
+ 'style' :simplestyle.formatStyle(style),
+ 'height' : str(h),
+ 'width' : str(w),
+ 'x' : str(x),
+ 'y' : str(y)
+ }
+ circ = inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), attribs )
+
+#turn a 2D array of 1's and 0's into a set of black squares
+def render_data_matrix( module_arrays, size, spacing, parent):
+
+ for i in range(len(module_arrays)): #for each data matrix
+
+ height = len(module_arrays[i])
+ width = len(module_arrays[i][0] )
+
+ for y in range(height): #loop over all the modules in the datamatrix
+ for x in range(width):
+
+ if module_arrays[i][y][x] == 1: #A binary 1 is a filled square
+ draw_SVG_square((size,size), (x*size + i*spacing,y*size), parent)
+ elif module_arrays[i][y][x] != 0: #we have an invalid bit value
+ inkex.errormsg(_('Invalid bit value, this is a bug!'))
+
+class DataMatrix(inkex.Effect):
+ def __init__(self):
+ inkex.Effect.__init__(self)
+
+ #PARSE OPTIONS
+ self.OptionParser.add_option("--text",
+ action="store", type="string",
+ dest="TEXT", default='Inkscape')
+ self.OptionParser.add_option("--rows",
+ action="store", type="int",
+ dest="ROWS", default=10)
+ self.OptionParser.add_option("--cols",
+ action="store", type="int",
+ dest="COLS", default=10)
+ self.OptionParser.add_option("--size",
+ action="store", type="int",
+ dest="SIZE", default=4)
+
+ def effect(self):
+
+ so = self.options
+
+ if so.TEXT == '': #abort if converting blank text
+ inkex.errormsg(_('Please enter an input string'))
+ else:
+
+ #INKSCAPE GROUP TO CONTAIN EVERYTHING
+
+ centre = self.view_center #Put in in the centre of the current view
+ grp_transform = 'translate' + str( centre )
+ grp_name = 'DataMatrix'
+ grp_attribs = {inkex.addNS('label','inkscape'):grp_name,
+ 'transform':grp_transform }
+ grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs)#the group to put everything in
+
+ #GENERATE THE DATAMATRIX
+ encoded = encode( so.TEXT, (so.ROWS, so.COLS) ) #get the pattern of squares
+ render_data_matrix( encoded, so.SIZE, so.COLS*so.SIZE*1.5, grp ) # generate the SVG elements
+
+if __name__ == '__main__':
+ e = DataMatrix()
+ e.affect()
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
diff --git a/share/extensions/wireframe_sphere.inx b/share/extensions/wireframe_sphere.inx
new file mode 100644
index 000000000..733ba8e11
--- /dev/null
+++ b/share/extensions/wireframe_sphere.inx
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
+ <_name>Wireframe Sphere</_name>
+ <id>il.wireframesphere</id>
+ <dependency type="executable" location="extensions">wireframe_sphere.py</dependency>
+ <dependency type="executable" location="extensions">inkex.py</dependency>
+ <dependency type="executable" location="extensions">simplestyle.py</dependency>
+ <dependency type="executable" location="extensions">simpletransform.py</dependency>
+ <param name="num_lat" type="int" min="0" max="1000" _gui-text="Lines of latitude">19</param>
+ <param name="num_long" type="int" min="0" max="1000" _gui-text="Lines of longitude">24</param>
+ <param name="tilt" type="float" min="-90" max="90" _gui-text="Tilt [deg]">35</param>
+ <param name="rotation" type="float" min="0" max="360" _gui-text="Rotation [deg]">4</param>
+ <param name="radius" type="float" min="1" max="1000" _gui-text="Radius [px]">100.0</param>
+ <param name="hide_back" type="boolean" _gui-text="Hide lines behind the sphere">false</param>
+ <effect>
+ <object-type>all</object-type>
+ <effects-menu>
+ <submenu _name="Render"/>
+ </effects-menu>
+ </effect>
+ <script>
+ <command reldir="extensions" interpreter="python">wireframe_sphere.py</command>
+ </script>
+</inkscape-extension>
diff --git a/share/extensions/wireframe_sphere.py b/share/extensions/wireframe_sphere.py
new file mode 100644
index 000000000..ec7e9ea33
--- /dev/null
+++ b/share/extensions/wireframe_sphere.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+'''
+Copyright (C) 2009 John Beard john.j.beard@gmail.com
+
+######DESCRIPTION######
+
+This extension renders a wireframe sphere constructed from lines of latitude
+and lines of longitude.
+
+The number of lines of latitude and longitude is independently variable. Lines
+of latitude and longtude are in separate subgroups. The whole figure is also in
+its own group.
+
+The whole sphere can be tilted towards or away from the veiwer by a given
+number of degrees. If the whole sphere is then rotated normally in Inkscape,
+any position can be acheived.
+
+There is an option to hide the lines at the back of the sphere, as if the
+sphere were opaque.
+ #FIXME: Lines of latitude only have an approximation of the function needed
+ to hide the back portion. If you can derive the proper equation,
+ please add it in.
+ Line of longitude have the exact method already.
+ Workaround: Use the Inkscape ellipse tool to edit the start and end
+ points of the lines of latitude to end at the horizon circle.
+
+
+#TODO: Add support for odd numbers of lines of longitude. This means breaking
+ the line at the poles, and having two half ellipses for each line.
+ The angles at which the ellipse arcs pass the poles are not constant and
+ need to be derived before this can be implemented.
+#TODO: Add support for prolate and oblate spheroids
+
+######LICENCE#######
+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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+######VERSION HISTORY#####
+ Ver. Date Notes
+
+ 0.10 2009-10-25 First version. Basic spheres supported.
+ Hidden lines of latitude still not properly calculated.
+ Prolate and oblate spheroids not considered.
+'''
+
+import inkex, simplestyle
+
+import gettext
+_ = gettext.gettext
+
+from math import *
+
+#SVG OUTPUT FUNCTIONS ================================================
+def draw_SVG_ellipse((rx, ry), (cx, cy), parent, start_end=(0,2*pi),transform='' ):
+
+ style = { 'stroke' : '#000000',
+ 'width' : '1',
+ 'fill' : 'none' }
+ circ_attribs = {'style':simplestyle.formatStyle(style),
+ inkex.addNS('cx','sodipodi') :str(cx),
+ inkex.addNS('cy','sodipodi') :str(cy),
+ inkex.addNS('rx','sodipodi') :str(rx),
+ inkex.addNS('ry','sodipodi') :str(ry),
+ inkex.addNS('start','sodipodi') :str(start_end[0]),
+ inkex.addNS('end','sodipodi') :str(start_end[1]),
+ inkex.addNS('open','sodipodi') :'true', #all ellipse sectors we will draw are open
+ inkex.addNS('type','sodipodi') :'arc',
+ 'transform' :transform
+
+ }
+ circ = inkex.etree.SubElement(parent, inkex.addNS('path','svg'), circ_attribs )
+
+class Wireframe_Sphere(inkex.Effect):
+ def __init__(self):
+ inkex.Effect.__init__(self)
+
+ #PARSE OPTIONS
+ self.OptionParser.add_option("--num_lat",
+ action="store", type="int",
+ dest="NUM_LAT", default=19)
+ self.OptionParser.add_option("--num_long",
+ action="store", type="int",
+ dest="NUM_LONG", default=24)
+ self.OptionParser.add_option("--radius",
+ action="store", type="float",
+ dest="RADIUS", default=100.0)
+ self.OptionParser.add_option("--tilt",
+ action="store", type="float",
+ dest="TILT", default=35.0)
+ self.OptionParser.add_option("--rotation",
+ action="store", type="float",
+ dest="ROT_OFFSET", default=4)
+ self.OptionParser.add_option("--hide_back",
+ action="store", type="inkbool",
+ dest="HIDE_BACK", default=False)
+
+ def effect(self):
+
+ so = self.options
+
+ #PARAMETER PROCESSING
+
+ if so.NUM_LONG % 2 != 0: #lines of longitude are odd : abort
+ inkex.errormsg(_('Please enter an even number of lines of longitude.'))
+ else:
+ if so.TILT < 0: # if the tilt is backwards
+ flip = ' scale(1, -1)' # apply a vertical flip to the whole sphere
+ else:
+ flip = '' #no flip
+
+ so.TILT = abs(so.TILT)*(pi/180) #Convert to radians
+ so.ROT_OFFSET = so.ROT_OFFSET*(pi/180) #Convert to radians
+
+ EPSILON = 0.001 #add a tiny value to the ellipse radii, so that if we get a zero radius, the ellipse still shows up as a line
+
+ #INKSCAPE GROUP TO CONTAIN EVERYTHING
+
+ centre = self.view_center #Put in in the centre of the current view
+ grp_transform = 'translate' + str( centre ) + flip
+ grp_name = 'WireframeSphere'
+ grp_attribs = {inkex.addNS('label','inkscape'):grp_name,
+ 'transform':grp_transform }
+ grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs)#the group to put everything in
+
+ #LINES OF LONGITUDE
+
+ if so.NUM_LONG > 0: #only process longitudes if we actually want some
+
+ #GROUP FOR THE LINES OF LONGITUDE
+ grp_name = 'Lines of Longitude'
+ grp_attribs = {inkex.addNS('label','inkscape'):grp_name}
+ grp_long = inkex.etree.SubElement(grp, 'g', grp_attribs)
+
+ delta_long = 360.0/so.NUM_LONG #angle between neighbouring lines of longitude in degrees
+
+ for i in range(0,so.NUM_LONG/2):
+ long_angle = so.ROT_OFFSET + (i*delta_long)*(pi/180.0); #The longitude of this particular line in radians
+ width = so.RADIUS * cos(long_angle)
+ height = so.RADIUS * sin(long_angle) * sin(so.TILT) #the rise is scaled by the sine of the tilt
+ length = sqrt(width*width+height*height) #by pythagorean theorem
+ inverse = sin(acos(length/so.RADIUS))
+
+ minorRad = so.RADIUS * inverse
+ minorRad=minorRad + EPSILON
+
+ #calculate the rotation of the ellipse to get it to pass through the pole (in degrees)
+ rotation = atan(height/width)*(180.0/pi)
+ transform = "rotate("+str(rotation)+')' #generate the transform string
+ #the rotation will be applied about the group centre (the centre of the sphere)
+
+ # remove the hidden side of the ellipses if required
+ # this is always exactly half the ellipse, but we need to find out which half
+ start_end = (0, 2*pi) #Default start and end angles -> full ellipse
+ if so.HIDE_BACK:
+ if long_angle <= pi/2: #cut out the half ellispse that is hidden
+ start_end = (pi/2, 3*pi/2)
+ else:
+ start_end = (3*pi/2, pi/2)
+
+ #finally, draw the line of longitude
+ #the centre is always at the centre of the sphere
+ draw_SVG_ellipse( ( minorRad, so.RADIUS ), (0,0), grp_long , start_end,transform)
+
+ # LINES OF LATITUDE
+ if so.NUM_LAT > 0:
+
+ #GROUP FOR THE LINES OF LATITUDE
+ grp_name = 'Lines of Latitude'
+ grp_attribs = {inkex.addNS('label','inkscape'):grp_name}
+ grp_lat = inkex.etree.SubElement(grp, 'g', grp_attribs)
+
+
+ so.NUM_LAT = so.NUM_LAT + 1 #Account for the fact that we loop over N-1 elements
+ delta_lat = 180.0/so.NUM_LAT #Angle between the line of latitude (subtended at the centre)
+
+ for i in range(1,so.NUM_LAT):
+ lat_angle=((delta_lat*i)*(pi/180)) #The angle of this line of latitude (from a pole)
+
+ majorRad=so.RADIUS*sin(lat_angle) #The width of the LoLat (no change due to projection)
+ minorRad=so.RADIUS*sin(lat_angle) * sin(so.TILT) #The projected height of the line of latitude
+ minorRad=minorRad + EPSILON
+
+ cy=so.RADIUS*cos(lat_angle) * cos(so.TILT) #The projected y position of the LoLat
+ cx=0 #The x position is just the center of the sphere
+
+ if so.HIDE_BACK:
+ if lat_angle > so.TILT: #this LoLat is partially or fully visible
+ if lat_angle > pi-so.TILT: #this LoLat is fully visible
+ draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat)
+ else: #this LoLat is partially visible
+
+ proportion = -(acos( (lat_angle - pi/2)/(pi/2 - so.TILT)) )/pi + 1 #this is a dirty hacky approximation
+ #FIXME: if you can work out the right way to do this, please do it
+ start_end = ( pi/2 - proportion*pi, pi/2 + proportion*pi ) #make the start and end angles (mirror image around pi/2)
+ draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat, start_end)
+
+ else: #just draw the full lines of latitude
+ draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat)
+
+
+ #THE HORIZON CIRCLE
+ draw_SVG_ellipse((so.RADIUS, so.RADIUS), (0,0), grp) #circle, centred on the sphere centre
+
+if __name__ == '__main__':
+ e = Wireframe_Sphere()
+ e.affect()
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
diff --git a/share/icons/Makefile.am b/share/icons/Makefile.am
index e39174833..59c55948d 100644
--- a/share/icons/Makefile.am
+++ b/share/icons/Makefile.am
@@ -1,6 +1,13 @@
+SUBDIRS = application
+
iconsdir = $(datadir)/inkscape/icons
pixmaps = \
+ too-much-ink-icon.png \
+ too-much-ink-icon.svg \
+ out-of-gamut-icon.png \
+ out-of-gamut-icon.svg \
+ color-management-icon.png \
remove-color.png \
remove-color.svg \
ticotico.jpg \
diff --git a/share/icons/application/16x16/Makefile.am b/share/icons/application/16x16/Makefile.am
new file mode 100644
index 000000000..a87c2cbfa
--- /dev/null
+++ b/share/icons/application/16x16/Makefile.am
@@ -0,0 +1,5 @@
+icondir = $(datadir)/icons/hicolor/16x16/apps
+icon_DATA = inkscape.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/share/icons/application/16x16/inkscape.png b/share/icons/application/16x16/inkscape.png
new file mode 100644
index 000000000..e4aed9222
--- /dev/null
+++ b/share/icons/application/16x16/inkscape.png
Binary files differ
diff --git a/share/icons/application/22x22/Makefile.am b/share/icons/application/22x22/Makefile.am
new file mode 100644
index 000000000..8beeed331
--- /dev/null
+++ b/share/icons/application/22x22/Makefile.am
@@ -0,0 +1,5 @@
+icondir = $(datadir)/icons/hicolor/22x22/apps
+icon_DATA = inkscape.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/share/icons/application/22x22/inkscape.png b/share/icons/application/22x22/inkscape.png
new file mode 100644
index 000000000..b1adda08c
--- /dev/null
+++ b/share/icons/application/22x22/inkscape.png
Binary files differ
diff --git a/share/icons/application/24x24/Makefile.am b/share/icons/application/24x24/Makefile.am
new file mode 100644
index 000000000..8fc9b59aa
--- /dev/null
+++ b/share/icons/application/24x24/Makefile.am
@@ -0,0 +1,5 @@
+icondir = $(datadir)/icons/hicolor/24x24/apps
+icon_DATA = inkscape.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/share/icons/application/24x24/inkscape.png b/share/icons/application/24x24/inkscape.png
new file mode 100644
index 000000000..4c2cded2c
--- /dev/null
+++ b/share/icons/application/24x24/inkscape.png
Binary files differ
diff --git a/share/icons/application/256x256/Makefile.am b/share/icons/application/256x256/Makefile.am
new file mode 100644
index 000000000..34969a4a9
--- /dev/null
+++ b/share/icons/application/256x256/Makefile.am
@@ -0,0 +1,5 @@
+icondir = $(datadir)/icons/hicolor/256x256/apps
+icon_DATA = inkscape.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/share/icons/application/256x256/inkscape.png b/share/icons/application/256x256/inkscape.png
new file mode 100644
index 000000000..76e07fb3d
--- /dev/null
+++ b/share/icons/application/256x256/inkscape.png
Binary files differ
diff --git a/share/icons/application/32x32/Makefile.am b/share/icons/application/32x32/Makefile.am
new file mode 100644
index 000000000..cdccebd02
--- /dev/null
+++ b/share/icons/application/32x32/Makefile.am
@@ -0,0 +1,5 @@
+icondir = $(datadir)/icons/hicolor/32x32/apps
+icon_DATA = inkscape.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/share/icons/application/32x32/inkscape.png b/share/icons/application/32x32/inkscape.png
new file mode 100644
index 000000000..aa445e4bc
--- /dev/null
+++ b/share/icons/application/32x32/inkscape.png
Binary files differ
diff --git a/share/icons/application/48x48/Makefile.am b/share/icons/application/48x48/Makefile.am
new file mode 100644
index 000000000..ffa5c1a55
--- /dev/null
+++ b/share/icons/application/48x48/Makefile.am
@@ -0,0 +1,5 @@
+icondir = $(datadir)/icons/hicolor/48x48/apps
+icon_DATA = inkscape.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/share/icons/application/48x48/inkscape.png b/share/icons/application/48x48/inkscape.png
new file mode 100644
index 000000000..668acfdef
--- /dev/null
+++ b/share/icons/application/48x48/inkscape.png
Binary files differ
diff --git a/share/icons/application/Makefile.am b/share/icons/application/Makefile.am
new file mode 100644
index 000000000..0e9bb7d7d
--- /dev/null
+++ b/share/icons/application/Makefile.am
@@ -0,0 +1,15 @@
+SUBDIRS = 16x16 22x22 24x24 32x32 48x48 256x256
+
+gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
+
+install-data-hook: update-icon-cache
+uninstall-hook: update-icon-cache
+
+update-icon-cache:
+ @-if test -z "$(DESTDIR)"; then \
+ echo "Updating Gtk icon cache."; \
+ $(gtk_update_icon_cache); \
+ else \
+ echo "*** Icon cache not updated. After (un)install, run this:"; \
+ echo "*** $(gtk_update_icon_cache)"; \
+ fi
diff --git a/share/icons/color-management-icon.png b/share/icons/color-management-icon.png
new file mode 100644
index 000000000..469ccd72a
--- /dev/null
+++ b/share/icons/color-management-icon.png
Binary files differ
diff --git a/share/icons/out-of-gamut-icon.png b/share/icons/out-of-gamut-icon.png
new file mode 100644
index 000000000..1e96a9563
--- /dev/null
+++ b/share/icons/out-of-gamut-icon.png
Binary files differ
diff --git a/share/icons/out-of-gamut-icon.svg b/share/icons/out-of-gamut-icon.svg
new file mode 100644
index 000000000..4fb171139
--- /dev/null
+++ b/share/icons/out-of-gamut-icon.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="249.50522"
+ height="249.50523"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <g
+ transform="translate(-218.10454,-476.18098)"
+ id="layer1">
+ <path
+ d="m 462.85715,600.93359 c 0,66.27417 -53.72583,120 -120,120 -66.27417,0 -120,-53.72583 -120,-120 0,-66.27417 53.72583,-120 120,-120 66.27417,0 120,53.72583 120,120 z m 182.9912,0 c 0,167.33742 -135.65378,302.99121 -302.9912,302.99121 -167.33743,0 -302.991208,-135.65379 -302.991208,-302.99121 0,-167.33742 135.653778,-302.9912 302.991208,-302.9912 167.33742,0 302.9912,135.65378 302.9912,302.9912 z"
+ transform="matrix(0.3960511,0,0,0.3960511,207.0682,362.93318)"
+ id="path2818"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:24;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/share/icons/too-much-ink-icon.png b/share/icons/too-much-ink-icon.png
new file mode 100644
index 000000000..14fed033d
--- /dev/null
+++ b/share/icons/too-much-ink-icon.png
Binary files differ
diff --git a/share/icons/too-much-ink-icon.svg b/share/icons/too-much-ink-icon.svg
new file mode 100644
index 000000000..a2f688498
--- /dev/null
+++ b/share/icons/too-much-ink-icon.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="249.50522"
+ height="249.50523"
+ id="svg2"
+ inkscape:version="0.47+devel"
+ sodipodi:docname="too-much-ink-icon.svg"
+ inkscape:export-filename="/home/felipe/devel/bzr-inkscape/inkscape/share/icons/too-much-ink-icon.png"
+ inkscape:export-xdpi="5.6999998"
+ inkscape:export-ydpi="5.6999998">
+ <metadata
+ id="metadata8">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1024"
+ inkscape:window-height="693"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="0.33866729"
+ inkscape:cx="194.49558"
+ inkscape:cy="191.55723"
+ inkscape:window-x="0"
+ inkscape:window-y="25"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 124.75262 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="249.50522 : 124.75262 : 1"
+ inkscape:persp3d-origin="124.75261 : 83.168411 : 1"
+ id="perspective10" />
+ </defs>
+ <g
+ transform="translate(-218.10454,-476.18098)"
+ id="layer1" />
+ <path
+ id="path2988"
+ style="fill:#200e13;fill-opacity:0.96862745;fill-rule:evenodd;stroke:#20241d;stroke-width:5.49399996000000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 44.205845,53.627099 c 6.538205,8.776404 7.179182,14.929511 7.184639,20.799914 0.0043,4.681179 -10.770356,1.897693 -15.869168,-0.2132 -7.694024,-3.185304 -15.824487,-9.784438 -17.689511,-16.915388 -1.158352,-4.428985 0.749479,-10.229203 5.19903,-11.623732 6.495074,-2.035617 16.872258,2.176709 21.17501,7.952406 z M 30.008964,205.99522 c 9.10047,-17.44806 19.580437,-23.91826 30.209061,-29.20542 8.475488,-4.21608 14.636139,14.03423 16.113709,23.38441 2.229628,14.10927 -1.271148,31.92641 -12.249789,41.06491 -6.81876,5.67586 -19.309578,8.10365 -26.46219,2.85474 -10.440776,-7.6619 -13.599752,-26.61618 -7.610791,-38.09864 z M 173.64367,123.09593 c 1.4357,-39.91444 54.53677,19.12723 69.59235,-3.63891 8.93961,-13.51796 5.32456,-38.561425 -7.86464,-47.97932 -9.68684,-6.916994 -50.66722,5.557227 -60.7695,-0.737512 -18.8117,-11.721606 7.93318,-34.929939 -8.70266,-49.576607 -24.86167,-21.88894402 -44.62485,-21.29438502 -68.539321,1.625623 -15.178156,14.546991 10.871641,22.047341 3.192441,41.61827 -10.607154,27.033004 -39.063593,8.120474 -45.546174,36.427236 -4.104651,17.9233 1.357147,48.93421 19.081937,53.82552 13.316852,3.6749 13.818475,-22.5941 38.882527,-4.90635 25.06405,17.68776 4.4552,41.49178 10.10048,65.11007 5.64529,23.61827 22.84904,17.71636 35.42061,15.11786 15.97666,-3.30232 11.12595,-30.4217 33.70881,-33.39655 22.58287,-2.97487 16.69776,21.8648 41.58646,-0.63804 41.60195,-37.61392 -49.85797,-50.12848 -60.14333,-72.85127 l 10e-6,-2e-5 z" />
+</svg>