From: JazzyNico Date: Mon, 30 Aug 2010 11:29:57 +0000 (+0200) Subject: Extensions. Fix EOL inconsistencies (Bug #314381). X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=55409b97452fc42cc6fbb542da79ab133ed705b3;p=inkscape.git Extensions. Fix EOL inconsistencies (Bug #314381). --- diff --git a/share/extensions/aisvg.xslt b/share/extensions/aisvg.xslt index 62a10ee93..2faebc7f3 100644 --- a/share/extensions/aisvg.xslt +++ b/share/extensions/aisvg.xslt @@ -1,36 +1,36 @@ - - - - - - - - - - - - layer - - - - - - - - - - - - - - + + + + + + + + + + + + layer + + + + + + + + + + + + + + diff --git a/share/extensions/colors.xml b/share/extensions/colors.xml index d877113d7..51167fdd7 100644 --- a/share/extensions/colors.xml +++ b/share/extensions/colors.xml @@ -1,150 +1,150 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/share/extensions/convert2dashes.inx b/share/extensions/convert2dashes.inx index 9f3ff365e..1230ff2d8 100644 --- a/share/extensions/convert2dashes.inx +++ b/share/extensions/convert2dashes.inx @@ -1,16 +1,16 @@ - - - <_name>Convert to Dashes - com.vaxxine.filter.dashes - convert2dashes.py - inkex.py - - path - - - - - - + + + <_name>Convert to Dashes + com.vaxxine.filter.dashes + convert2dashes.py + inkex.py + + path + + + + + + diff --git a/share/extensions/guillotine.inx b/share/extensions/guillotine.inx index ba88f668c..6e2aa000e 100644 --- a/share/extensions/guillotine.inx +++ b/share/extensions/guillotine.inx @@ -1,26 +1,26 @@ - - - <_name>Guillotine - org.inkscape.guillotine - - org.inkscape.output.svg.inkscape - - guillotine.py - inkex.py - - ~/ - guillotined - false - - - all - - - - - - - - + + + <_name>Guillotine + org.inkscape.guillotine + + org.inkscape.output.svg.inkscape + + guillotine.py + inkex.py + + ~/ + guillotined + false + + + all + + + + + + + + diff --git a/share/extensions/guillotine.py b/share/extensions/guillotine.py index 7c43daa6d..f0e3f4aaa 100644 --- a/share/extensions/guillotine.py +++ b/share/extensions/guillotine.py @@ -1,248 +1,248 @@ -#!/usr/bin/env python -''' -guillotine.py - -Copyright (C) 2010 Craig Marshall, craig9 [at] gmail.com - -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 - ------------------------ - -This script slices an inkscape drawing along the guides, similarly to -the GIMP plugin called "guillotine". It can optionally export to the -same directory as the SVG file with the same name, but with a number -suffix. e.g. - -/home/foo/drawing.svg - -will export to: - -/home/foo/drawing0.png -/home/foo/drawing1.png -/home/foo/drawing2.png -/home/foo/drawing3.png - -etc. - -''' - -import os -import sys -import inkex -import simplestyle -import locale - -locale.setlocale(locale.LC_ALL, '') - -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False - -def float_sort(a, b): - ''' - This is used to sort the horizontal and vertical guide positions, - which are floating point numbers, but which are held as text. - ''' - return cmp(float(a), float(b)) - -class Guillotine(inkex.Effect): - """Exports slices made using guides""" - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--directory", action="store", - type="string", dest="directory", - default=None, help="") - - self.OptionParser.add_option("--image", action="store", - type="string", dest="image", - default=None, help="") - - self.OptionParser.add_option("--ignore", action="store", - type="inkbool", dest="ignore", - default=None, help="") - - def get_guides(self): - ''' - Returns all guide elements as an iterable collection - ''' - root = self.document.getroot() - guides = [] - xpath = self.document.xpath("//sodipodi:guide", - namespaces=inkex.NSS) - for g in xpath: - guide = {} - (x, y) = g.attrib['position'].split(',') - if g.attrib['orientation'] == '0,1': - guide['orientation'] = 'horizontal' - guide['position'] = y - guides.append(guide) - elif g.attrib['orientation'] == '1,0': - guide['orientation'] = 'vertical' - guide['position'] = x - guides.append(guide) - return guides - - def get_all_horizontal_guides(self): - ''' - Returns all horizontal guides as a list of floats stored as - strings. Each value is the position from 0 in pixels. - ''' - guides = [] - for g in self.get_guides(): - if g['orientation'] == 'horizontal': - guides.append(g['position']) - return guides - - def get_all_vertical_guides(self): - ''' - Returns all vertical guides as a list of floats stored as - strings. Each value is the position from 0 in pixels. - ''' - guides = [] - for g in self.get_guides(): - if g['orientation'] == 'vertical': - guides.append(g['position']) - return guides - - def get_horizontal_slice_positions(self): - ''' - Make a sorted list of all horizontal guide positions, - including 0 and the document height, but not including - those outside of the canvas - ''' - root = self.document.getroot() - horizontals = ['0'] - height = inkex.unittouu(root.attrib['height']) - for h in self.get_all_horizontal_guides(): - if h >= 0 and float(h) <= float(height): - horizontals.append(h) - horizontals.append(height) - horizontals.sort(cmp=float_sort) - return horizontals - - def get_vertical_slice_positions(self): - ''' - Make a sorted list of all vertical guide positions, - including 0 and the document width, but not including - those outside of the canvas. - ''' - root = self.document.getroot() - verticals = ['0'] - width = inkex.unittouu(root.attrib['width']) - for v in self.get_all_vertical_guides(): - if v >= 0 and float(v) <= float(width): - verticals.append(v) - verticals.append(width) - verticals.sort(cmp=float_sort) - return verticals - - def get_slices(self): - ''' - Returns a list of all "slices" as denoted by the guides - on the page. Each slice is really just a 4 element list of - floats (stored as strings), consisting of the X and Y start - position and the X and Y end position. - ''' - hs = self.get_horizontal_slice_positions() - vs = self.get_vertical_slice_positions() - slices = [] - for i in range(len(hs)-1): - for j in range(len(vs)-1): - slices.append([vs[j], hs[i], vs[j+1], hs[i+1]]) - return slices - - def get_filename_parts(self): - ''' - Attempts to get directory and image as passed in by the inkscape - dialog. If the boolean ignore flag is set, then it will ignore - these settings and try to use the settings from the export - filename. - ''' - - if self.options.ignore == False: - return (self.options.directory, self.options.image) - else: - ''' - First get the export-filename from the document, if the - document has been exported before (TODO: Will not work if it - hasn't been exported yet), then uses this to return a tuple - consisting of the directory to export to, and the filename - without extension. - ''' - svg = self.document.getroot() - att = '{http://www.inkscape.org/namespaces/inkscape}export-filename' - try: - export_file = svg.attrib[att] - except KeyError: - inkex.errormsg("To use the export hints option, you " + - "need to have previously exported the document. " + - "Otherwise no export hints exist!") - sys.exit(-1) - dirname, filename = os.path.split(export_file) - filename = filename.rsplit(".", 1)[0] # Without extension - return (dirname, filename) - - def check_dir_exists(self, dir): - if not os.path.isdir(dir): - os.makedirs(dir) - - def get_localised_string(self, str): - return locale.format("%.f", float(str), 0) - - def export_slice(self, s, filename): - ''' - Runs inkscape's command line interface and exports the image - slice from the 4 coordinates in s, and saves as the filename - given. - ''' - svg_file = self.args[-1] - command = "inkscape -a %s:%s:%s:%s -e \"%s\" \"%s\" " % (self.get_localised_string(s[0]), self.get_localised_string(s[1]), self.get_localised_string(s[2]), self.get_localised_string(s[3]), filename, svg_file) - 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.open3(command) - f.close() - - def export_slices(self, slices): - ''' - Takes the slices list and passes each one with a calculated - filename/directory into export_slice. - ''' - dirname, filename = self.get_filename_parts() - if dirname == '' or dirname == None: - dirname = './' - inkex.errormsg(dirname) - dirname = os.path.expanduser(dirname) - dirname = os.path.expandvars(dirname) - self.check_dir_exists(dirname) - i = 0 - for s in slices: - f = dirname + os.path.sep + filename + str(i) + ".png" - self.export_slice(s, f) - i += 1 - - def effect(self): - slices = self.get_slices() - self.export_slices(slices) - -if __name__ == "__main__": - e = Guillotine() - e.affect() - +#!/usr/bin/env python +''' +guillotine.py + +Copyright (C) 2010 Craig Marshall, craig9 [at] gmail.com + +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 + +----------------------- + +This script slices an inkscape drawing along the guides, similarly to +the GIMP plugin called "guillotine". It can optionally export to the +same directory as the SVG file with the same name, but with a number +suffix. e.g. + +/home/foo/drawing.svg + +will export to: + +/home/foo/drawing0.png +/home/foo/drawing1.png +/home/foo/drawing2.png +/home/foo/drawing3.png + +etc. + +''' + +import os +import sys +import inkex +import simplestyle +import locale + +locale.setlocale(locale.LC_ALL, '') + +try: + from subprocess import Popen, PIPE + bsubprocess = True +except: + bsubprocess = False + +def float_sort(a, b): + ''' + This is used to sort the horizontal and vertical guide positions, + which are floating point numbers, but which are held as text. + ''' + return cmp(float(a), float(b)) + +class Guillotine(inkex.Effect): + """Exports slices made using guides""" + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--directory", action="store", + type="string", dest="directory", + default=None, help="") + + self.OptionParser.add_option("--image", action="store", + type="string", dest="image", + default=None, help="") + + self.OptionParser.add_option("--ignore", action="store", + type="inkbool", dest="ignore", + default=None, help="") + + def get_guides(self): + ''' + Returns all guide elements as an iterable collection + ''' + root = self.document.getroot() + guides = [] + xpath = self.document.xpath("//sodipodi:guide", + namespaces=inkex.NSS) + for g in xpath: + guide = {} + (x, y) = g.attrib['position'].split(',') + if g.attrib['orientation'] == '0,1': + guide['orientation'] = 'horizontal' + guide['position'] = y + guides.append(guide) + elif g.attrib['orientation'] == '1,0': + guide['orientation'] = 'vertical' + guide['position'] = x + guides.append(guide) + return guides + + def get_all_horizontal_guides(self): + ''' + Returns all horizontal guides as a list of floats stored as + strings. Each value is the position from 0 in pixels. + ''' + guides = [] + for g in self.get_guides(): + if g['orientation'] == 'horizontal': + guides.append(g['position']) + return guides + + def get_all_vertical_guides(self): + ''' + Returns all vertical guides as a list of floats stored as + strings. Each value is the position from 0 in pixels. + ''' + guides = [] + for g in self.get_guides(): + if g['orientation'] == 'vertical': + guides.append(g['position']) + return guides + + def get_horizontal_slice_positions(self): + ''' + Make a sorted list of all horizontal guide positions, + including 0 and the document height, but not including + those outside of the canvas + ''' + root = self.document.getroot() + horizontals = ['0'] + height = inkex.unittouu(root.attrib['height']) + for h in self.get_all_horizontal_guides(): + if h >= 0 and float(h) <= float(height): + horizontals.append(h) + horizontals.append(height) + horizontals.sort(cmp=float_sort) + return horizontals + + def get_vertical_slice_positions(self): + ''' + Make a sorted list of all vertical guide positions, + including 0 and the document width, but not including + those outside of the canvas. + ''' + root = self.document.getroot() + verticals = ['0'] + width = inkex.unittouu(root.attrib['width']) + for v in self.get_all_vertical_guides(): + if v >= 0 and float(v) <= float(width): + verticals.append(v) + verticals.append(width) + verticals.sort(cmp=float_sort) + return verticals + + def get_slices(self): + ''' + Returns a list of all "slices" as denoted by the guides + on the page. Each slice is really just a 4 element list of + floats (stored as strings), consisting of the X and Y start + position and the X and Y end position. + ''' + hs = self.get_horizontal_slice_positions() + vs = self.get_vertical_slice_positions() + slices = [] + for i in range(len(hs)-1): + for j in range(len(vs)-1): + slices.append([vs[j], hs[i], vs[j+1], hs[i+1]]) + return slices + + def get_filename_parts(self): + ''' + Attempts to get directory and image as passed in by the inkscape + dialog. If the boolean ignore flag is set, then it will ignore + these settings and try to use the settings from the export + filename. + ''' + + if self.options.ignore == False: + return (self.options.directory, self.options.image) + else: + ''' + First get the export-filename from the document, if the + document has been exported before (TODO: Will not work if it + hasn't been exported yet), then uses this to return a tuple + consisting of the directory to export to, and the filename + without extension. + ''' + svg = self.document.getroot() + att = '{http://www.inkscape.org/namespaces/inkscape}export-filename' + try: + export_file = svg.attrib[att] + except KeyError: + inkex.errormsg("To use the export hints option, you " + + "need to have previously exported the document. " + + "Otherwise no export hints exist!") + sys.exit(-1) + dirname, filename = os.path.split(export_file) + filename = filename.rsplit(".", 1)[0] # Without extension + return (dirname, filename) + + def check_dir_exists(self, dir): + if not os.path.isdir(dir): + os.makedirs(dir) + + def get_localised_string(self, str): + return locale.format("%.f", float(str), 0) + + def export_slice(self, s, filename): + ''' + Runs inkscape's command line interface and exports the image + slice from the 4 coordinates in s, and saves as the filename + given. + ''' + svg_file = self.args[-1] + command = "inkscape -a %s:%s:%s:%s -e \"%s\" \"%s\" " % (self.get_localised_string(s[0]), self.get_localised_string(s[1]), self.get_localised_string(s[2]), self.get_localised_string(s[3]), filename, svg_file) + 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.open3(command) + f.close() + + def export_slices(self, slices): + ''' + Takes the slices list and passes each one with a calculated + filename/directory into export_slice. + ''' + dirname, filename = self.get_filename_parts() + if dirname == '' or dirname == None: + dirname = './' + inkex.errormsg(dirname) + dirname = os.path.expanduser(dirname) + dirname = os.path.expandvars(dirname) + self.check_dir_exists(dirname) + i = 0 + for s in slices: + f = dirname + os.path.sep + filename + str(i) + ".png" + self.export_slice(s, f) + i += 1 + + def effect(self): + slices = self.get_slices() + self.export_slices(slices) + +if __name__ == "__main__": + e = Guillotine() + e.affect() + diff --git a/share/extensions/param_curves.inx b/share/extensions/param_curves.inx index 0d21329cd..e9d734fe1 100644 --- a/share/extensions/param_curves.inx +++ b/share/extensions/param_curves.inx @@ -1,28 +1,28 @@ - - - <_name>Parametric Curves - org.inkscape.effect.param_curves - param_curves.py - inkex.py - - - 0.0 - 1.0 - true - -1.0 - 1.0 - -1.0 - 1.0 - 30 - false - - + + + <_name>Parametric Curves + org.inkscape.effect.param_curves + param_curves.py + inkex.py + + + 0.0 + 1.0 + true + -1.0 + 1.0 + -1.0 + 1.0 + 30 + false + + <_param name="funcplotuse" type="description" xml:space="preserve">Select a rectangle before calling the extension, it will determine X and Y scales. -First derivatives are always determined numerically. - - +First derivatives are always determined numerically. + + <_param name="pythonfunctions" type="description" xml:space="preserve">Standard Python math functions are available: ceil(x); fabs(x); floor(x); fmod(x,y); frexp(x); ldexp(x,i); @@ -31,20 +31,20 @@ acos(x); asin(x); atan(x); atan2(y,x); hypot(x,y); cos(x); sin(x); tan(x); degrees(x); radians(x); cosh(x); sinh(x); tanh(x). -The constants pi and e are also available. - - - cos(3*t) - sin(5*t) - true - false - - rect - - - - - - +The constants pi and e are also available. + + + cos(3*t) + sin(5*t) + true + false + + rect + + + + + + diff --git a/share/extensions/param_curves.py b/share/extensions/param_curves.py index 32f4b8c80..7a8f384aa 100644 --- a/share/extensions/param_curves.py +++ b/share/extensions/param_curves.py @@ -1,252 +1,252 @@ -#!/usr/bin/env python -''' -Copyright (C) 2009 Michel Chatelain. -Copyright (C) 2007 Tavmjong Bah, tavmjong@free.fr -Copyright (C) 2006 Georg Wiora, xorx@quarkbox.de -Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl -Copyright (C) 2005 Aaron Spike, aaron@ekips.org - -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 - -Changes: - * This program is derived by Michel Chatelain from funcplot.py. His changes are in the Public Domain. - * Michel Chatelain, 17-18 janvier 2009, a partir de funcplot.py - * 20 janvier 2009 : adaptation a la version 0.46 a partir de la nouvelle version de funcplot.py - -''' - -import inkex, simplepath, simplestyle -from math import * -from random import * - -def drawfunction(t_start, t_end, xleft, xright, ybottom, ytop, samples, width, height, left, bottom, - fx = "cos(3*t)", fy = "sin(5*t)", times2pi = False, isoscale = True, drawaxis = True): - - if times2pi == True: - t_start = 2 * pi * t_start - t_end = 2 * pi * t_end - - # coords and scales based on the source rect - scalex = width / (xright - xleft) - xoff = left - coordx = lambda x: (x - xleft) * scalex + xoff #convert x-value to coordinate - scaley = height / (ytop - ybottom) - yoff = bottom - coordy = lambda y: (ybottom - y) * scaley + yoff #convert y-value to coordinate - - # Check for isotropic scaling and use smaller of the two scales, correct ranges - if isoscale: - if scaley=0: - # xaxis - a.append(['M ',[left, coordy(0)]]) - a.append([' l ',[width, 0]]) - # check for visibility of y-axis - if xleft<=0 and xright>=0: - # xaxis - a.append([' M ',[coordx(0),bottom]]) - a.append([' l ',[0, -height]]) - - # initialize functions and derivatives for 0; - # they are carried over from one iteration to the next, to avoid extra function calculations. - x0 = f1(t_start) - y0 = f2(t_start) - - # numerical derivatives, using 0.001*step as the small differential - t1 = t_start + ds # Second point AFTER first point (Good for first point) - x1 = f1(t1) - y1 = f2(t1) - dx0 = (x1 - x0)/ds - dy0 = (y1 - y0)/ds - - # Start curve - a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto - for i in range(int(samples-1)): - t1 = (i+1) * step + t_start - t2 = t1 - ds # Second point BEFORE first point (Good for last point) - x1 = f1(t1) - x2 = f1(t2) - y1 = f2(t1) - y2 = f2(t2) - - # numerical derivatives - dx1 = (x1 - x2)/ds - dy1 = (y1 - y2)/ds - - # create curve - a.append([' C ', - [coordx(x0 + (dx0 * third)), coordy(y0 + (dy0 * third)), - coordx(x1 - (dx1 * third)), coordy(y1 - (dy1 * third)), - coordx(x1), coordy(y1)] - ]) - t0 = t1 # Next segment's start is this segments end - x0 = x1 - y0 = y1 - dx0 = dx1 # Assume the functions are smooth everywhere, so carry over the derivatives too - dy0 = dy1 - return a - -class ParamCurves(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--t_start", - action="store", type="float", - dest="t_start", default=0.0, - help="Start t-value") - self.OptionParser.add_option("--t_end", - action="store", type="float", - dest="t_end", default=1.0, - help="End t-value") - self.OptionParser.add_option("--times2pi", - action="store", type="inkbool", - dest="times2pi", default=True, - help="Multiply t-range by 2*pi") - self.OptionParser.add_option("--xleft", - action="store", type="float", - dest="xleft", default=-1.0, - help="x-value of rectangle's left") - self.OptionParser.add_option("--xright", - action="store", type="float", - dest="xright", default=1.0, - help="x-value of rectangle's right") - self.OptionParser.add_option("--ybottom", - action="store", type="float", - dest="ybottom", default=-1.0, - help="y-value of rectangle's bottom") - self.OptionParser.add_option("--ytop", - action="store", type="float", - dest="ytop", default=1.0, - help="y-value of rectangle's top") - self.OptionParser.add_option("-s", "--samples", - action="store", type="int", - dest="samples", default=8, - help="Samples") - self.OptionParser.add_option("--fofx", - action="store", type="string", - dest="fofx", default="cos(3*t)", - help="fx(t) for plotting") - self.OptionParser.add_option("--fofy", - action="store", type="string", - dest="fofy", default="sin(5*t)", - help="fy(t) for plotting") - self.OptionParser.add_option("--remove", - action="store", type="inkbool", - dest="remove", default=True, - help="If True, source rectangle is removed") - self.OptionParser.add_option("--isoscale", - action="store", type="inkbool", - dest="isoscale", default=True, - help="If True, isotropic scaling is used") - self.OptionParser.add_option("--drawaxis", - action="store", type="inkbool", - dest="drawaxis", default=True, - help="If True, axis are drawn") - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", default="sampling", - help="The selected UI-tab when OK was pressed") - self.OptionParser.add_option("--paramcurvesuse", - action="store", type="string", - dest="paramcurvesuse", default="", - help="dummy") - self.OptionParser.add_option("--pythonfunctions", - action="store", type="string", - dest="pythonfunctions", default="", - help="dummy") - - def effect(self): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('rect','svg'): - # create new path with basic dimensions of selected rectangle - newpath = inkex.etree.Element(inkex.addNS('path','svg')) - x = float(node.get('x')) - y = float(node.get('y')) - w = float(node.get('width')) - h = float(node.get('height')) - - #copy attributes of rect - s = node.get('style') - if s: - newpath.set('style', s) - - t = node.get('transform') - if t: - newpath.set('transform', t) - - # top and bottom were exchanged - newpath.set('d', simplepath.formatPath( - drawfunction(self.options.t_start, - self.options.t_end, - self.options.xleft, - self.options.xright, - self.options.ybottom, - self.options.ytop, - self.options.samples, - w,h,x,y+h, - self.options.fofx, - self.options.fofy, - self.options.times2pi, - self.options.isoscale, - self.options.drawaxis))) - newpath.set('title', self.options.fofx + " " + self.options.fofy) - - #newpath.set('desc', '!func;' + self.options.fofx + ';' + self.options.fofy + ';' - # + `self.options.t_start` + ';' - # + `self.options.t_end` + ';' - # + `self.options.samples`) - - # add path into SVG structure - node.getparent().append(newpath) - # option wether to remove the rectangle or not. - if self.options.remove: - node.getparent().remove(node) - -if __name__ == '__main__': - e = ParamCurves() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +#!/usr/bin/env python +''' +Copyright (C) 2009 Michel Chatelain. +Copyright (C) 2007 Tavmjong Bah, tavmjong@free.fr +Copyright (C) 2006 Georg Wiora, xorx@quarkbox.de +Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl +Copyright (C) 2005 Aaron Spike, aaron@ekips.org + +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 + +Changes: + * This program is derived by Michel Chatelain from funcplot.py. His changes are in the Public Domain. + * Michel Chatelain, 17-18 janvier 2009, a partir de funcplot.py + * 20 janvier 2009 : adaptation a la version 0.46 a partir de la nouvelle version de funcplot.py + +''' + +import inkex, simplepath, simplestyle +from math import * +from random import * + +def drawfunction(t_start, t_end, xleft, xright, ybottom, ytop, samples, width, height, left, bottom, + fx = "cos(3*t)", fy = "sin(5*t)", times2pi = False, isoscale = True, drawaxis = True): + + if times2pi == True: + t_start = 2 * pi * t_start + t_end = 2 * pi * t_end + + # coords and scales based on the source rect + scalex = width / (xright - xleft) + xoff = left + coordx = lambda x: (x - xleft) * scalex + xoff #convert x-value to coordinate + scaley = height / (ytop - ybottom) + yoff = bottom + coordy = lambda y: (ybottom - y) * scaley + yoff #convert y-value to coordinate + + # Check for isotropic scaling and use smaller of the two scales, correct ranges + if isoscale: + if scaley=0: + # xaxis + a.append(['M ',[left, coordy(0)]]) + a.append([' l ',[width, 0]]) + # check for visibility of y-axis + if xleft<=0 and xright>=0: + # xaxis + a.append([' M ',[coordx(0),bottom]]) + a.append([' l ',[0, -height]]) + + # initialize functions and derivatives for 0; + # they are carried over from one iteration to the next, to avoid extra function calculations. + x0 = f1(t_start) + y0 = f2(t_start) + + # numerical derivatives, using 0.001*step as the small differential + t1 = t_start + ds # Second point AFTER first point (Good for first point) + x1 = f1(t1) + y1 = f2(t1) + dx0 = (x1 - x0)/ds + dy0 = (y1 - y0)/ds + + # Start curve + a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto + for i in range(int(samples-1)): + t1 = (i+1) * step + t_start + t2 = t1 - ds # Second point BEFORE first point (Good for last point) + x1 = f1(t1) + x2 = f1(t2) + y1 = f2(t1) + y2 = f2(t2) + + # numerical derivatives + dx1 = (x1 - x2)/ds + dy1 = (y1 - y2)/ds + + # create curve + a.append([' C ', + [coordx(x0 + (dx0 * third)), coordy(y0 + (dy0 * third)), + coordx(x1 - (dx1 * third)), coordy(y1 - (dy1 * third)), + coordx(x1), coordy(y1)] + ]) + t0 = t1 # Next segment's start is this segments end + x0 = x1 + y0 = y1 + dx0 = dx1 # Assume the functions are smooth everywhere, so carry over the derivatives too + dy0 = dy1 + return a + +class ParamCurves(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--t_start", + action="store", type="float", + dest="t_start", default=0.0, + help="Start t-value") + self.OptionParser.add_option("--t_end", + action="store", type="float", + dest="t_end", default=1.0, + help="End t-value") + self.OptionParser.add_option("--times2pi", + action="store", type="inkbool", + dest="times2pi", default=True, + help="Multiply t-range by 2*pi") + self.OptionParser.add_option("--xleft", + action="store", type="float", + dest="xleft", default=-1.0, + help="x-value of rectangle's left") + self.OptionParser.add_option("--xright", + action="store", type="float", + dest="xright", default=1.0, + help="x-value of rectangle's right") + self.OptionParser.add_option("--ybottom", + action="store", type="float", + dest="ybottom", default=-1.0, + help="y-value of rectangle's bottom") + self.OptionParser.add_option("--ytop", + action="store", type="float", + dest="ytop", default=1.0, + help="y-value of rectangle's top") + self.OptionParser.add_option("-s", "--samples", + action="store", type="int", + dest="samples", default=8, + help="Samples") + self.OptionParser.add_option("--fofx", + action="store", type="string", + dest="fofx", default="cos(3*t)", + help="fx(t) for plotting") + self.OptionParser.add_option("--fofy", + action="store", type="string", + dest="fofy", default="sin(5*t)", + help="fy(t) for plotting") + self.OptionParser.add_option("--remove", + action="store", type="inkbool", + dest="remove", default=True, + help="If True, source rectangle is removed") + self.OptionParser.add_option("--isoscale", + action="store", type="inkbool", + dest="isoscale", default=True, + help="If True, isotropic scaling is used") + self.OptionParser.add_option("--drawaxis", + action="store", type="inkbool", + dest="drawaxis", default=True, + help="If True, axis are drawn") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", default="sampling", + help="The selected UI-tab when OK was pressed") + self.OptionParser.add_option("--paramcurvesuse", + action="store", type="string", + dest="paramcurvesuse", default="", + help="dummy") + self.OptionParser.add_option("--pythonfunctions", + action="store", type="string", + dest="pythonfunctions", default="", + help="dummy") + + def effect(self): + for id, node in self.selected.iteritems(): + if node.tag == inkex.addNS('rect','svg'): + # create new path with basic dimensions of selected rectangle + newpath = inkex.etree.Element(inkex.addNS('path','svg')) + x = float(node.get('x')) + y = float(node.get('y')) + w = float(node.get('width')) + h = float(node.get('height')) + + #copy attributes of rect + s = node.get('style') + if s: + newpath.set('style', s) + + t = node.get('transform') + if t: + newpath.set('transform', t) + + # top and bottom were exchanged + newpath.set('d', simplepath.formatPath( + drawfunction(self.options.t_start, + self.options.t_end, + self.options.xleft, + self.options.xright, + self.options.ybottom, + self.options.ytop, + self.options.samples, + w,h,x,y+h, + self.options.fofx, + self.options.fofy, + self.options.times2pi, + self.options.isoscale, + self.options.drawaxis))) + newpath.set('title', self.options.fofx + " " + self.options.fofy) + + #newpath.set('desc', '!func;' + self.options.fofx + ';' + self.options.fofy + ';' + # + `self.options.t_start` + ';' + # + `self.options.t_end` + ';' + # + `self.options.samples`) + + # add path into SVG structure + node.getparent().append(newpath) + # option wether to remove the rectangle or not. + if self.options.remove: + node.getparent().remove(node) + +if __name__ == '__main__': + e = ParamCurves() + e.affect() + + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 diff --git a/share/extensions/render_alphabetsoup.py b/share/extensions/render_alphabetsoup.py index 7e4009328..ffc20323b 100644 --- a/share/extensions/render_alphabetsoup.py +++ b/share/extensions/render_alphabetsoup.py @@ -1,463 +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 -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() - +#!/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/svg2xaml.xsl b/share/extensions/svg2xaml.xsl index cda6c7a97..1c663c11c 100755 --- a/share/extensions/svg2xaml.xsl +++ b/share/extensions/svg2xaml.xsl @@ -1,1483 +1,1483 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Collapsed - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Absolute - RelativeToBoundingBox - - - - - - Pad - Reflect - Repeat - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Absolute - RelativeToBoundingBox - - - - - - Pad - Reflect - Repeat - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NonZero - - - - - - - - - - - - - - - - - - - #000000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Bevel - Round - Miter - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Round - Square - Flat - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Left - Center - Right - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Collapsed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Absolute + RelativeToBoundingBox + + + + + + Pad + Reflect + Repeat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Absolute + RelativeToBoundingBox + + + + + + Pad + Reflect + Repeat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NonZero + + + + + + + + + + + + + + + + + + + #000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bevel + Round + Miter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Round + Square + Flat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Left + Center + Right + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/share/extensions/xaml2svg.xsl b/share/extensions/xaml2svg.xsl index c5f1cfd75..8c0e4a5c9 100644 --- a/share/extensions/xaml2svg.xsl +++ b/share/extensions/xaml2svg.xsl @@ -1,107 +1,107 @@ - - - - - - - - - - - - - - - - - - visible - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - start - middle - end - - - - hanging - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + visible + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + start + middle + end + + + + hanging + + + + + + + + + + + +