<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.inkscape.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Newacct</id>
	<title>Inkscape Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.inkscape.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Newacct"/>
	<link rel="alternate" type="text/html" href="https://wiki.inkscape.org/wiki/Special:Contributions/Newacct"/>
	<updated>2026-04-08T05:50:48Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://wiki.inkscape.org/wiki/index.php?title=InkSlide&amp;diff=66259</id>
		<title>InkSlide</title>
		<link rel="alternate" type="text/html" href="https://wiki.inkscape.org/wiki/index.php?title=InkSlide&amp;diff=66259"/>
		<updated>2010-12-14T00:19:45Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== InkSlide - quick and easy presentations using Inkscape ==&lt;br /&gt;
&lt;br /&gt;
InkSlide produces slides like this:&lt;br /&gt;
&lt;br /&gt;
[[Image:slide0004.jpg]]&lt;br /&gt;
&lt;br /&gt;
from simple text input like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
InkSlide: Features&lt;br /&gt;
++++++++++++++++++&lt;br /&gt;
&lt;br /&gt;
Features include wrapped top level text and&lt;br /&gt;
- mulitple&lt;br /&gt;
  - levels&lt;br /&gt;
    - of wrapped bulleted lists with bullets and font&lt;br /&gt;
      information taken from the template file.&lt;br /&gt;
