Difference between revisions of "PythonEffectTutorial"

From Inkscape Wiki
Jump to navigation Jump to search
(Added more info to the first paragraph, some minor corrections)
(Replaced content with "[extensions under review]")
Tag: Replaced
 
(18 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Effect extensions in Inkscape means a simple programs or scripts that reads an SVG file from standard input, transforms it somehow and prints it to the standart output.  Usually Inkscape sits on both ends, providing the file with some parameters as input first and finally reading the output, which is then used for further work.
[extensions under review]
 
We will write a simple effect extension script in Python that will put "Hello World!" or "Hello <value of --what option>!" string in the center of document and inside a new layer.
 
== Effect Extension Script ==
 
First of all create a file ''hello_world.py'' and make it executable with the Python interpreter with the well-known directive:
 
<pre>
#!/usr/bin/env python
</pre>
 
If you're going to put the file somewhere else than into inkscape's installation directory, we need to add a path so that python can find the necessary modules:
 
<pre>
import sys
sys.path.append('/usr/share/inkscape/extensions') # or another path, as necessary
</pre>
 
Import ''inkex.py'' file with ''Effect'' base class that will do most of work for us and ''simplestyle.py'' module with support functions for working with CSS styles. We will use just the ''formatStyle'' function from this module.:
 
<pre>
import inkex
from simplestyle import *
</pre>
 
Declare ''HelloWordEffect'' class and write a constructor where the base class is initialized and script options for the option parser are defined:
 
<pre>
class HelloWorldEffect(inkex.Effect):
    def __init__(self):
        inkex.Effect.__init__(self)
        self.OptionParser.add_option('-w', '--what', action = 'store',
          type = 'string', dest = 'what', default = 'World',
          help = 'What would you like to greet?')
</pre>
 
The complete documentation for the ''OptionParser'' class can be found at http://docs.python.org/lib/module-optparse.html. Here we just use the ''add_option'' method which has as first argument a short option name, as second argument a long option name and then a few other arguments with this meaning:
 
* ''action'' - An action which should be done with option value. In this case we use action ''store'' which will store option value in ''self.options.<destination>'' attribute.
* ''type'' - Type of option value. We use string here.
* ''dest'' - Destination of option action specified by ''action'' argument. Using ''what'' value we say that we want to store option value to self.options.what attribute.
* ''default'' - Defalut value for this option if it is not specified.
* ''help'' - A help string that will be displayed if script will be given no arguments or some option or argument will have wrong syntax.
 
Inkscape will create a GUI form with widgets for all specified options and prefill them with specified default values using ''.inx''. file for this extenstion which we will write later.
 
We need to override only one ''Effect'' class method to provide effect functionality:
<pre>
    def effect(self):
        what = self.options.what
</pre>
 
As you can mention we just stored ''--what'' option value to ''what'' variable.
 
Now we will finally start to do something. We will work with XML representation of SVG document via ''self.document'' attribute. It is of ''Document'' class type from ''xml.dom'' module. Complete documentation for this module can be found at http://docs.python.org/lib/module-xml.dom.html.
 
First get SVG document ''svg'' element and its dimensions:
 
<pre>
        svg = self.document.getElementsByTagName('svg')[0]
        width = inkex.unittouu(svg.getAttribute('width'))
        height = inkex.unittouu(svg.getAttribute('height'))
</pre>
 
Function ''getElementsByTagName'' returns list of all found elements of this name so we just use first of them.
 
Create SVG group element and "convert" it to layer using Inkscape SVG extenstions:
 
<pre>
        layer = self.document.createElement('g')
        layer.setAttribute('inkscape:label', 'Hello %s Layer' % (what))
        layer.setAttribute('inkscape:groupmode', 'layer')
</pre>
 
Create SVG text element and its value containing "Hello World"" string:
 
<pre>
        text = self.document.createElement('text')
        value = self.document.createTextNode('Hello %s!' % (what))
</pre>
 
Set position of text to center of SVG document:
 
<pre>
        text.setAttribute('x', str(width / 2))
        text.setAttribute('y', str(height  / 2))
</pre>
 
If we want center text on its position we will define CSS style of SVG ''text'' element. Actually use ''text-anchor'' SVG extension to CSS styles to do that work:
 
<pre>
        style = {'text-align' : 'center', 'text-anchor' : 'middle'}
        text.setAttribute('style', formatStyle(style))
</pre>
 
Finally connect all created elements together and put them in SVG document:
 
<pre>
        text.appendChild(value)
        layer.appendChild(text)
        svg.appendChild(layer)
</pre>
 
We just defined a class of our effect extension so we have to create an instance of it and execute it in main control flow:
 
<pre>
effect = HelloWorldEffect()
effect.affect()
</pre>
 
== Extension Description File ==
 
To include script in Inkscape's main menu create ''hello_world.inx'' file describing script evokation.
 
<pre>
<inkscape-extension>
  <_name>Hello World!</_name>
  <id>org.ekips.filter.hello_world</id>
  <dependency type="executable" location="extensions">hello_world.py</dependency>
  <dependency type="executable" location="extensions">inkex.py</dependency>
  <param name="what" type="string" _gui-text="What would you like to greet?">World</param>
  <effect>
    <object-type>all</object-type>
    <effects-menu>
      <submenu _name="Examples"/>
    </effects-menu>
  </effect>
  <script>
    <command reldir="extensions" interpreter="python">hello_world.py</command>
  </script>
</inkscape-extension>
</pre>
 
Create ''<param>'' element for every option of a script and ''<dependency>'' for every included module which is not from Python standard library. Inkscape will search for this modules in directory with script. ''<effect>'' element and its descendants defines name of menu item evoking our new "Hello World!" extension.
 
If the inx file isn't well formed or if any of the dependencies wasn't met, the extension won't show up in the menu. If your extension doesn't show up, take a look at extension-errors.log, which may give you a hint why it wasn't loaded.
 
== Installation ==
 
To install a new extenstion just put ''hello_world.py'' and ''hello_world.inx'' files with all dependency modules  to ''<path_to_inkscape>/extensions'' or ''~/.inkscape/extensions'' directory and start Inkscape. A new menu item ''Hello World!'' in ''Effects->Examples'' menu should appear.
 
== Complete Source Code ==
 
Here is a complete commented source pre of ''hello_world.py'' script file:
 
<pre>
#!/usr/bin/env python
 
# These two lines are only needed if you don't put the script directly into
# the installation directory
import sys
sys.path.append('/usr/share/inkscape/extensions') # or another path, as necessary
 
# We will use inex module with predefined effect base class.
import inkex
# simplestyle module provides functions for style parsing.
from simplestyle import *
 
""" Example Inkscape effect extension.
Creates a new layer with "Hello World!" text centered in middle of document."""
class HelloWorldEffect(inkex.Effect):
    """ Constructor.
    Defines "--what" option of a script."""
    def __init__(self):
        # Call base class construtor.
        inkex.Effect.__init__(self)
 
        # Define string option "--what" with "-w" shortcut and default value "World".
        self.OptionParser.add_option('-w', '--what', action = 'store',
          type = 'string', dest = 'what', default = 'World',
          help = 'What would you like to greet?')
 
    """ Effect behaviour.
    Overrides base class' method and insert "Hello World" text in SVG document. """
    def effect(self):
        # Get script "--what" option value.
        what = self.options.what
 
        # Get access to main SVG document element and get its dimensions.
        svg = self.document.getElementsByTagName('svg')[0]
        width = inkex.unittouu(svg.getAttribute('width'))
        height = inkex.unittouu(svg.getAttribute('height'))
 
        # Create a new layer.
        layer = self.document.createElement('g')
        layer.setAttribute('inkscape:label', 'Hello %s Layer' % (what))
        layer.setAttribute('inkscape:groupmode', 'layer')
 
        # Create text element
        text = self.document.createElement('text')
        value = self.document.createTextNode('Hello %s!' % (what))
 
        # Set text position to center of document.
        text.setAttribute('x', str(width / 2))
        text.setAttribute('y', str(height  / 2))
 
        # Center text horizontally with CSS style.
        style = {'text-align' : 'center', 'text-anchor': 'middle'}
        text.setAttribute('style', formatStyle(style))
 
        # Connect elements together.
        text.appendChild(value)
        layer.appendChild(text)
        svg.appendChild(layer)
 
# Create effect instance and apply it.
effect = HelloWorldEffect()
effect.affect()
</pre>
 
[[User:Blackhex|Blackhex]] 11:59, 26 April 2007 (UTC)

Latest revision as of 04:07, 2 February 2020

[extensions under review]