From bbefc771b039bfb9e6ad819a8e5f62256ed25a19 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Sun, 29 Nov 2009 13:42:45 +0100 Subject: Deprecation warning fix on xcf export Fixed bugs: - https://launchpad.net/bugs/485027 (bzr r8846) --- share/extensions/gimp_xcf.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'share/extensions') diff --git a/share/extensions/gimp_xcf.py b/share/extensions/gimp_xcf.py index 22e45006b..92da6cf40 100755 --- a/share/extensions/gimp_xcf.py +++ b/share/extensions/gimp_xcf.py @@ -19,6 +19,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import inkex import sys, os, tempfile +try: + from subprocess import Popen, PIPE + bsubprocess = True +except: + bsubprocess = False + class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) @@ -95,7 +101,13 @@ class MyEffect(inkex.Effect): name = "%s.png" % id filename = os.path.join(tmp_dir, name) command = "inkscape -i %s -j %s -e %s %s " % (id, area, filename, svg_file) - _,f,err = os.popen3(command,'r') + if bsubprocess: + p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) + return_code = p.wait() + f = p.stdout + err = p.stderr + else: + _,f,err = os.popen3(command,'r') f.read() f.close() err.close() -- cgit v1.2.3 From a2f98a2d2b6be3d2a5d666a92fb77f37e24b57b3 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Sun, 29 Nov 2009 20:20:07 +0100 Subject: Scour extension update Fixed bugs: - https://launchpad.net/bugs/453737 (bzr r8847) --- share/extensions/scour.inkscape.py | 53 ++++++++++++++++++++++++++++++++++---- share/extensions/scour.inx | 29 +++++++++++++++++++++ 2 files changed, 77 insertions(+), 5 deletions(-) (limited to 'share/extensions') diff --git a/share/extensions/scour.inkscape.py b/share/extensions/scour.inkscape.py index 531dfb46c..9e8775782 100755 --- a/share/extensions/scour.inkscape.py +++ b/share/extensions/scour.inkscape.py @@ -1,8 +1,51 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys +import sys, inkex from scour import scourString -input = file(sys.argv[1], "r") -sys.stdout.write(scourString(input.read()).encode("UTF-8")) -input.close() -sys.stdout.close() + +class ScourInkscape (inkex.Effect): + + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab") + self.OptionParser.add_option("--simplify-colors", type="inkbool", + action="store", dest="simple_colors", default=True, + help="won't convert all colors to #RRGGBB format") + self.OptionParser.add_option("--style-to-xml", type="inkbool", + action="store", dest="style_to_xml", default=True, + help="won't convert styles into XML attributes") + self.OptionParser.add_option("--group-collapsing", type="inkbool", + action="store", dest="group_collapse", default=True, + help="won't collapse elements") + self.OptionParser.add_option("--enable-id-stripping", type="inkbool", + action="store", dest="strip_ids", default=False, + help="remove all un-referenced ID attributes") + self.OptionParser.add_option("--embed-rasters", type="inkbool", + action="store", dest="embed_rasters", default=True, + help="won't embed rasters as base64-encoded data") + self.OptionParser.add_option("--keep-editor-data", type="inkbool", + action="store", dest="keep_editor_data", default=False, + help="won't remove Inkscape, Sodipodi or Adobe Illustrator elements and attributes") + self.OptionParser.add_option("--strip-xml-prolog", type="inkbool", + action="store", dest="strip_xml_prolog", default=False, + help="won't output the prolog") + self.OptionParser.add_option("-p", "--set-precision", + action="store", type=int, dest="digits", default=5, + help="set number of significant digits (default: %default)") + self.OptionParser.add_option("--indent", + action="store", type="string", dest="indent_type", default="space", + help="indentation of the output: none, space, tab (default: %default)") + + + def effect(self): + input = file(sys.argv[11], "r") + sys.stdout.write(scourString(input.read(), self.options).encode("UTF-8")) + input.close() + sys.stdout.close() + + +if __name__ == '__main__': + e = ScourInkscape() + e.affect(output=False) diff --git a/share/extensions/scour.inx b/share/extensions/scour.inx index 57884b6aa..d5cddeea5 100644 --- a/share/extensions/scour.inx +++ b/share/extensions/scour.inx @@ -5,6 +5,35 @@ scour.py svg_regex.py yocto_css.py + + + true + true + true + false + true + false + false + 5 + + <_item value="space">Space + <_item value="tab">Tab + <_item value="none">None + + + + <_param name="instructions" type="description" xml:space="preserve">This extension optimize the SVG file according to the following options: + * Simplify colors: convert all colors to #RRGGBB format. + * Style to xml: convert styles into XML attributes. + * Group collapsing: collapse <g> elements. + * Enable id stripping: remove all un-referenced ID attributes. + * Embed rasters: embed rasters as base64-encoded data. + * Keep editor data: don't remove Inkscape, Sodipodi or Adobe Illustrator elements and attributes. + * Strip xml prolog: don't output the xml prolog. + * Set precision: set number of significant digits (default: 5). + * Indent: indentation of the output: none, space, tab (default: space). + + .svg image/svg+xml -- cgit v1.2.3 From 77163369317023d0442f835f04d75ea27fd9e58d Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Thu, 3 Dec 2009 16:13:26 +0100 Subject: New conversion factors added to inkex.py (ft, yd, m and km). Measure path extension now uses inkex.py conversion factors. (bzr r8860) --- share/extensions/inkex.py | 3 ++- share/extensions/measure.py | 23 +---------------------- 2 files changed, 3 insertions(+), 23 deletions(-) (limited to 'share/extensions') diff --git a/share/extensions/inkex.py b/share/extensions/inkex.py index b7e3e0e63..d36820692 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())) 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) -- cgit v1.2.3 From 6be0b6d268b123d715186bf8eb927e1be6e7e096 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 16 Dec 2009 21:31:01 +0100 Subject: Embedimage extension fix and stderr Unicode support in inkex.py Fixed bugs: - https://launchpad.net/bugs/386069 (bzr r8890) --- share/extensions/embedimage.py | 7 ++++--- share/extensions/inkex.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'share/extensions') 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 d36820692..1a70c25d6 100755 --- a/share/extensions/inkex.py +++ b/share/extensions/inkex.py @@ -84,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': -- cgit v1.2.3 From a19a8eab4a74ded5007a23c3edff81ff2839b42c Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sat, 19 Dec 2009 08:45:36 -0500 Subject: modify exit message if non-Ascii characters Fixed bugs: - https://launchpad.net/bugs/424162 (bzr r8894) --- share/extensions/render_alphabetsoup.py | 924 ++++++++++++++++---------------- 1 file changed, 463 insertions(+), 461 deletions(-) (limited to 'share/extensions') 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() + -- cgit v1.2.3 From fca8f5e6291c1a65964ade431ec3a88f29dd309e Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sun, 20 Dec 2009 17:09:40 -0500 Subject: patch by mbeach for UPC-A checksum Fixed bugs: - https://launchpad.net/bugs/301129 (bzr r8897) --- share/extensions/Barcode/EAN13.py | 10 +++++----- share/extensions/Barcode/UPCA.py | 4 ++-- share/extensions/Barcode/UPCE.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'share/extensions') 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/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) -- cgit v1.2.3