&lt;br /&gt;
Slide specific content like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
which is updated when the template changes.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An Inkscape file is used as a template file to define the background, title position and font, fonts and positions for text at different levels of indentation, groups to be cloned and used as bullets, etc.&lt;br /&gt;
&lt;br /&gt;
Content specific to a particular slide can also be created in Inkscape, this content merged with the template and text input to make the final slide, so changes to the template after a particular slide is edited in Inkscape are included.&lt;br /&gt;
&lt;br /&gt;
=== Download ===&lt;br /&gt;
&lt;br /&gt;
Copy the [[InkSlide#Code|text below]] into a file called 'inkslide.py'.  (How do you attach a non-image file on this wiki?)&lt;br /&gt;
&lt;br /&gt;
Here is an [[Media:template0.svg|example template]].  Use Save Link As to stop your browser displaying the file instead of downloading it.&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
First InkSlide parses the text input, something like the example at the top of this page.  It looks for flowed text boxes in the template file with special @id attributes like ''fr_title'' for the title, and ''fr_tab2'' for the second level of bulleted lists.  Copies of these elements are made and placed in a layer called 'Texts'.  At this point, the text is all piled up at the top of the page.&lt;br /&gt;
&lt;br /&gt;
InkSlide saves the file, and uses Inkscape's command line ''--query-height'' and friends to find out how high the wrapped text pieces are.  At it then repositions them properly, adds clones of the bullet markers, etc.  Bullet markers have special @id attributes like ''bu_1'' for the first level of bulleted list.&lt;br /&gt;
&lt;br /&gt;
Finally, InkSlide checks to see if there's an id tag for the slide, and if so if there's a corresponding Inkscape SVG file with content for this particular slide. This content has to occur in layers whose name starts with ''Instance'', and these layers have to be present in the template file, but you can have more than one, so they can be above and below the regular content.  If such content is found, it's copied into the output slide.&lt;br /&gt;
&lt;br /&gt;
=== The Template File ===&lt;br /&gt;
&lt;br /&gt;
The template file is a regular Inkscape file.  If this list seems hard, just use the example template and modify it to suit your needs.&lt;br /&gt;
&lt;br /&gt;
Required contents:&lt;br /&gt;
&lt;br /&gt;
*A group or layer called ''gr_text'', into which text will be placed.&lt;br /&gt;
*A flowed text frame with an @id of ''fr_title'' to define the font and position for the slide title.  This should contain text like ''Title goes here Sly'' because ''Sly'' includes letters which ascend and descend from the baseline to the greatest extent.  The placeholder text must be '''only''' one line because it's used to calculate line height.&lt;br /&gt;
*A group or layer called ''gr_title'' into which the title will be placed.  This makes it easier to do special effects on the title like shadows.&lt;br /&gt;
*Flowed text frames with an @id of ''fr_tabN'' for each N in 0, 1, 2, 3.  ''fr_tab0'' is used for top level non bulleted text.  These should also include ''Sly'' or similar.  The placeholder text must be '''only''' one line because it's used to calculate line height.&lt;br /&gt;
*Objects or groups withan @id of ''bu_N'' for each N in 1, 2, 3, for the three levels of bulleted list.&lt;br /&gt;
&lt;br /&gt;
The fr_* elements define the font, font-size, color etc. for the different levels of text.  They also define the position and wrap width.  See the example template file for a possible arrangement.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;A group or layer called 'X'&amp;quot; indicates either a group with an '''@id'''&lt;br /&gt;
of 'X' ''or'' a layer with a '''label''' (name) of 'X'.  When both exist the group will take precedence.&lt;br /&gt;
 &lt;br /&gt;
Optional contents:&lt;br /&gt;
&lt;br /&gt;
*A background, which should be placed in a group or layer called `gr_bg`&lt;br /&gt;
*A foreground, which should be placed in a group or layer called `gr_fg`&lt;br /&gt;
*Affiliation text and logos you want to appear on every slide, this could go in the background, or another named group or layer.&lt;br /&gt;
*A blurred clone of the gr_title element, offset and behind it.  It's easier to do this is `gr_title` is a group rather than a layer.&lt;br /&gt;
*Layers whose name starts with ''Instance'' - these are the layers the user can edit directly in Inkscape for a particular slide.&lt;br /&gt;
&lt;br /&gt;
When you save the template file you should make sure that layers containing place holder text (the fr_* elements) and bullets are invisible.  Likewise the Texts layer should be visible, as well as any Instance layers.&lt;br /&gt;
=== Text Input ===&lt;br /&gt;
&lt;br /&gt;
InkSlide uses [http://docutils.sourceforge.net/rst.html reStructuredText] for markup, although it renders only a subset of rst.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Inkslide: an example&lt;br /&gt;
++++++++++++++++++++&lt;br /&gt;
&lt;br /&gt;
This text will appear as a top level paragraph.&lt;br /&gt;
&lt;br /&gt;
- Dash prefix indicates this text will appear as a bulleted item.&lt;br /&gt;
&lt;br /&gt;
  - Indented dash prefix -&amp;gt; second level bulleted list.&lt;br /&gt;
&lt;br /&gt;
.. is:pause&lt;br /&gt;
&lt;br /&gt;
Two slides will be produced for this input, one with everything up to the&lt;br /&gt;
&amp;quot;.. is:pause&amp;quot;, and one with that plus the remaining content.&lt;br /&gt;
Incremental list display can be done this way.&lt;br /&gt;
&lt;br /&gt;
The is:id tag below indicates that a file with a name like&lt;br /&gt;
'extra/is_intro.svg' should be inspected for extra content&lt;br /&gt;
for this particular slide.&lt;br /&gt;
&lt;br /&gt;
.. is:id is_intro&lt;br /&gt;
&lt;br /&gt;
Inkslide: the next slide...&lt;br /&gt;
+++++++++++++++++++++++++++&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The GUI ===&lt;br /&gt;
&lt;br /&gt;
A GUI for InkSlide is available as a plug-in for the [http://webpages.charter.net/edreamleo/front.html Leo] outline editor.  This makes slide re-arranging easy, and adds some macro substitution capability.  It also adds buttons for editing slide specific content in Inkscape.&lt;br /&gt;
&lt;br /&gt;
FIXME: post plug-in on Leo wiki and link.&lt;br /&gt;
&lt;br /&gt;
=== To do / status ===&lt;br /&gt;
&lt;br /&gt;
InkSlide is very usable, but is missing some features.  Remember you can &lt;br /&gt;
use the slide specific editing feature to do any of these things and&lt;br /&gt;
anything else you can do in Inkscape already, these will just be more&lt;br /&gt;
convenient in the text input when they're done.&lt;br /&gt;
&lt;br /&gt;
*Inline text formatting (bold, color, etc.) for part of a piece of text&lt;br /&gt;
*Justification switching&lt;br /&gt;
*Verbatim code display&lt;br /&gt;
*&amp;lt;strike&amp;gt;Simple image inclusion&amp;lt;/strike&amp;gt;&lt;br /&gt;
*more helper tools to make PNG and PDF versions of slides&lt;br /&gt;
*configuring / using a directory for edited slides&lt;br /&gt;
*command line flags for generating specific slides&lt;br /&gt;
&lt;br /&gt;
Currently InkSlide is slow, because it must invoke Inkscape once for every single dimension it needs to retrieve.  I'll try and get a --query-all switch into 0.46.&lt;br /&gt;
&lt;br /&gt;
=== Bugs ===&lt;br /&gt;
&lt;br /&gt;
*There may be an issue with the way slide specific content is merged into the template producing conflicting @id attributes, but I haven't seen this happen yet.&lt;br /&gt;
&lt;br /&gt;
=== Author  / Credits ===&lt;br /&gt;
&lt;br /&gt;
InkSlide was written by Terry Brown, terry-n-brown@yahoo.com - but use underscore, not '-'.&lt;br /&gt;
&lt;br /&gt;
InkSlide was inspired by [http://member.wide.ad.jp/wg/mgp/ MagicPoint]&lt;br /&gt;
&lt;br /&gt;
Matt Harrison suggested using reStructured text as the markup language.&lt;br /&gt;
&lt;br /&gt;
=== Code ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# inkslide.py $Id$&lt;br /&gt;
# Author: Terry Brown&lt;br /&gt;
# Created: Thu Oct 11 2007&lt;br /&gt;
&lt;br /&gt;
import lxml.etree as ET&lt;br /&gt;
&lt;br /&gt;
import copy&lt;br /&gt;
import subprocess&lt;br /&gt;
import os.path&lt;br /&gt;
from docutils.core import publish_string&lt;br /&gt;
&lt;br /&gt;
import sys  # for debug&lt;br /&gt;
class inkSlide(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
&lt;br /&gt;
        self.NS = { 'i': 'http://www.inkscape.org/namespaces/inkscape',&lt;br /&gt;
           's': 'http://www.w3.org/2000/svg',&lt;br /&gt;
           'xlink' : 'http://www.w3.org/1999/xlink'}&lt;br /&gt;
&lt;br /&gt;
        # number of defined tablevels, FIXME, could derive from template?&lt;br /&gt;
        self.tabLevels = 4  &lt;br /&gt;
&lt;br /&gt;
        self._nextId = 0&lt;br /&gt;
&lt;br /&gt;
        self.gap = {&lt;br /&gt;
            'bIMAGE': 15,   # gap before image&lt;br /&gt;
            'aIMAGE': 15,   # gap after image&lt;br /&gt;
            'aTAB0': 10,    # gap after top level text&lt;br /&gt;
            'aTAB1': 10,    # gap after level 1 bullet&lt;br /&gt;
            'aTAB2': 10,    # gap after level 2 bullet&lt;br /&gt;
            'aTAB3': 10,    # gap after level 3 bullet&lt;br /&gt;
            'fVCENTER': 1,  # flag - center vertically&lt;br /&gt;
            'dHEIGHT': 728, # dimension, bottom of page&lt;br /&gt;
            'fHCENTER': 1,  # flag - center vertically&lt;br /&gt;
            'dWIDTH': 1024, # dimension, bottom of page&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        self.dimCache = {}&lt;br /&gt;
        self.is_reads, self.is_cache = 0, 0&lt;br /&gt;
    def __del__(self):&lt;br /&gt;
        print '%d reads, %d cache hits' % (self.is_reads, self.is_cache)&lt;br /&gt;
    def nextId(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;return an unsed Id&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        # FIXME, should inspect template doc.&lt;br /&gt;
        self._nextId += 1&lt;br /&gt;
        return 'is'+str(self._nextId)&lt;br /&gt;
&lt;br /&gt;
    def clearId(self, x, what='id', NS={}):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;recursively clear @id on element x and descendants&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if not NS: NS = self.NS&lt;br /&gt;
        if what in x.keys():&lt;br /&gt;
            del x.attrib[what]&lt;br /&gt;
        for i in x.xpath('.//*[@%s]'%what, NS):&lt;br /&gt;
            del i.attrib[what]&lt;br /&gt;
        return x&lt;br /&gt;
    def getDim(self, fn, Id, what):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;return dimension of element in fn with @id Id, what is&lt;br /&gt;
        x, y, width, height&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        hsh = fn+Id+what&lt;br /&gt;
        if hsh in self.dimCache:&lt;br /&gt;
            self.is_cache += 1&lt;br /&gt;
            return self.dimCache[hsh]&lt;br /&gt;
&lt;br /&gt;
        cmd = ('inkscape', '--without-gui', '--query-id', Id, '--query-'+what, fn)&lt;br /&gt;
&lt;br /&gt;
        proc = subprocess.Popen(cmd, stdout = subprocess.PIPE,&lt;br /&gt;
                                stderr = subprocess.PIPE)&lt;br /&gt;
        # make new pipe for stderr to supress chatter from inkscape&lt;br /&gt;
        proc.wait()&lt;br /&gt;
        self.dimCache[hsh] = proc.stdout.read()&lt;br /&gt;
        if self.dimCache[hsh].strip() == '':&lt;br /&gt;
            print &amp;quot;Warning: '%s' not found&amp;quot; % Id&lt;br /&gt;
        self.is_reads += 1&lt;br /&gt;
        return self.dimCache[hsh]&lt;br /&gt;
    def textReader(self, text):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;NOT USED iterate parts in input text&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if not text: return&lt;br /&gt;
        for line in text.split('\n'):&lt;br /&gt;
            if line.startswith('%slide '):&lt;br /&gt;
                yield {'type':'TITLE', 's':line[7:].strip()}&lt;br /&gt;
                continue&lt;br /&gt;
            if line.startswith('%pause'):&lt;br /&gt;
                yield {'type':'PAUSE'}&lt;br /&gt;
                continue&lt;br /&gt;
            if line.startswith('%id '):&lt;br /&gt;
                yield {'type':'ID', 's':line[4:].strip()}&lt;br /&gt;
                continue&lt;br /&gt;
            if not line.strip():&lt;br /&gt;
                yield {'type':'BLANK'}&lt;br /&gt;
                continue&lt;br /&gt;
            tabs = len(line) - len(line.lstrip('\t'))&lt;br /&gt;
            yield {'type':'TAB', 'tabs':tabs, 's':line.strip()}&lt;br /&gt;
&lt;br /&gt;
    def textReaderRst(self, text):&lt;br /&gt;
&lt;br /&gt;
        xml = publish_string(text.replace('\t','    '), writer_name = 'xml')&lt;br /&gt;
        doc = ET.fromstring(xml)&lt;br /&gt;
        # yield {'type':'TITLE', 's':doc.xpath('/document/@title')[0]}&lt;br /&gt;
        nodes = 'paragraph', 'comment', 'title', 'image'&lt;br /&gt;
        for i in doc.xpath('//%s' % '|//'.join(nodes)):&lt;br /&gt;
&lt;br /&gt;
            if i.tag == 'title':&lt;br /&gt;
                yield {'type':'TITLE', 's':i.text}&lt;br /&gt;
            if i.tag == 'paragraph':&lt;br /&gt;
                tabs = len(i.xpath('ancestor::list_item'))&lt;br /&gt;
                yield {'type':'TAB', 'tabs':tabs, 's':i.text, 'e':i}&lt;br /&gt;
            if i.tag == 'image':&lt;br /&gt;
                tabs = len(i.xpath('ancestor::list_item'))&lt;br /&gt;
                yield {'type':'IMAGE', 'uri':i.get('uri')}&lt;br /&gt;
            if i.tag == 'comment':&lt;br /&gt;
&lt;br /&gt;
                comparts = i.text.split(None, 1)&lt;br /&gt;
&lt;br /&gt;
                if len(comparts) &amp;gt; 1:&lt;br /&gt;
                    ctag, cval = comparts&lt;br /&gt;
                elif len(comparts) == 1:&lt;br /&gt;
                    ctag = comparts[0]&lt;br /&gt;
                else:&lt;br /&gt;
                    continue  # empty comment had no meaning to InkView&lt;br /&gt;
&lt;br /&gt;
                if ctag == 'is:id':&lt;br /&gt;
                    try:&lt;br /&gt;
                        yield {'type':'ID', 's':cval}&lt;br /&gt;
                    except:&lt;br /&gt;
                        raise Exception('&amp;quot;id&amp;quot; comment requires a value')&lt;br /&gt;
                elif ctag == 'is:notitle':&lt;br /&gt;
                    yield {'type':'DROP', 'what':('gr_title',)}&lt;br /&gt;
                elif ctag == 'is:notext':&lt;br /&gt;
                    yield {'type':'DROP', 'what':('gr_text',)}&lt;br /&gt;
                elif ctag == 'is:nobackground':&lt;br /&gt;
                    yield {'type':'DROP', 'what':('gr_bg',)}&lt;br /&gt;
                elif ctag == 'is:noforeground':&lt;br /&gt;
                    yield {'type':'DROP', 'what':('gr_fg',)}&lt;br /&gt;
                elif ctag == 'is:blank':&lt;br /&gt;
                    yield {'type':'DROP', 'what':('gr_title','gr_text')}&lt;br /&gt;
                elif ctag == 'is:empty':&lt;br /&gt;
                    yield {'type':'DROP', 'what':('gr_bg','gr_title','gr_text','gr_fg')}&lt;br /&gt;
                elif ctag == 'is:no':&lt;br /&gt;
                    try:&lt;br /&gt;
                        yield {'type':'DROP', 'what':(cval,)}&lt;br /&gt;
                    except:&lt;br /&gt;
                        raise Exception('&amp;quot;no&amp;quot; comment requires a value')&lt;br /&gt;
&lt;br /&gt;
                if ctag == 'is:dim':&lt;br /&gt;
                    dim, val = cval.strip().split()&lt;br /&gt;
                    yield {'type':'DIM', 'dim':dim, 'val':val}&lt;br /&gt;
    def groupOrLayer(self, g):&lt;br /&gt;
        dst = self.doc.xpath('//s:g[@id=&amp;quot;%s&amp;quot;]'%g, self.NS)&lt;br /&gt;
        if not dst: dst = self.doc.xpath('//s:g[@i:label=&amp;quot;%s&amp;quot;]'%g, self.NS)&lt;br /&gt;
        if not dst: return dst  # let the caller test, don't raise exception here&lt;br /&gt;
        dst = dst[0]&lt;br /&gt;
        return dst&lt;br /&gt;
    def instanceFromTemplate(self, template, instance, text, pauseOk = True):&lt;br /&gt;
&lt;br /&gt;
        slide = 0&lt;br /&gt;
&lt;br /&gt;
        hlist = []&lt;br /&gt;
        self.doc = ET.parse(template)&lt;br /&gt;
        slideId = None&lt;br /&gt;
&lt;br /&gt;
        for t in self.textReaderRst(text):&lt;br /&gt;
&lt;br /&gt;
            if t['type'] == 'ID':&lt;br /&gt;
                slideId = t['s']&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            if t['type'] == 'TITLE':&lt;br /&gt;
                if hlist:&lt;br /&gt;
                    self.process(instance, hlist, slideId, slide)&lt;br /&gt;
                    slide = slide + 1&lt;br /&gt;
                    hlist = [t]&lt;br /&gt;
                    self.doc = ET.parse(template)&lt;br /&gt;
                    slideId = None&lt;br /&gt;
                else:&lt;br /&gt;
                    hlist.append(t)&lt;br /&gt;
&lt;br /&gt;
                print t['s']&lt;br /&gt;
&lt;br /&gt;
                dst = self.groupOrLayer('gr_title')&lt;br /&gt;
                src = self.doc.xpath('//s:flowRoot[@id=&amp;quot;fr_title&amp;quot;]', self.NS)[0]&lt;br /&gt;
                cpy = self.clearId(copy.deepcopy(src))&lt;br /&gt;
                Id = self.nextId()&lt;br /&gt;
                cpy.set('id', Id)&lt;br /&gt;
                hlist[-1]['id']=Id&lt;br /&gt;
                cpy.xpath('s:flowPara',self.NS)[0].text = t['s']&lt;br /&gt;
                dst.append(cpy)&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            if t['type'] == 'PAUSE':&lt;br /&gt;
                if pauseOk:&lt;br /&gt;
                    self.process(instance, hlist, slideId, slide)&lt;br /&gt;
                    slide = slide + 1&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            if t['type'] == 'BLANK':&lt;br /&gt;
                hlist.append(t)&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            if t['type'] == 'TAB':&lt;br /&gt;
                hlist.append(t)&lt;br /&gt;
                dst = self.groupOrLayer('gr_text')&lt;br /&gt;
                src = self.doc.xpath('//s:flowRoot[@id=&amp;quot;fr_tab%d&amp;quot;]' % t['tabs'], self.NS)[0]&lt;br /&gt;
                cpy = self.clearId(copy.deepcopy(src))&lt;br /&gt;
                Id = self.nextId()&lt;br /&gt;
                cpy.set('id', Id)&lt;br /&gt;
                hlist[-1]['id']=Id&lt;br /&gt;
                # cpy.xpath('s:flowPara',self.NS)[0].text = t['s']&lt;br /&gt;
                self.flowParaFromElement(&lt;br /&gt;
                    cpy.xpath('s:flowPara',self.NS)[0], t['e'])&lt;br /&gt;
                dst.append(cpy)&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            if t['type'] == 'IMAGE':&lt;br /&gt;
                hlist.append(t)&lt;br /&gt;
                dst = self.groupOrLayer('gr_image')&lt;br /&gt;
                if not dst:&lt;br /&gt;
                    dst = self.groupOrLayer('gr_text')&lt;br /&gt;
                img = ET.Element('image')&lt;br /&gt;
                img.set('{%s}href'%self.NS['xlink'], t['uri'])&lt;br /&gt;
                Id = self.nextId()&lt;br /&gt;
                img.set('id', Id)&lt;br /&gt;
                hlist[-1]['id']=Id&lt;br /&gt;
                dst.append(img)&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            hlist.append(t)  # whatever it was&lt;br /&gt;
&lt;br /&gt;
        self.process(instance, hlist, slideId, slide)&lt;br /&gt;
    def flowParaFromElement(self, fp, e):&lt;br /&gt;
        fp.text = e.xpath('string(.)')&lt;br /&gt;
    def process(self, instance, hlist, slideId, slide):&lt;br /&gt;
&lt;br /&gt;
        instanceName = instance.replace('%s', '%04d'%slide)&lt;br /&gt;
&lt;br /&gt;
        instance = 'tmp.svg'  # reusing allows caching in getDim, but relies on nextId ensuring&lt;br /&gt;
                              # that the changing parts have new ids&lt;br /&gt;
&lt;br /&gt;
        self.doc.write(file(instance, 'w'))&lt;br /&gt;
&lt;br /&gt;
        drop = []&lt;br /&gt;
&lt;br /&gt;
        bullDim = {}&lt;br /&gt;
        tabDim = {}&lt;br /&gt;
        for n in range(0,self.tabLevels):&lt;br /&gt;
            b = {}&lt;br /&gt;
            x = self.doc.xpath('//*[@id=&amp;quot;bu_%d&amp;quot;]'%n, self.NS)&lt;br /&gt;
            if x:&lt;br /&gt;
                # self.clearId(x[0], what='transform')&lt;br /&gt;
                for i in 'x', 'y', 'width', 'height':&lt;br /&gt;
                    b[i] = float(self.getDim(instance, 'bu_%d'%n, i))&lt;br /&gt;
                bullDim[n] = b&lt;br /&gt;
            b = {}&lt;br /&gt;
            x = self.doc.xpath('//*[@id=&amp;quot;fr_tab%d&amp;quot;]'%n, self.NS)&lt;br /&gt;
            if x:&lt;br /&gt;
                # clearId(x[0], what='transform')&lt;br /&gt;
                for i in 'x', 'y', 'width', 'height':&lt;br /&gt;
                    b[i] = float(self.getDim(instance, 'fr_tab%d'%n, i))&lt;br /&gt;
                x = x[0].xpath('.//s:rect',self.NS)[0]&lt;br /&gt;
                b['max-width'] = float(x.get('width'))&lt;br /&gt;
                b['max-height'] = float(x.get('height'))&lt;br /&gt;
                tabDim[n] = b&lt;br /&gt;
&lt;br /&gt;
        delta = 0.&lt;br /&gt;
        firstVert = True&lt;br /&gt;
        placed_xy = []&lt;br /&gt;
        placed_transform = []&lt;br /&gt;
&lt;br /&gt;
        for n, i in enumerate(hlist):&lt;br /&gt;
&lt;br /&gt;
            this = hlist[n]&lt;br /&gt;
            prev = hlist[n-1]&lt;br /&gt;
&lt;br /&gt;
            if this['type'] == 'DROP': drop += this['what']&lt;br /&gt;
&lt;br /&gt;
            if this['type'] == 'DIM':&lt;br /&gt;
                if this['dim'] not in self.gap or this['val'][0] not in '+-':&lt;br /&gt;
                    self.gap[this['dim']] = float(this['val'])&lt;br /&gt;
                else:&lt;br /&gt;
                    self.gap[this['dim']] += float(this['val'])&lt;br /&gt;
&lt;br /&gt;
            zeroHeight = ['TITLE', 'DROP', 'DIM']&lt;br /&gt;
&lt;br /&gt;
            # don't do this - need to add height from prev to delta&lt;br /&gt;
            #if this['type'] in zeroHeight:&lt;br /&gt;
            #    continue  # already in right place, not a vertical element&lt;br /&gt;
&lt;br /&gt;
            hgt = 0&lt;br /&gt;
            if prev['type'] == 'BLANK':&lt;br /&gt;
                hgt = 30&lt;br /&gt;
            elif prev['type'] not in zeroHeight:&lt;br /&gt;
                hgt = float(self.getDim(instance, prev['id'], 'height'))&lt;br /&gt;
&lt;br /&gt;
                # risky gambit to space bullets properly when some lines&lt;br /&gt;
                # have no ascenders etc.&lt;br /&gt;
                if prev['type'] == 'TAB' and prev['tabs'] &amp;gt; 0:&lt;br /&gt;
                    lnh = tabDim[prev['tabs']]['height']&lt;br /&gt;
                    hgt = lnh * int(hgt/lnh+0.5)&lt;br /&gt;
&lt;br /&gt;
            # TAB0, TAB1, TITLE, IMAGE, etc.&lt;br /&gt;
            # gap after previous&lt;br /&gt;
            hsh = 'a' + prev['type'] + str(prev.get('tabs',''))&lt;br /&gt;
            hgt += self.gap.get(hsh, 0)&lt;br /&gt;
            # gap before current&lt;br /&gt;
            hsh = 'b' + this['type'] + str(this.get('tabs',''))&lt;br /&gt;
            hgt += self.gap.get(hsh, 0)&lt;br /&gt;
&lt;br /&gt;
            if firstVert:&lt;br /&gt;
                hgt = 0&lt;br /&gt;
                firstVert = False&lt;br /&gt;
&lt;br /&gt;
            delta += hgt&lt;br /&gt;
&lt;br /&gt;
            if this['type'] == 'BLANK': continue&lt;br /&gt;
&lt;br /&gt;
            if this['type'] == 'TAB':&lt;br /&gt;
                tabs = this['tabs']&lt;br /&gt;
&lt;br /&gt;
                r = self.doc.xpath('//s:flowRoot[@id=&amp;quot;%s&amp;quot;]' % this['id'], self.NS)[0]&lt;br /&gt;
                self.clearId(r, what='transform')&lt;br /&gt;
                r = r.xpath('.//s:rect', self.NS)[0]&lt;br /&gt;
                r.set('x', str(tabDim[tabs]['x']))&lt;br /&gt;
                y = tabDim[tabs]['y'] + delta&lt;br /&gt;
                #print '%s -&amp;gt; %s' % (r.get('y'), y)&lt;br /&gt;
                #print tabDim[tabs]['y']&lt;br /&gt;
                r.set('y', str(y))&lt;br /&gt;
                placed_xy.append([r, this['id']])&lt;br /&gt;
&lt;br /&gt;
            if (this['type'] == 'TAB' and this['tabs'] in bullDim&lt;br /&gt;
                and 'isDone' not in this):&lt;br /&gt;
                this['isDone'] = True&lt;br /&gt;
                dx = (tabDim[tabs]['x'] &lt;br /&gt;
                      - bullDim[tabs]['x']&lt;br /&gt;
                      - 1.5*bullDim[tabs]['width']&lt;br /&gt;
                      )&lt;br /&gt;
                dy = (y &lt;br /&gt;
                      + tabDim[tabs]['height'] / 2.&lt;br /&gt;
                      - bullDim[tabs]['y'] &lt;br /&gt;
                      - bullDim[tabs]['height'] / 2.&lt;br /&gt;
                      )&lt;br /&gt;
                # dst = doc0.xpath('//s:g[@i:label=&amp;quot;Texts&amp;quot;]', NS)[0]&lt;br /&gt;
                dst = self.groupOrLayer('gr_text')&lt;br /&gt;
                #print y, tabDim[tabs]['height'], bullDim[tabs]['y'], bullDim[tabs]['height'], dy&lt;br /&gt;
                clone = ET.Element('use')&lt;br /&gt;
                clone.set('transform', 'translate(%f,%f)' % (dx,dy))&lt;br /&gt;
                clone.set('{%s}href'%self.NS['xlink'], '#bu_%d'%tabs)&lt;br /&gt;
                placed_transform.append([clone, dx, dy])&lt;br /&gt;
                dst.append(clone)&lt;br /&gt;
&lt;br /&gt;
            if this['type'] == 'IMAGE':&lt;br /&gt;
&lt;br /&gt;
                xpath = '//s:image[@id=&amp;quot;%s&amp;quot;]' % this['id']  # doesn't work?&lt;br /&gt;
                xpath = '//*[@id=&amp;quot;%s&amp;quot;]' % this['id']&lt;br /&gt;
                i = self.doc.xpath(xpath, self.NS)[0]&lt;br /&gt;
                w = float(self.getDim(instance, this['id'], 'width'))&lt;br /&gt;
                x = tabDim[0]['x']+tabDim[0]['max-width']/2-w/2&lt;br /&gt;
                i.set('x', str(x))&lt;br /&gt;
                y = tabDim[0]['y'] + delta&lt;br /&gt;
                i.set('y', str(y))&lt;br /&gt;
                placed_xy.append([i,this['id']])&lt;br /&gt;
&lt;br /&gt;
        if self.gap['fVCENTER']:&lt;br /&gt;
&lt;br /&gt;
            if 'id' in this:&lt;br /&gt;
                delta += float(self.getDim(instance, this['id'], 'height'))&lt;br /&gt;
&lt;br /&gt;
            recenter = (self.gap['dHEIGHT'] - delta - tabDim[0]['y']) * 0.45&lt;br /&gt;
&lt;br /&gt;
            for i in placed_transform:&lt;br /&gt;
                i[0].set('transform', 'translate(%f,%f)'%(i[1],i[2]+recenter))&lt;br /&gt;
                i[2] += recenter  # so it's not lost below&lt;br /&gt;
            for i in placed_xy:&lt;br /&gt;
                i[0].set('y', str(float(i[0].get('y'))+recenter))&lt;br /&gt;
&lt;br /&gt;
        if self.gap['fHCENTER']:&lt;br /&gt;
&lt;br /&gt;
            maxX = 0&lt;br /&gt;
            for i in placed_xy:&lt;br /&gt;
                x = float(self.getDim(instance, i[1], 'x'))&lt;br /&gt;
                x += float(self.getDim(instance, i[1], 'width'))&lt;br /&gt;
                if x &amp;gt; maxX: maxX = x&lt;br /&gt;
&lt;br /&gt;
            recenter = (self.gap['dWIDTH'] - maxX - tabDim[0]['x']) * 0.5&lt;br /&gt;
&lt;br /&gt;
            for i in placed_transform:&lt;br /&gt;
                i[0].set('transform', 'translate(%f,%f)'%(i[1]+recenter,i[2]))&lt;br /&gt;
                i[1] += recenter  # in case it's used again&lt;br /&gt;
            for i in placed_xy:&lt;br /&gt;
                if i[0].tag != 'image':  # images already centered&lt;br /&gt;
                    # print i[0].tag&lt;br /&gt;
                    i[0].set('x', str(float(i[0].get('x'))+recenter))&lt;br /&gt;
&lt;br /&gt;
        # look for instance specific parts&lt;br /&gt;
        if slideId:&lt;br /&gt;
            f = self.instancePath(slideId)&lt;br /&gt;
            if os.path.isfile(f):&lt;br /&gt;
                comp = ET.parse(f)&lt;br /&gt;
                svg = self.doc.xpath('//s:svg', self.NS)[0]&lt;br /&gt;
                g = &amp;quot;{%s}g&amp;quot;%self.NS['s']&lt;br /&gt;
                k = &amp;quot;{%s}label&amp;quot;%self.NS['i']&lt;br /&gt;
                for n, i in enumerate(svg.getchildren()):&lt;br /&gt;
                    if i.tag == g and i.get(k, '').startswith('Instance'):&lt;br /&gt;
                        x = comp.xpath('//s:svg//s:g[@i:label=&amp;quot;%s&amp;quot;]'%i.get(k), self.NS)&lt;br /&gt;
                        if x:&lt;br /&gt;
                            x = x[0]&lt;br /&gt;
                            cpy = self.clearId(copy.deepcopy(x))&lt;br /&gt;
                            # cpy = self.textCopy(x)&lt;br /&gt;
                            svg[n] = cpy&lt;br /&gt;
                defs = comp.xpath('//s:svg/s:defs/*', self.NS)&lt;br /&gt;
                dst = self.doc.xpath('//s:svg/s:defs', self.NS)[0]&lt;br /&gt;
                for d in defs:&lt;br /&gt;
                    Id = d.get('id')&lt;br /&gt;
                    current = self.doc.xpath('//s:svg/s:defs/*[@id=&amp;quot;%s&amp;quot;]'%Id, self.NS)&lt;br /&gt;
                    if not current:&lt;br /&gt;
                        cpy = copy.deepcopy(d)&lt;br /&gt;
                        dst.append(cpy)&lt;br /&gt;
&lt;br /&gt;
        for i in drop:&lt;br /&gt;
            e = self.groupOrLayer(i)&lt;br /&gt;
            if e:&lt;br /&gt;
                e.xpath('..')[0].remove(e)&lt;br /&gt;
&lt;br /&gt;
        # problem losing xlink ns?&lt;br /&gt;
        for i in self.doc.xpath('//*[@href]'):&lt;br /&gt;
            i.set('{%s}href'%self.NS['xlink'], i.get('href'))&lt;br /&gt;
&lt;br /&gt;
        self.doc.write(file(instanceName, 'w'))&lt;br /&gt;
&lt;br /&gt;
        return slideId&lt;br /&gt;
    def textCopy(self, ele):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;copy the element ele via xml-&amp;gt;text-&amp;gt;xml, as deepcopy seems to lose text&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        txt = ET.tostring(ele)&lt;br /&gt;
        # print txt&lt;br /&gt;
        return ET.fromstring(txt)&lt;br /&gt;
    def instancePath(self, slideId):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;return path to component for slide&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        # return os.path.join(slideId, component)&lt;br /&gt;
        return slideId+'.svg'&lt;br /&gt;
    def writeComponents(self, inkscapeFile, slideId):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;write components from file for slide&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if not slideId: return&lt;br /&gt;
        doc0 = ET.parse(inkscapeFile)&lt;br /&gt;
        hasComponents = False&lt;br /&gt;
        for i in doc0.xpath('//s:svg//s:g', self.NS):&lt;br /&gt;
            k = &amp;quot;{%s}label&amp;quot;%self.NS['i']&lt;br /&gt;
            # print i.keys(),k&lt;br /&gt;
            if (k in i.keys() and i.get(k).startswith('Instance')):&lt;br /&gt;
                if len(i) &amp;gt; 0:&lt;br /&gt;
                    hasComponents = True&lt;br /&gt;
                    break&lt;br /&gt;
                    # ET.ElementTree(i).write(f)&lt;br /&gt;
&lt;br /&gt;
        f = self.instancePath(slideId)&lt;br /&gt;
&lt;br /&gt;
        if hasComponents:&lt;br /&gt;
            if (os.path.abspath(os.path.realpath(inkscapeFile)) != &lt;br /&gt;
                os.path.abspath(os.path.realpath(f))):&lt;br /&gt;
                file(f, 'w').write(file(inkscapeFile).read())&lt;br /&gt;
        else:&lt;br /&gt;
            if os.path.isfile(f):&lt;br /&gt;
                os.remove(f)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    import sys&lt;br /&gt;
    x = inkSlide()&lt;br /&gt;
    x.instanceFromTemplate(sys.argv[1], 'slide%s.svg', file(sys.argv[2]).read())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://wiki.inkscape.org/wiki/index.php?title=Win32_Installer&amp;diff=62359</id>
		<title>Win32 Installer</title>
		<link rel="alternate" type="text/html" href="https://wiki.inkscape.org/wiki/index.php?title=Win32_Installer&amp;diff=62359"/>
		<updated>2010-05-28T00:00:10Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There has been some complaints about the Windows installer and also many ideas has been raised. So I want to bundle all those ideas here on one page.&lt;br /&gt;
&lt;br /&gt;
=== new feature request will cause complete rework ===&lt;br /&gt;
There is a request from a professor on the university to have a .msi installer in order to integrate inkscape into the university software distribution system.&lt;br /&gt;
This would require a complete rework and an entirely separate package as NSIS is not compatible with MSI packages.  The standard recommendation from NSIS is to use the silent install options they provide to help automate large installations.&lt;br /&gt;
&lt;br /&gt;
=== reported problems ===&lt;br /&gt;
* no uninstall option, this is a privilege issue as the user has no rigths to write the necessary registry strings&lt;br /&gt;
*- in order to install Inkscape on systems with limited rights the installer ignores such errors and just do not write registry keys&lt;br /&gt;
*  Windows: problems installing as non-privileged user, same as above. We should help the user selecting the correct settings -- remove the check for all users or shortcuts in general (done)&lt;br /&gt;
* the uninstaller simply deletes the install directory. If the user installs accidentally to C:\Program Files\ ... oh that S****&lt;br /&gt;
&lt;br /&gt;
=== coming up - where you can help ===&lt;br /&gt;
* check if Inkscape installer is not translated into your language and help translating it &lt;br /&gt;
* msi package using the wix installer, volunteers welcome&lt;br /&gt;
&lt;br /&gt;
=== status ===&lt;br /&gt;
* screenshots [http://www.geocities.com/theAdib current version]&lt;br /&gt;
* multi user installation&lt;br /&gt;
*translated into catalan, english, czech, french, finnish, german, italian, polish, slovak, slovenian and spanish&lt;br /&gt;
* optional sets file associations for .svg and .svgz&lt;br /&gt;
* optional keeps the personal preferences&lt;br /&gt;
* selectable components (core, gtk, shortcuts, examples, tutorials, translations)&lt;br /&gt;
* show GPL, not need to accept just click next&lt;br /&gt;
* added non program files (README, AUTHORS, ...)&lt;br /&gt;
* crc validation&lt;br /&gt;
* does not show details any more during installation/deinstallation&lt;br /&gt;
* silent install, all settings can be done via command line&lt;br /&gt;
* test if the user has privileges to write registry,&lt;br /&gt;
* test if inkscape is installed and the previous installation is done by the same user&lt;br /&gt;
* ask to uninstall inkscape before overwriting&lt;br /&gt;
* test if the same user uninstalls inkscape&lt;br /&gt;
* optionally removes all reachable inkscape personal settings&lt;br /&gt;
&lt;br /&gt;
=== feedback or what users say ===&lt;br /&gt;
* the file association should go to the toplevel three&lt;br /&gt;
* also associations for other file formats&lt;br /&gt;
&lt;br /&gt;
=== component page ===&lt;br /&gt;
* inkscape core files (required)&lt;br /&gt;
* gtk files (required)&lt;br /&gt;
* shortcuts&lt;br /&gt;
*- install for all user&lt;br /&gt;
*- desktop icon&lt;br /&gt;
*- quick launch icon&lt;br /&gt;
*- default SVG editor&lt;br /&gt;
*- shell menu integration&lt;br /&gt;
* additional Files&lt;br /&gt;
*- examples&lt;br /&gt;
*- tutorials&lt;br /&gt;
* languages&lt;br /&gt;
*- English (required)&lt;br /&gt;
*- German&lt;br /&gt;
*- French&lt;br /&gt;
*- ...&lt;br /&gt;
&lt;br /&gt;
=== ideas ===&lt;br /&gt;
# (DONE) installer installs everything, I don't need chinese translations&lt;br /&gt;
# (DONE) installer translations is bad, I don't understand the sense&lt;br /&gt;
    * there are descriptions if you select/mouse-over that menu item&lt;br /&gt;
# (DONE) crc validation&lt;br /&gt;
# custom installations (examples, tutorial, translations)&lt;br /&gt;
# (DONE) silent installation&lt;br /&gt;
    * is by default enables but no other option as [[/D]] directory can be set. Use [[/S]] to switch silent mode.&lt;br /&gt;
    * now all the Options can be deselected with command line parameters&lt;br /&gt;
# use the common/extra gtk-lib as gaim or gimp are doing and only supply extra libs&lt;br /&gt;
    * (Ishmal) We have talked about this before, and it is something that we need to examine.  But&lt;br /&gt;
      what we need is more of a reason to do this than only download size or disk space.  This&lt;br /&gt;
      would be much more work than just repackaging.&lt;br /&gt;
          # The individual packages of their existing ports were built individually.  This means that&lt;br /&gt;
            for development, the dev must have the makefile point to all of their individual trees.&lt;br /&gt;
            The pkg-config information thus also refers to individual trees.  This would make development&lt;br /&gt;
            -much- more difficult than is is now.  Remember, the Win32 build is just another build &lt;br /&gt;
            environment of the Inkscape tree.  We can edit/compile/debug on it just as easily as&lt;br /&gt;
            on Linux.  It is -not- a port, where the development is done entirely on Linux.&lt;br /&gt;
          # We would need for the startup code to look for the location of the Gtk directory in the&lt;br /&gt;
            registry.  We would then either need to add it to the path, or do explicit [[LoadLibrary]]()&lt;br /&gt;
            calls.&lt;br /&gt;
          # If the user does not already have the common Gtk directory, then it must be part of our&lt;br /&gt;
            install process.  We cannot ask the user to go to some website, download and install it.&lt;br /&gt;
            We provide -everything- now.  We would need an extremely good reason to stop doing this.&lt;br /&gt;
            Actually, if you have ever used [[InstallShield]], you would know that it provides all of its&lt;br /&gt;
            dependencies, too (the huge ODBC or OLE packages within your installer are examples).&lt;br /&gt;
      I am not against this.  We just need to do it a different way.   What we have discussed is the&lt;br /&gt;
      possibility of being able to build the entire set of libraries from source, all of the way from&lt;br /&gt;
      iconv to Gtkmm and libxslt and beyond.  If we could do this, then the build would be clean, and have&lt;br /&gt;
      valid interdependencies (no missing DLLs or DLLs with the wrong names).  A single pkg-config &lt;br /&gt;
      directory would point to all of the correct places.  This would benefit everyone; Gimp, Gaim,&lt;br /&gt;
      Inkscape, and anyone else who wanted to build a Gtk app on Win32 would find it much easier&lt;br /&gt;
      this way.  We need to talk with the guys doing the porting, about doing something just like this.&lt;br /&gt;
&lt;br /&gt;
      There is a promising subproject of [[MinGW]], 'portmaker,'  which can maybe allow this to happen.&lt;br /&gt;
      It is [http://sourceforge.net/forum/forum.php?forum_id=476731 here].&lt;br /&gt;
&lt;br /&gt;
# (DONE) there is no need to show the GPL just for the usage of the program. Make it not mandatory to accept.&lt;br /&gt;
    * (Ishmal)  I think the GPL is cool.   It basically says &amp;quot;Welcome to Open Source,&amp;quot; and reminds&lt;br /&gt;
       the users that it is not a commercial application, but a community effort.&lt;br /&gt;
# (DONE) not to show Details by default&lt;br /&gt;
# test dependencies before installing extensions&lt;br /&gt;
# associate more than just .svg&lt;br /&gt;
    * uh, again how do we test which dependencies are supported uberconverter, ghostscript, etc&lt;br /&gt;
&lt;br /&gt;
=== problems and questions ===&lt;br /&gt;
* (DONE) we need to detect, what are the inkscape translations and let the user choose&lt;br /&gt;
: how we present the languages?&lt;br /&gt;
: In the native one &amp;quot;English, Deutsch, Italiano&amp;quot; or in the language of the installer?&lt;br /&gt;
    * currently it is presented like that, ordered by ISO code &amp;quot;am Amharic, de German)&lt;br /&gt;
: once we detected inkscape translation we can left over the other languages from the gtk package&lt;br /&gt;
* how can we put the translations out of the installer so that more people can help translating&lt;br /&gt;
    * what about let a script write the translation part ? &lt;br /&gt;
      this script then should access the po files for the translations&lt;br /&gt;
      Q: does python or perl allow to access the inkscape po files ?&lt;br /&gt;
* (DONE) what should a silent installation do, what are the options ?&lt;br /&gt;
    * all options are supported a /? gives a screen with all possible options&lt;br /&gt;
* (DONE) we also need to add some none program-files: license (done), authors, hacking, news (release-notes), readme,&lt;br /&gt;
&lt;br /&gt;
=== more todo ===&lt;br /&gt;
* please provide samples or screenshots of a application that you satisfied and think is good&lt;br /&gt;
* other ideas&lt;br /&gt;
&lt;br /&gt;
=== screenshots ===&lt;br /&gt;
* [[http://www.geocities.com/theAdib screenshots Abiword Blender Gaim Gimp NSIS WinCVS WinMerge installer]]&lt;br /&gt;
&lt;br /&gt;
Adib&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://wiki.inkscape.org/wiki/index.php?title=FindMatch&amp;diff=55005</id>
		<title>FindMatch</title>
		<link rel="alternate" type="text/html" href="https://wiki.inkscape.org/wiki/index.php?title=FindMatch&amp;diff=55005"/>
		<updated>2009-11-29T06:41:14Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Find Match tries to match the last path selected against all the path in the document.&lt;br /&gt;
&lt;br /&gt;
The algorithm first checks that the number of node points are the same. Then checks that the node commands match. If the commands match it will then do a correlation against the point positions. This allows the match to catch even those paths that have been scaled, rotated or flipped. The correlation threshold allows the match to be tuned. A 1.0 will match only those paths that haven't been transformed. There is also a check box to match on color or not. &lt;br /&gt;
&lt;br /&gt;
Please leave comments and suggestions.&lt;br /&gt;
&lt;br /&gt;
The Find Match inx file&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;inkscape-extension&amp;gt;&lt;br /&gt;
  &amp;lt;_name&amp;gt;Find Match&amp;lt;/_name&amp;gt;&lt;br /&gt;
  &amp;lt;id&amp;gt;org.find_match&amp;lt;/id&amp;gt;&lt;br /&gt;
  &amp;lt;dependency type=&amp;quot;executable&amp;quot; location=&amp;quot;extensions&amp;quot;&amp;gt;findmatch.py&amp;lt;/dependency&amp;gt;&lt;br /&gt;
  &amp;lt;dependency type=&amp;quot;executable&amp;quot; location=&amp;quot;extensions&amp;quot;&amp;gt;inkex.py&amp;lt;/dependency&amp;gt;&lt;br /&gt;
  &amp;lt;param name=&amp;quot;foundLayer&amp;quot; type=&amp;quot;string&amp;quot; _gui-text=&amp;quot;Name of layer to put found objects on?&amp;quot;&amp;gt;Found&amp;lt;/param&amp;gt;&lt;br /&gt;
  &amp;lt;param name=&amp;quot;threshold&amp;quot; type=&amp;quot;float&amp;quot; min=&amp;quot;0.0&amp;quot; max=&amp;quot;1.0&amp;quot; _gui-text=&amp;quot;Correlation Threshold&amp;quot;&amp;gt;0.8&amp;lt;/param&amp;gt;&lt;br /&gt;
  &amp;lt;param name=&amp;quot;matchcolor&amp;quot;    type=&amp;quot;boolean&amp;quot; _gui-text=&amp;quot;Colors should match&amp;quot;&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;
  &amp;lt;effect&amp;gt;&lt;br /&gt;
    &amp;lt;object-type&amp;gt;all&amp;lt;/object-type&amp;gt;&lt;br /&gt;
    &amp;lt;effects-menu&amp;gt;&lt;br /&gt;
       &amp;lt;submenu _name=&amp;quot;Examples&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/effects-menu&amp;gt;&lt;br /&gt;
  &amp;lt;/effect&amp;gt;&lt;br /&gt;
  &amp;lt;script&amp;gt;&lt;br /&gt;
    &amp;lt;command reldir=&amp;quot;extensions&amp;quot; interpreter=&amp;quot;python&amp;quot;&amp;gt;findmatch.py&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/inkscape-extension&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The python file for Find Match&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&lt;br /&gt;
'''&lt;br /&gt;
This program is free software; you can redistribute it and/or modify&lt;br /&gt;
it under the terms of the GNU General Public License as published by&lt;br /&gt;
the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
(at your option) any later version.&lt;br /&gt;
&lt;br /&gt;
This program is distributed in the hope that it will be useful,&lt;br /&gt;
but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
GNU General Public License for more details.&lt;br /&gt;
&lt;br /&gt;
You should have received a copy of the GNU General Public License&lt;br /&gt;
along with this program; if not, write to the Free Software&lt;br /&gt;
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA&lt;br /&gt;
'''&lt;br /&gt;
import sys&lt;br /&gt;
sys.path.append('/usr/share/inkscape/extensions')&lt;br /&gt;
&lt;br /&gt;
# We will use the inkex module with the predefined Effect base class.&lt;br /&gt;
import inkex&lt;br /&gt;
from simplestyle import *&lt;br /&gt;
from simplepath import *&lt;br /&gt;
from math import sqrt&lt;br /&gt;
&lt;br /&gt;
color_props_fill=('fill:','stop-color:','flood-color:','lighting-color:')&lt;br /&gt;
color_props_stroke=('stroke:',)&lt;br /&gt;
color_props = color_props_fill + color_props_stroke&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def correlation(xList,yList):&lt;br /&gt;
    #print yList&lt;br /&gt;
    n = len(xList)&lt;br /&gt;
    sumX = 0&lt;br /&gt;
    sumXX = 0&lt;br /&gt;
    sumY = 0&lt;br /&gt;
    sumYY = 0&lt;br /&gt;
    sumXY = 0&lt;br /&gt;
    for i in range(0,n):&lt;br /&gt;
    	X = xList[i]&lt;br /&gt;
        sumX += X&lt;br /&gt;
        sumXX += X*X&lt;br /&gt;
        Y = yList[i]&lt;br /&gt;
        sumY += Y&lt;br /&gt;
        sumYY += Y*Y&lt;br /&gt;
        sumXY += X*Y&lt;br /&gt;
    corrnum = (n * sumXY)-(sumX * sumY)&lt;br /&gt;
    corrden = sqrt( (n * sumXX) - (sumX * sumX) ) * sqrt( (n * sumYY) - (sumY * sumY) )&lt;br /&gt;
    corr = corrnum/corrden&lt;br /&gt;
    return corr&lt;br /&gt;
&lt;br /&gt;
def pathMatch(rPath,cPath):&lt;br /&gt;
    n = len(rPath)&lt;br /&gt;
    for i in range(0,n):&lt;br /&gt;
        rNode = rPath[i]&lt;br /&gt;
        cNode = cPath[i]&lt;br /&gt;
        [rCmd,rPoints] = rNode&lt;br /&gt;
        [cCmd,cPoints] = cNode&lt;br /&gt;
        if rCmd != cCmd:&lt;br /&gt;
            #print &amp;quot;not match&amp;quot;&lt;br /&gt;
            return 0&lt;br /&gt;
    #print &amp;quot;Command Match&amp;quot;&lt;br /&gt;
    return 1&lt;br /&gt;
    &lt;br /&gt;
def pathPullPoints(rPath,cPath):&lt;br /&gt;
    n = len(rPath)&lt;br /&gt;
    rPointList = []&lt;br /&gt;
    cPointList = []&lt;br /&gt;
    for i in range(0,n):&lt;br /&gt;
        rNode = rPath[i]&lt;br /&gt;
        cNode = cPath[i]&lt;br /&gt;
        [rCmd,rPoints] = rNode&lt;br /&gt;
        [cCmd,cPoints] = cNode&lt;br /&gt;
        rPointList.extend(rPoints)&lt;br /&gt;
        cPointList.extend(cPoints)&lt;br /&gt;
    return [rPointList,cPointList]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def getLayer(svg, layerName):&lt;br /&gt;
    for g in svg.xpath('//svg:g', namespaces=inkex.NSS):&lt;br /&gt;
        if g.get(inkex.addNS('groupmode', 'inkscape')) == 'layer' \&lt;br /&gt;
            and g.get(inkex.addNS('label', 'inkscape')) \&lt;br /&gt;
            == layerName:&lt;br /&gt;
            return g&lt;br /&gt;
    # Create a new layer.&lt;br /&gt;
    newLayer = inkex.etree.SubElement(svg, 'g')&lt;br /&gt;
    newLayer.set(inkex.addNS('label', 'inkscape'), layerName)&lt;br /&gt;
    newLayer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')&lt;br /&gt;
    return newLayer&lt;br /&gt;
&lt;br /&gt;
def compareColors(refNode, compNode):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
def getColor(node):&lt;br /&gt;
    col = {}&lt;br /&gt;
    if 'style' in node.attrib:&lt;br /&gt;
        style=node.get('style') # fixme: this will break for presentation attributes!&lt;br /&gt;
        if style!='':&lt;br /&gt;
            #inkex.debug('old style:'+style)&lt;br /&gt;
            styles=style.split(';')&lt;br /&gt;
            for i in range(len(styles)):&lt;br /&gt;
                for c in range(len(color_props)):&lt;br /&gt;
                    if styles[i].startswith(color_props[c]):&lt;br /&gt;
                        #print &amp;quot;col num %d&amp;quot; % c&lt;br /&gt;
                        #print styles[i][len(color_props[c]):]&lt;br /&gt;
                        col[c] =  styles[i][len(color_props[c]):]&lt;br /&gt;
    return col&lt;br /&gt;
    &lt;br /&gt;
def colorMatch(rNode,cNode):&lt;br /&gt;
    rCol = getColor(rNode)&lt;br /&gt;
    #print rCol&lt;br /&gt;
    cCol = getColor(cNode)&lt;br /&gt;
    #print cCol&lt;br /&gt;
    if rCol == cCol:&lt;br /&gt;
        return 1&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class FindMatch(inkex.Effect):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Inkscape effect extension.&lt;br /&gt;
    Searches for paths that match and places them on the named layer.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Constructor.&lt;br /&gt;
        Defines the &amp;quot;--what&amp;quot; option of a script.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        # Call the base class constructor.&lt;br /&gt;
        inkex.Effect.__init__(self)&lt;br /&gt;
          &lt;br /&gt;
        self.OptionParser.add_option('-f', '--foundLayer', action = 'store',&lt;br /&gt;
          type = 'string', dest = 'foundLayer', default = 'Found',&lt;br /&gt;
          help = 'Name of layer to put found objects on?')&lt;br /&gt;
&lt;br /&gt;
        self.OptionParser.add_option(&amp;quot;-t&amp;quot;, &amp;quot;--threshold&amp;quot;,&lt;br /&gt;
                        action=&amp;quot;store&amp;quot;, type=&amp;quot;float&amp;quot;, &lt;br /&gt;
                        dest=&amp;quot;threshold&amp;quot;, default = 0.8,&lt;br /&gt;
                        help=&amp;quot;threshold for correlation match&amp;quot;)&lt;br /&gt;
        self.OptionParser.add_option(&amp;quot;--matchcolor&amp;quot;,&lt;br /&gt;
                        action=&amp;quot;store&amp;quot;, type=&amp;quot;inkbool&amp;quot;, &lt;br /&gt;
                        dest=&amp;quot;matchcolor&amp;quot;, default=True,&lt;br /&gt;
                        help=&amp;quot;If True, colors will be matched&amp;quot;) &lt;br /&gt;
                        &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def effect(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Effect behaviour.&lt;br /&gt;
        Search for all paths that match the selected path&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        foundLayer = self.options.foundLayer&lt;br /&gt;
        matchcolor = self.options.matchcolor&lt;br /&gt;
&lt;br /&gt;
        # Get access to main SVG document element &lt;br /&gt;
        svg = self.document.getroot()&lt;br /&gt;
        &lt;br /&gt;
        # get the layer where the found paths will be moved to&lt;br /&gt;
        layer = getLayer(svg, foundLayer)&lt;br /&gt;
        &lt;br /&gt;
        # get a list of all path nodes&lt;br /&gt;
        pathNodes = self.document.xpath('//svg:path',namespaces=inkex.NSS)&lt;br /&gt;
&lt;br /&gt;
        # setup stderr so that we can print to it for debugging        &lt;br /&gt;
        saveout = sys.stdout&lt;br /&gt;
       &lt;br /&gt;
        sys.stdout = sys.stderr&lt;br /&gt;
        &lt;br /&gt;
        rPathLen = 0&lt;br /&gt;
        rPathList = []&lt;br /&gt;
        rPathNode = None&lt;br /&gt;
        &lt;br /&gt;
        if len(self.selected) == 0:&lt;br /&gt;
            print &amp;quot;Nothing Selected&amp;quot;&lt;br /&gt;
            sys.stdout = saveout&lt;br /&gt;
            return&lt;br /&gt;
        &lt;br /&gt;
        for id, node in self.selected.iteritems():&lt;br /&gt;
            #print dir(node)&lt;br /&gt;
            if node.tag == inkex.addNS('path','svg'):&lt;br /&gt;
                #print node.attrib['d']&lt;br /&gt;
                rPathList = parsePath(node.attrib['d'])&lt;br /&gt;
                rPathLen = len(rPathList)&lt;br /&gt;
                rPathNode = node&lt;br /&gt;
                #print rPathLen&lt;br /&gt;
                #print rPathList&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
        for cPathNode in pathNodes:&lt;br /&gt;
            cPathList = parsePath(cPathNode.attrib['d'])&lt;br /&gt;
            cPathLen = len(cPathList)&lt;br /&gt;
            #print cPathLen&lt;br /&gt;
            #print cPathList&lt;br /&gt;
            if rPathLen == cPathLen:&lt;br /&gt;
                #print &amp;quot; Found %d in %s&amp;quot; % (rPathLen,cPathNode)&lt;br /&gt;
                &lt;br /&gt;
                #print matchcolor&lt;br /&gt;
                colorMatchFlag = colorMatch(rPathNode,cPathNode) == 1 or not matchcolor&lt;br /&gt;
                pathMatchFlag = pathMatch(rPathList,cPathList)==1&lt;br /&gt;
                &lt;br /&gt;
                if pathMatchFlag and colorMatchFlag:&lt;br /&gt;
                    [rList,cList] = pathPullPoints(rPathList,cPathList)&lt;br /&gt;
                    corVal = correlation(rList,cList)&lt;br /&gt;
                    #print &amp;quot;The correlation was %g&amp;quot; % corVal&lt;br /&gt;
                    if corVal &amp;gt; 0.80:&lt;br /&gt;
                        layer.append(cPathNode)&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        #print &lt;br /&gt;
        #print 'This message will be logged instead of displayed'&lt;br /&gt;
        sys.stdout = saveout &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Create effect instance and apply it.&lt;br /&gt;
effect = FindMatch()&lt;br /&gt;
effect.affect()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Comments==&lt;br /&gt;
&lt;br /&gt;
: I can't say it really works for me:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Unknown option: --&lt;br /&gt;
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...&lt;br /&gt;
Try `python -h' for more information.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also had to fix extension namespace for trunk. Basically, the first line was replaced with&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;inkscape-extension xmlns=&amp;quot;http://www.inkscape.org/namespace/inkscape/extension&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
--[[User:Prokoudine|Prokoudine]] 23:51, 7 January 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
</feed>