A random link Home Compute Inkscape Contact   
   
   
   

Modularize

Since most of the code was shared between my last two test extensions, I thought it would be a good idea to create a module. The most current version of it is available here.

This is the second version of my Inkscape extension module. I was unhappy with the lack of flexibility that the original option, which used a callback function, offered. So I consulted with a good friend and he suggested that a class would be just the right approach.

#!/usr/bin/env python
"""
inkex.py
A helper module for creating Inkscape extensions
"""
import sys, optparse
import xml.dom.ext
import xml.dom.ext.reader.Sax2
import xml.xpath

def parseStyle(s):
	"""Create a dictionary from the value of an inline style attribute"""
	return dict([i.split(":") for i in s.split(";")])
def formatStyle(a):
	"""Format an inline style attribute from a dictionary"""
	return ";".join([":".join(i) for i in a.iteritems()])

class Effect:
	def __init__(self):
		self.document=None
		self.selected={}
		self.options=None
		self.args=None
		self.OptionParser = optparse.OptionParser(usage="usage: %prog [options] SVGfile")
		self.OptionParser.add_option("--id",
						action="append", type="string", dest="ids", default=[], 
						help="id attribute of object to manipulate")
	def effect(self):
		pass
	def getoptions(self,args=sys.argv[1:]):
		"""Collect command line arguments"""
		self.options, self.args = self.OptionParser.parse_args(args)
	def parse(self,file=None):
		"""Parse document in specified file or on stdin"""
		reader = xml.dom.ext.reader.Sax2.Reader()
		try:
			try:
				stream = open(file,'r')
			except:
				stream = open(self.args[-1],'r')
		except:
			stream = sys.stdin
		self.document = reader.fromStream(stream)
		stream.close()
	def getselected(self):
		"""Collect selected nodes"""
		for id in self.options.ids:
			path = '//*[@id="%s"]' % id
			for node in xml.xpath.Evaluate(path,self.document):
				self.selected[id] = node
	def output(self):
		"""Serialize document into XML on stdout"""
		xml.dom.ext.Print(self.document)
	def affect(self):
		"""Affect an SVG document with a callback effect"""
		self.getoptions()
		self.parse()
		self.getselected()
		self.effect()
		self.output()
	
And an example of it in use.
#!/usr/bin/env python
"""
style.py
Example of accessing and altering a style attribute of an element 
"""
import inkex
from inkex import Effect

class setOpacity(Effect):
	def __init__(self):
		Effect.__init__(self)
		self.OptionParser.add_option("-o", "--opacity",
						action="store", type="string", 
						dest="opacity", default="1.0",
						help="desired fill-opacity")
	def effect(self): 
		for id,node in self.selected.iteritems():
			style = node.attributes.getNamedItem('style')
			s = inkex.parseStyle(style.value)
			s['fill-opacity']=self.options.opacity
			style.value = inkex.formatStyle(s)

obj = setOpacity()
obj.affect()

My original Inscape extension module.

#!/usr/bin/env python
"""
inkex.py
A helper module for creating Inkscape extensions
"""
import sys, getopt
import xml.dom.ext
import xml.dom.ext.reader.Sax2
import xml.xpath

def parseStyle(s):
	"""Create a dictionary from the value of an inline style attribute"""
	return dict([i.split(":") for i in s.split(";")])
def formatStyle(a):
	"""Format an inline style attribute from a dictionary"""
	return ";".join([":".join(i) for i in a.iteritems()])

def affect(effect_callback):
	"""Affect an SVG document with a callback effect"""
	#collect ids from the arguments
	#TODO: get other arguments?
	opts = getopt.getopt(sys.argv[1:],'',['id='])
	ids = [opt[1] for opt in opts[0] if opt[0]=='--id']

	#create xml parser
	reader = xml.dom.ext.reader.Sax2.Reader()
	#open SVG tempfile
	#TODO: optionailly read from STDIN
	stream = open(sys.argv[-1:][0],'r')
	#create DOM object
	doc = reader.fromStream(stream)
	stream.close()

	#collect nodes
	nodes = {}
	for id in ids:
		path = '//*[@id="%s"]' % id
		for node in xml.xpath.Evaluate(path,doc):
			nodes[id] = node

	#affect the document
	params = {
		'doc': doc,
		'selected': nodes 
	}
	effect_callback(params)

	#serialize DOM object into XML on stdout
	xml.dom.ext.Print(doc)
And an example of it in use.
#!/usr/bin/env python
"""
style.py
Example of accessing and altering a style attribute of an element 
"""
import inkex

def alterStyle(params): 
	for id,node in params['selected'].iteritems():
		style = node.attributes.getNamedItem('style')
		s = inkex.parseStyle(style.value)
		s['fill-opacity']='0.5'
		style.value = inkex.formatStyle(s)

inkex.affect(alterStyle)

Files:

     
   
   
Home Compute Inkscape Contact