[cairo-commit] [cairo-www] src/svgtopycairo.mdwn
Carl Worth
cworth at freedesktop.org
Thu Nov 8 08:00:28 PST 2007
src/svgtopycairo.mdwn | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 141 insertions(+)
New commits:
commit 033370ce5af4f868a79377d4a28ce0ee7c90f7f8
Author: Donn <donn.ingle at gmail.com>
Date: Thu Nov 8 08:00:28 2007 -0800
The day's labour
diff --git a/src/svgtopycairo.mdwn b/src/svgtopycairo.mdwn
new file mode 100644
index 0000000..2c7ed5c
--- /dev/null
+++ b/src/svgtopycairo.mdwn
@@ -0,0 +1,141 @@
+##SVG paths can be parsed and turned into a seqence of cairo commands that re-draw them.
+
+This took a while, the pyparsing had me in knots, but now it's short and sweet. A fuller implementation of what can be done in SVG would be really nice. (Hint...)
+Make sure you pass it a very simple SVG file -- one that has had all the shapes reduced to paths. Oh, and keep your canvas 400 by 400 or it may draw clear off the screen.
+It re-uses the framework from my other recipe. You should be able to copy/paste and run, but you may need elementree and pyparsing first.
+
+
+ #!/usr/bin/env python
+ """\
+ Usage: drawsvg.py file
+ file - one SVG file (from Inkscape!) that is all simple paths
+
+ """
+ ## svg2py Copyright (C) 2007 Donn.C.Ingle
+ ##
+ ## Contact: donn.ingle at gmail.com - I hope this email lasts.
+ ##
+ ## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ##
+
+ import pygtk
+ pygtk.require('2.0')
+ import gtk, gobject, cairo
+ from pyparsing import *
+ import os, sys
+ from elementtree import ElementTree as et
+
+ # Create a GTK+ widget on which we will draw using Cairo
+ class Screen(gtk.DrawingArea):
+
+ # Draw in response to an expose-event
+ __gsignals__ = { "expose-event": "override" }
+
+ # Handle the expose-event by drawing
+ def do_expose_event(self, event):
+
+ # Create the cairo context
+ cr = self.window.cairo_create()
+
+ # Restrict Cairo to the exposed area; avoid extra work
+ cr.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+ cr.clip()
+
+ self.draw(cr, *self.window.get_size())
+
+ def draw(self, cr, width, height):
+ # Fill the background with gray
+ cr.set_source_rgb(0.5, 0.5, 0.5)
+ cr.rectangle(0, 0, width, height)
+ cr.fill()
+
+ # GTK mumbo-jumbo to show the widget in a window and quit when it's closed
+ def run(Widget):
+ window = gtk.Window()
+ window.set_size_request(400, 400)
+ window.connect("delete-event", gtk.main_quit)
+ widget = Widget()
+ widget.show()
+ window.add(widget)
+ window.present()
+ gtk.main()
+
+ #######################
+ ## Do all your testing in Shapes ##
+ #######################
+
+ class Shapes(Screen):
+ def draw(self, ctx, width, height):
+
+ #Build a string of cairo commands
+ cairo_commands = ""
+ command_list = []
+ for tokens in paths:
+ for command,couples in tokens[:-1]: #looks weird, but it works :)
+ c = couples.asList()
+ if command == "M":
+ cairo_commands += "ctx.move_to(%s,%s);" % (c[0],c[1])
+ if command == "C":
+ cairo_commands += "ctx.curve_to(%s,%s,%s,%s,%s,%s);" % (c[0],c[1],c[2],c[3],c[4],c[5])
+ if command == "L":
+ cairo_commands += "ctx.line_to(%s,%s);" % (c[0],c[1])
+ if command == "Z":
+ cairo_commands += "ctx.close_path();"
+
+ command_list.append(cairo_commands) #Add them to the list
+
+ #Draw it. Only stroked, to fill as per the SVG drawing is another whole story.
+ ctx.set_source_rgb(1,0,0)
+ for c in command_list:
+ exec(c)
+ ctx.stroke()
+
+ #Check args:
+ if len(sys.argv) < 2:
+ raise SystemExit(__doc__)
+ file = sys.argv[1]
+
+ ## With HUGE help from Paul McGuire <paul at alanweberassociates.com>
+ ## Thanks!
+ dot = Literal(".")
+ comma = Literal(",").suppress()
+ floater = Combine(Optional("-") + Word(nums) + dot + Word(nums))
+ ## Unremark to have numbers be floats rather than strings.
+ #floater.setParseAction(lambda toks:float(toks[0]))
+ couple = floater + comma + floater
+ M_command = "M" + Group(couple)
+ C_command = "C" + Group(couple + couple + couple)
+ L_command = "L" + Group(couple)
+ Z_command = "Z"
+ svgcommand = M_command | C_command | L_command | Z_command
+ phrase = OneOrMore(Group(svgcommand))
+
+ ## Find and open the svg file
+ xml_file = os.path.abspath(__file__)
+ xml_file = os.path.dirname(xml_file)
+ xml_file = os.path.join(xml_file, file)
+
+ tree = et.parse(xml_file)
+
+ ns = "http://www.w3.org/2000/svg" #The XML namespace.
+ paths = []
+ for group in tree.getiterator('{%s}g' % ns):
+ for e in group.getiterator('{%s}path' % ns):
+ p = e.get("d")
+ tokens = phrase.parseString(p.upper())
+ paths.append(tokens)
+
+ run(Shapes)
More information about the cairo-commit
mailing list