render_alphabetsoup.py revision 55409b97452fc42cc6fbb542da79ab133ed705b3
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoCopyright (C) 2001-2002 Matt Chisholm matt@theory.org
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoCopyright (C) 2008 Joel Holdsworth joel@airwebreathe.org.uk
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoThis program is free software; you can redistribute it and/or modify
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoit under the terms of the GNU General Public License as published by
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicothe Free Software Foundation; either version 2 of the License, or
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico(at your option) any later version.
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoThis program is distributed in the hope that it will be useful,
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicobut WITHOUT ANY WARRANTY; without even the implied warranty of
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoGNU General Public License for more details.
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoYou should have received a copy of the GNU General Public License
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoalong with this program; if not, write to the Free Software
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicoFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico# Loads a super-path from a given SVG file
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico os.path.join( os.getcwd(), os.path.dirname(__file__) )
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # __file__ is better then sys.argv[0] because this file may be a module
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # for another one.
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico tree = inkex.etree.parse( extensionDir + "/" + svgPath )
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico pathElement = root.find('{http://www.w3.org/2000/svg}path')
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico return simplepath.parsePath(d), width, height # Currently we only support a single path
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico elif pathA == None:
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico elif pathB == None:
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico else: # complex roots
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico a, b, c, d = 1, b/float(a), c/float(a), d/float(a) # Divide through by a
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico else: # Complex Real Root
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico return [y1 - t]
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico elif b != 0:
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico return [(-c + math.sqrt(det))/(2.0*b),(-c - math.sqrt(det))/(2.0*b)]
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico elif c != 0:
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico return [-d/c]
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # A move cannot contribute to the bounding box
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico segmentBox = (min(params[4], last[0]), max(params[4], last[0]), min(params[5], last[1]), max(params[5], last[1]))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # Compute the x limits
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico segmentBox = (min(segmentBox[0], x), max(segmentBox[1], x), segmentBox[2], segmentBox[3])
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # Compute the y limits
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico segmentBox = (segmentBox[0], segmentBox[1], min(segmentBox[2], y), max(segmentBox[3], y))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # Provisional
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # Provisional
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico box = (min(segmentBox[0],box[0]), max(segmentBox[1],box[1]), min(segmentBox[2],box[2]), max(segmentBox[3],box[3]))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef mxfm( image, width, height, stack ): # returns possibly transformed image
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef comparerule( rule, nodes ): # compare node list to nodes in rule
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico for i in range( 0, len(nodes)): # range( a, b ) = (a, a+1, a+2 ... b-2, b-1)
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico else: return 0
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef findrule( state, nodes ): # find the rule which generated this subtree
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if ((rulelen == nodelen) and (comparerule( rule, nodes ))):
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef generate( state ): # generate a random tree (in stack form)
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if ( len(syntax[state]) == 1 ): # if this is a stop symbol
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico path = random.randint(0, (len(syntax[state][1])-1)) # choose randomly from next states
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico for symbol in syntax[state][1][path]: # recurse down each non-terminal
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if (symbol[3]):stack.append( "-" ) # top-bottom flip
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if (symbol[4]):stack.append( "|" ) # left-right flip
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #inkex.debug("found end of list in generate( state =", state, ")") # this should be deprecated/never happen
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef draw( stack ): # draw a character based on a tree stack
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #print state,
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico image, width, height = loadPath( font+syntax[state][0] ) # load the image
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if (len(syntax[state]) == 1): # this state is a terminal node
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico substack = generate( state ) # generate random substack
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #inkex.debug("[")
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico newimage, width, height = draw( stack ) # draw the daughter state
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico tfimage = mxfm( newimage, width, height, stack ) # maybe transform daughter state
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico images.append( [tfimage, width, height] ) # list of daughter images
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #inkex.debug(("recurse on",newstate,"failed")) # this should never happen
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico rule = findrule( state, nodes ) # find the rule for this subtree
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #box = getPathBoundingBox(currimg)
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef draw_crop_scale( stack, zoom ): # draw, crop and scale letter image
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico simplepath.scalePath(image, zoom/units, zoom/units)
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico return image, bbox[1] - bbox[0], bbox[3] - bbox[2]
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef randomize_input_string( str, zoom ): # generate list of images based on input string
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #if ( re.match("[a-zA-Z0-9?]", char)):
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if ((i > 0) and (char == str[i-1])): # if this letter matches previous letter
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico imagelist.append(imagelist[len(stack)-1])# make them the same image
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico else: # generate image for letter
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-1))] , "." )
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico #stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-2))] , "." )
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico elif( char == " "): # add a " " space to the image list
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico else: # this character is not in config.alphabet, skip it
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico inkex.errormsg(_("bad character") + " = 0x%x" % ord(char))
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef optikern( image, width, zoom ): # optical kerning algorithm
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # A move cannot contribute to the bounding box
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if (y >= last[1] and y <= params[1]) or (y >= params[1] and y <= last[1]):
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico x = (y - b) / a
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico else: x = None
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # Quadratic beziers are ignored
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # Arcs are ignored
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico left.append( xmin ) # distance from left edge of region to left edge of bbox
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico right.append( width - xmax ) # distance from right edge of region to right edge of bbox
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNicodef layoutstring( imagelist, zoom ): # layout string of letter-images using optical kerning
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if (entry == " "): # leaving room for " " space characters
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico length = length + (zoom * render_alphabetsoup_config.space)
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico length = length + width + zoom # add letter length to overall length
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico kernlist.append( optikern(image, width, zoom) ) # append kerning data for this image
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico position = position + (zoom * render_alphabetsoup_config.space )
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico # set the kerning
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico if i == 0: kern = 0 # for first image, kerning is zero
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico kerncompare.append( kernlist[i][0][j]+kernlist[i-1][1][j] )
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico position = position - kern # move position back by kern amount
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico position = position + width + zoom # advance position by letter width
55409b97452fc42cc6fbb542da79ab133ed705b3JazzyNico imagelist = randomize_input_string(self.options.text, zoom)