draw freely
Back to Inkscape.org
September 19, 2015

Inkscape Tutorials

Creating and editing PDFs in Inkscape is pretty simple. This quick tip will cover the basics of saving your Inkscape SVG to a PDF, as well as using Inkscape’s PDF import functionality. Saving to PDF Once you have your document... Continue Reading →

September 19, 2015 05:00 AM

September 16, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { } div.figure p { font-size: 14px; } pre { font-size: 14px; } ol.circled { list-style: symbols("\2776" "\2777" "\2778" "\2779" "\277A" "\277B" ); font-family: "Inconsolata"; font-size: 14px; }

Part 1 introduced SVG filter primitives and demonstrated the creation of a Fabric filter effect. Part 2 shows various ways to colorize the fabric. It ends with an example of using the techniques learned here to draw part of a bag of coffee beans.

Dying the Fabric

Our fabric at this point is white. We can give it color a variety of ways. We could have started off with a colorized pattern but that would not allow us to change the color so easily. And as this is a tutorial on using filters, lets look at ways the color can be changed utilizing filter primitives.

Coloring with the Flood, Blend, and Composite Primitives

We can use the Flood filter primitive to create a sheet of solid color and then use the Blend filter primitive to combine it with the fabric. The resulting image bleeds into the background. We’ll use the Composite filter primitive to auto-clip the background.

The Flood Filter Primitive

Add the Flood filter primitive to the filter chain by selecting Flood and clicking on the Add Effect button. The fabric will turn a solid black. Like the Turbulence filter primitive, the Flood filter primitive takes no inputs but simply fills the filter region with a solid color Black is the default flood color. You can change the color by clicking on the color sample next to Flood Color: in the dialog. Change the color however you wish. Leave the Opacity at one.

The Blend Filter Primitive.

Next add the Blend filter primitive. The drawing will be unchanged. Connect the Blend input to the last Displacement Map. The fabric should appear on top of the flood fill. This is expected as the default blending mode is Normal which simply draws the second image over the first. Use the drop-down menu to change the Mode to Multiply. This results in the lighter areas of the fabric taking on the flood color.

The output of the filter chain after blending.

Try experimenting with the other blending modes.

The Composite Filter Primitive

The flood fill leaks into the background. This can be removed by clipping the image to fabric area using the Composite filter primitive. Add the Composite filter primitive to the filter chain. The resulting image is again unchanged. Connect the second input to the composite filter to the last Displacement Map filter primitive. Still the image remains unchanged. Now change the Operator type to In. This dictates that the image should be clipped to the area that is “In” the image created by the second Displacement Map filter primitive.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the Flood, Blend, and Composite filter primitives.

The output of the filter after compositing.

Coloring the Fabric with the Component Transfer Filter Primitive

The Component Transfer filter primitive maps, pixel by pixel, the colors from an input image to different colors in an output image. Each “component” (Red, Green, Blue, and Alpha) is mapped independently. The method for mapping is determined by the Type; each Type has its own attributes. We’ll use the Linear and Identity mappings.

The output component has the same value as the input component.
The output component is equal to: intercept &plus input × slope. This is identical to the Identity type if the intercept is zero and the slope is one.

Replace the Flood Fill, Blend, and Composite filter primitives in the above filter chain by the Composite Transfer filter primitive. (To delete a filter primitive, right-click on the filter primitive name and select Delete in the menu that appears.) The just removed three-primitive filter chain mapped black to black and white to the flood color. We can duplicate this by setting the Red, Green, and Blue component transfer types to Linear (keeping the Alpha component type set to Identity). The condition that black maps to black requires that the Intercept values all be set to zero. The condition that white maps to the flood color dictates the slopes. The RGB values for the flood color used above are 205, 185, 107 on a scale where 255 is the maximum value. These values translate to 0.80, 0.73, 0.42 on a scale where the maximum value is one. Since an input value of 1.0 for the red component must result in a value of 0.80 we can see that these values are the required slopes.

Graph of input vs. output for the red, green, and blue channels.

Graph of the transfer functions.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the Component Transfer filter primitive.

The output of the filter after adding and adjusting the Component Transfer filter primitive.

Now suppose we want the fabric to be more subtle. We can change the mapping so that for each component, zero is mapped to half the maximum value. In this case we have the following values (RGB): Intercepts: 0.40, 0.36, 0.21 and Slopes: 0.40, 0.37, 0.21. See the following figure:

Graph of input vs. output for the red, green, and blue channels.

Graph of the transfer functions where the darkest value is half the lightest value.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the Component Transfer filter primitive.

The output of the filter after adjusting the Component Transfer filter primitive so the darkest areas have half the component values of the lightest.

Coloring the Fabric with the Color Matrix Filter Primitive

This filter primitive, unlike the Component Transfer, can intermix the color components. It does not, however, have the fine control over the transfer curves like in the Component Transfer filter primitive. There are several Types in this filter primitive. The Saturate, Hue Rotate, and Luminous to Alpha types are shortcuts for the more generic Matrix type. We need to use the Matrix type to match the results of the previous filters.

First replace the Component Transfer filter primitive by the Color Matrix filter primitive. After adding the new primitive, the fabric may disappear; that is a bug in Inkscape. Click on the matrix in the Filter Dialog and the fabric should reappear. The initial matrix is the Identity matrix (consisting of ones on the diagonal) which does not change the image.

The rows in the matrix control the output of, from top to bottom, the Red, Green, Blue, and Alpha channels. The columns correspond to the input, again in the same Red, Green, Blue, and Alpha order. The last column allows one to enter a constant offset for the row. For example, one can make a green object red by changing the top row to “0 1 0 0 0″ which means that the Red channel output is 0×R + 1×G + 0×B + 0×A + 0, where R, G, B, and A are the input values for the Red, Green, Blue, and Alpha channels respectively (on a scale of zero to one).

To change the values in the matrix, click first on a row of numbers to select the row and then click on a numeric entry in the row. The following figures show the values needed to match the fabric samples above.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the Color Matrix filter primitive to match the first (high contrast) fabric sample above.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the Color Matrix filter primitive to match the second (lower contrast) fabric sample above.

Coloring the Fabric Using the Fill Color and the Tile Filter Primitive

In an ideal world, a fabric filter would just take as input the color of an object and use that to blend with a pattern. SVG filters do have the ability to do this. One would read in a pattern tile using the Image filter primitive and then tile the pattern using the Tile filter primitive. But the Tile filter primitive is the one filter primitive that Inkscape hasn’t implemented. While more convenient, this method would still lack the fine control over color that the above methods have.

The output of a filter using the Tile primitive. The two rectangles differ only in Fill color. Renders correctly in Chrome, incorrectly in Firefox and Inkscape.

Putting it All Together

Let’s do something with the fabric! We could stencil some text on the fabric to make it look like part of a bag of coffee beans. The best way to do this is to break the filter up into two separate filters. The first will distort the weave (using the first Turbulence and Displacement Map pair and color the fabric while the second will add a gentle wave to both the fabric and text (using the second Turbulence and Displacement Map pair). The text is given its own filter to take away the sharp edges and to also give it a bit of irregularity independent of the weave. The text could be blended on top of the fabric by giving it an opacity of less than one. A better effect can be achieved, however, by using the new mix-blend-mode property. Inkscape can render this property but does not yet have a GUI to set it. Firefox supports this property and Chrome should soon (if it doesn’t already). I’ve used the mix-blend-mode value of multiply by adding the property to the text style attribute with the XML editor. The fabric and text are then grouped together before applying the “wave” filter to the group.

Part of a bag of coffee beans. Three filters are used. The first to distort the weave and give color to the fabric, the second to slightly blur and distort the text, and the third to take the blended together fabric and text and give them both a gentle wave.

Note, it is possible to put the text in the “defs” section and use the Image filter primitive to import the text into a filter so that the blending can be done with the Blend filter primitive. This isn’t easy to do in Inkscape and Firefox seems to have problems rendering it.

I hope you enjoyed this tutorial. Please leave comments and questions!

A section of a bag of coffee beans.

A PNG image just for Google+ which doesn’t support SVG images.

September 16, 2015 12:54 PM

Inkscape Tutorials

Ever needed to design a space ship for a game project or some other reason? Look no further than this two-part tutorial from the 2D art for game programmers blog.

The first part of the tutorial focuses on designing the basic shape and outline of the ships using basic shapes and objects in Inkscape.


The second part then instructs you on the best way of completing the details of your ships and shading and colouring them. As with most of the tutorials in the 2D Art blog, these tutorials outline the basic workflows involved in creating the artwork, and less on which buttons to actually press when creating.


September 16, 2015 09:51 AM

September 11, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { } div.figure p { font-size: 14px; } pre { font-size: 14px; } ol.circled { list-style: symbols("\2776" "\2777" "\2778" "\2779" "\277A" "\277B" ); font-family: "Inconsolata"; font-size: 14px; }

Part 1 introduces SVG filter primitives and demonstrates the creation of a Fabric filter effect. Part 2 shows various ways to colorize the fabric.


SVG filters allow bitmap-type manipulations inside a vector format. Scalability is preserved by pushing the bitmap processing to the SVG renderer at the point when the final screen resolution is known. SVG filters are very powerful, so powerful in fact that they have been moved out of SVG and into a separate CSS specification so that they can also be applied to HTML content. This power comes with a price: SVG filters can be difficult to construct. For example, a simple drop shadow filter consists of three connected filter primitives as shown in this SVG code:
<filter id="DropShadow">
  <feOffset in="SourceAlpha" dx="2" dy="2" result="offset"/>  ❶
  <feGaussianBlur in="offset" stdDeviation="2" result="blur"/>  ❷
  <feBlend in="SourceGraphic" in2="blur" mode="normal"/>  ❸
  1. Offset filter primtive: Create an image using the text alpha (SourceAlpha) and shift it down and right two pixels. Results in shifted black text.
  2. Gaussian Blur filter primitive: Blur result of previous step (“offset”).
  3. Blend filter primtive: Render the original image (SourceGraphic) over the result of the previous step (“blur”).
Some sample text!

A drop shadow applied to text.

Inkscape contains a Filter Dialog that can be used to construct filters. Here is the dialog showing the above drop-shadow filter effect:

Filter dialog showing the three filter primitives and how they are connected.

The Inkscape Filter Dialog showing a drop-shadow filter effect. The dialog shows the filter primitives and how their inputs (left-pointing triangles) are connected (black lines). It also contains controls for setting the various filter primitive attributes.

There can be more than one way to construct the same filter effect. For example, the order of the offset and blur primitives can be swapped without changing the result:

Some more text!

An alternative drop-shadow filter applied to text.

Inkscape contains over 200 canned filters effects, many of which have adjustable parameters. But sometimes none of them will do exactly what you want. In that case you can construct your own filter effect. It’s not as hard as it first seems once you understand some of the basic filter primitives.

A Fabric Filter

This tutorial creates a basic filter that can be applied to a pattern to create realistic fabric. It will introduce several very useful filter primitives that are fundamental to most of Inkscape’s canned filter effects.

Creating a Pattern

To begin with, we need a pattern that is the basis of the weave of the fabric. I’ve constructed a simple pattern consisting of four rectangles, two for the horizontal threads and two for the vertical threads. I’ve applied a linear gradient to give them a 3D look. One can certainly do better but as the pattern tile is quite small, one need not go overboard. Once you have drawn all the pattern parts, select them and then use Objects->Pattern to convert to a pattern. The new pattern will then be available in the Pattern drop-down menu that appears when the Pattern icon is highlighted on the Fill tab of the Fill and Stroke dialog.

The pattern consisting of four rectangles with linear gradients simulating a small section of the fabric weave.

The pattern (shown scaled up).

Next, apply the fabric pattern to the an object to create simple fabric.

The basic weave pattern applied to a large rectangle.

The pattern applied to a large rectangle.

Adding Blur

The pattern looks like a brick wall. It’s too harsh for fabric. We can soften the edges by applying a little blur. This is done through the Gaussian Blur filter primitive. Open the Filter Editor dialog (Filters->Filter Editor). Click on the New button to create a new, empty filter. A new filter with the name “filter1″ should be created. You can double click on the name to give the filter a custom name. Apply the filter to the fabric piece by selecting the piece and then checking the box next to the filter name. Your piece of fabric will disappear; don’t worry. We need to add a filter primitive to get it to show back up. To add a blur filter primitive select Gaussian Blur in the drop-down menu next to Add Effect and then clicking the Add Effect button. The fabric should now be visible with the blur effect applied. You can change the amount of blur by using the slider next to Standard Deviation; a value of 0.5 seems to be about right.

Filter Dialog image.

The Filter Effect dialog after applying a small amount of blur.

Note how the input to the Gaussian Blur primitive (triangle next to “Gaussian Blur”) is linked (under Connections) to the Source Graphic.
The basic weave pattern applied to a large rectangle.

A small amount of blur applied to the fabric.

Distorting the Threads

The pattern is still too rigid. The threads in real fabric are not so regular looking. We need to add some random distortions. To do so, we’ll link up two different filter primitives. The first filter primitive, Turbulence, will generate random noise. This noise will be used as an input to a Displacement Map filter primitive where pixels are shifted based on the value of the input.

The Turbulence Filter Primitive

Add a Turbulence filter primitive to the filter chain by selecting Turbulence from the drop-down menu next to Add Effect button, the click on the button. You should see a rectangle region filled with small random dots. There are a couple of things to note: The first is that the rectangle will be bigger than you initial object. This is normal. The filter region is enlarged by 10% on each side and the Turbulence filter fills this region. This is done on purpose as some filter primitives draw outside the object (e.g. the Gaussian Blur and Offset primitives). You can set the boundary of the filter region under the Filter General Settings tab. The default 10% works for most filters. You don’t want the region to be too large as it effects the time to render the filter. The second thing to note is that the Turbulence filter primitive has no inputs despite what is shown in the Filter Editor dialog.

There are a number of parameters to control the generation of the noise:

There are two values: Turbulence and Fractal Noise. The difference between the two is somewhat technical so I won’t go into it here. (See the Turbulence Filter Primitive section in my guide book.)
Base Frequency
This parameter controls the granularity of the noise. The value roughly corresponds to the inverse of the length in pixels of the fluctuations. (Note that the default value of ‘0’ is a special case and doesn’t follow this rule.)
The number of octaves used in creating the turbulence. For each additional octave, a new contribution is added to the turbulence with the frequency doubled and the contribution halved compared to the proceeding octave. It is usually not useful to use a value above three or four.
The seed for the pseudo-random number generator used to create the turbulence. Normally one doesn’t need to change this value.

One can guess that variations in the threads are about on the order of the distance between adjacent threads. For the pattern used here, the vertical threads are 6 pixels apart. This gives a base frequency of about 0.17 (i.e. 1/6). The value of Type should be changed to Fractal Noise. (Both Type values give good visual results but the Turbulence value leads to a shift of the image down and to the right for technical reasons.) Here is the resulting dialog:

Filter Dialog image.

The Filter Effect dialog after adding the Turbulence filter primitive.

And here is the resulting image:

The output of the first turbulence filter primitive.

The output of the filter chain which is at this point the output of the Turbulence filter primitive.

The Displacement Map Filter Primitive

Now we need to add the Displacement Map filter primitive which will take both the output of the Gaussian Blur and the Turbulence filter primitives as inputs. Select Dispacement Map from the drop-down menu and then click on the Add Effect button. Note that both inputs to the Dispacement Map filter primitive are set to the last filter primitive in the filter chain. We’ll need to drag the top one to the Gaussian Blur filter primitive. (Start the drag in the little triangle at the right of the filter primitive in the list.) Again, the image doesn’t change. We’ll need to make one more change but first here are the parameters for the Displacement Map filter primitive:

The scale factor is used to determine how far pixels should be shifted. The magnitude of the shift is the value of the displacement map (on a scale of 0 to 1) multiplied by this value.
X displacment
Determines which component (red, green, blue, alpha) should be used from the input map to control the x displacement.
Y displacement
Determines which component (red, green, blue, alpha) should be used from the input map to control the y displacement.

For our purpose, any values of X displacement and Y displacement are equally valid as all channels contain the same type of pseudo-random noise. To actually see a shift, one must set a non-zero scale factor. A value of about six seems to give a good effect.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the Displacement Map filter primitive.

And here is the resulting image:

The output of the first turbulence filter primitive.

The output of the filter chain after adding and adjusting the Displacement Map filter primitive.

Distorting the Fabric

Fabric rarely lies flat unless stretched and even then it is hard to make the threads lie straight and parallel. We can add a random wave to the fabric by adding another Turbulence and Displacement Map pair, but this time using a lower Base Frequency. Repeat the instructions above to add the two filter primitives but this time connect the top input to the Displacement Map to the previous Displacement Map. Set the Base Frequency to a value of 0.01. Set the Type to Fractal Noise. Set the Scale to ten.

Filter Dialog image.

The Filter Effect dialog after adding and adjusting the second Turbulence and Displacement Map filter primitives.

And here is the resulting image:

The final fabric image.

The output of the filter chain after distorting the fabric.

Of course, the pattern and filter can be applied to an arbitrary shape:

The pattern and filter applied to a blob.

The pattern and filter applied to a cloth patch.


We have constructed a basic Fabric filter but there is plenty of room for improvement. In the next part we’ll look at ways to add color to the fabric.

A section of a bag of coffee beans.

A PNG image just for Google+ which doesn’t support SVG images.

September 11, 2015 09:22 AM

July 27, 2015

Kees Cook

I helped print this statue of Edgar Allan Poe, through “We the Builders“, who coordinate large-scale crowd-sourced 3D print jobs:

Poe's Face

You can see one of my parts here on top, with “-Kees” on the piece with the funky hair strand:

Poe's Hair

The MakerWare I run on Ubuntu works well. I wish they were correctly signing their repositories. Even if I use non-SSL to fetch their key, as their Ubuntu/Debian instructions recommend, it still doesn’t match the packages:

W: GPG error: http://downloads.makerbot.com trusty Release: The following signatures were invalid: BADSIG 3D019B838FB1487F MakerBot Industries dev team <dev@makerbot.com>

And it’s not just my APT configuration:

$ wget http://downloads.makerbot.com/makerware/ubuntu/dists/trusty/Release.gpg
$ wget http://downloads.makerbot.com/makerware/ubuntu/dists/trusty/Release
$ gpg --verify Release.gpg Release
gpg: Signature made Wed 11 Mar 2015 12:43:07 PM PDT using RSA key ID 8FB1487F
gpg: requesting key 8FB1487F from hkp server pgp.mit.edu
gpg: key 8FB1487F: public key "MakerBot Industries LLC (Software development team) <dev@makerbot.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
gpg: BAD signature from "MakerBot Industries LLC (Software development team) <dev@makerbot.com>"
$ grep ^Date Release
Date: Tue, 09 Jun 2015 19:41:02 UTC

Looks like they’re updating their Release file without updating the signature file. (The signature is from March, but the Release file is from June. Oops!)

© 2015, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.
Creative Commons License

July 27, 2015 11:08 PM

June 23, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { } div.figure p { font-size: 10px; } I’ve just landed basic font features support in the development version of Inkscape. What are font features and why should you be excited? (And maybe why should you not be too excited.)

The letter combination 'st' shown without a ligature and with a 'historical' ligature.

Font Features

Font features support allows one to enable (or disable) the OpenType tables within a given font, allowing you to select alternative glyphs for rendering text.
A series of examples showing the same text with and without applying various OpenType tables.

A sample of font features in action. The font is Linux Biolinum which has reasonable OpenType tables. Try the SVG (with WOFF).

The new CSS Fonts Module Level 3 adds a variety of CSS properties for defining which OpenType tables to enable/disable (as well as having nice examples of each property’s use — this is one of the more readable W3C specifications). Inkscape trunk supports the ‘font-variants-liguatures’, ‘font-variant-caps’, ‘font-variant-numeric’, ‘font-variant-position’, and ‘font-feature-settings’ properties. The properties can be set under the Variants tab in the Text and Font dialog.
The 'Variants' Tab in the 'Text and Fonts' dialog showing a series of buttons to select which font features are enabled.

The Variants tab in the Text and Font dialog.

Why you shouldn’t be too excited

Being able to enable various font features within a font is quite exciting but there are quite a few caveats at the moment:
  • One must use a trunk build of Inkscape linked with the latest unstable version of Pango (1.37.1 or greater).
  • Font feature support in fonts is usually minimal and often buggy. It’s hard to know what OpenType tables are available in which fonts.
  • Browser support is sparse. Firefox has rather good support. Chrome support seems limited to ligatures.
  • Correct display of alternative glyphs requires that the same font as used in content creation is used for rendering. On the Web the best way to do this is to use WOFF but Inkscape has no support for using User fonts (this is a future goal of Inkscape but will require considerable work).


I would like to thank: Behdad Esfahbod, maintainer of Pango for adding the code to Pango to make accessing the OpenType tables possible. Thanks as well to Matthias Clasen and Akira Togoh who are the source of the patch to Pango. Thanks also to all the people that supported the Inkscape Hackfest in Toronto where I was able to meet and discuss Pango issues with Behdad in person and also where the idea of adding font feature support to Inkscape germinated.

June 23, 2015 11:55 AM

May 22, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { } div.figure p { font-size: 10px; } Google has recently announced their intention to drop SMIL support in Blink, the rendering engine for Chrome. SMIL is a way to animate SVG’s in a declarative way. Google’s argument is that SMIL animation has not become hugely popular and that Web Animations will provide the same functionality. As a result of this announcement, the SVG working group decided to move SMIL from SVG 2 and into its own specification. One could say that SMIL is on life support at the moment. SMIL’s lack of use is most likely due to its lack of support in IE. Microsoft has declared they will not implement SMIL in IE but they have hinted in the past that they are open to a native JS implementation built on top of Web Animations. So why would losing SMIL be a great loss?

  1. SMIL declarative animations are easier to write compared to JavaScript or CSS/Web Animations.
  2. SMIL animations are in general more performant.
  3. With SMIL animations one can independently animate different attributes and properties.
  4. JavaScript is not allowed to run inside SVGs in many situations due to security issues so it is not a viable alternative in many cases.
  5. Web Animations don’t replace all the functionality of SMIL. For example, one cannot animate attributes including paths. In particular you won’t be able to do this:
Morphing Batman logos.

A variety of Batman logos, animated with SMIL.

Ironically, YouTube is planning on using SMIL to animate buttons. As usual, if you are reading this in a blog aggregator and the images don’t display correctly, try viewing on my blog website. Aggregators don’t play well with SVG. (For more on animating paths, see my blog post on path animations.) You can read about Google’s intention and the debate that is going at the chromium.org Google group. If you use SMIL or plan to, let Google know that it is important to you.
A figure just to have a nice image in Google+ (which doesn’t do SVG… another reason to frown):
Frown face.

May 22, 2015 09:15 AM

April 29, 2015

Inkscape Tutorials

Today’s tutorial is yet another awesome little tutorial from the 2D Game Art for programmers blog that demonstrates a simple technique to illustrate the rings around Saturn.

The process itself is pretty straight forward using circles and boolean operations to make your rings, and then deforming the object with the on-canvas skew handles. Well worth a read for beginner and intermediate inkscapers.


2D Game Art for Programmers: Rings of Saturn.

April 29, 2015 10:11 AM

April 13, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { width: 80%; } div.figure p { font-size: 10px; } Path stroking and offsetting are two intertwined topics; stroking is often implemented by path offsetting. This post explores some of the problems encountered with these path operations.

Stroking: It’s not as easy as it looks.

What could be easier that stroking a path? It’s a fundamental concept in all graphics libraries. You construct a path: in PostScript:
100 100 moveto
150 100 lineto
10 setlinewidth
in SVG:
<path d="M 100,100 150,100" stroke-width="10"/>
and voila, you have a horizontal path, 50 pixels long, that is 10 pixels wide. Hmm, if only it were that easy. It turns out that stroking an arbitrary path can be quite complicated. Different graphics libraries can give quite different results.
A simple Bezier path segment with high curvature at one end.

A Bezier path segment with high curvature at the end. Web browsers differ on the rendering. (SVG)

Firefox's rendering of the circle. It appears solid. Chome's rendering of the circle. It appears like a donut.

Rendering of above path: Firefox (left/top), Chrome (right/bottom). (PNG)

There are two different ways to stroke a path. The first method is to pass a line segment of length ‘stroke-width’, centered on and perpendicular to the path, from one end to the other. Any pixels the line crosses are part of the stroke. This seems to be what Firefox does. (An equivalent method is to pass a circle of diameter ‘stroke-width’ centered on the path and then clip the semi-circles at the ends.) The second method is to construct two paths, offset by half the ‘stroke-width’ on each side of the original path and then fill the area between the two paths. This seems to be what Chrome does.
A simple Bezier path segment with high curvature at one end.

A Bezier path segment with high curvature at the end. Stroke constructed by offsetting path. Red: original path, blue: offset paths. (SVG)

Rendering engines appear to fall into one of these two camps:
Sweep a line:
Firefox, Adobe Reader
Offset paths:
Chrome, Inkscape (Cairo), Opera (Presto), Evince, Batik, rsvg
The difference can be also be seen in circular paths.
Two circular paths with strokes of different widths.

Two same size circular paths with different stroke widths. When one-half the stroke width exceeds the circle radius (right circle), web browsers differ in their rendering. (SVG)

Firefox's rendering of the circle. It appears solid. Chome's rendering of the circle. It appears like a doughnut.

Rendering of a circular path when one-half the stroke width is greater than the radius in: Firefox (left/top), Chrome (right/bottom). (PNG)

When using the Offset paths method, an inner path is always created. As the direction of this path is the same regardless of the stroke width, one cannot differentiate between the case where the stroke width is less than one-half the radius and the case where it is not. This can be seen in the animation below:
Two circular paths with strokes of different widths. The drawing of the stroke is animated.

Stroking the path. The arrows indicate the direction of the offset paths. If the drawing is not animated, view the image by itself. (SVG)

Interestingly, some renderers draw a filled circle when one-half the ‘stroke-width’ is greater than the radius for an SVG <circle> (i.e. not a circular <path>) while others still draw a doughnut. However, for the SVG <rect> element, the rectangles are always drawn filled if the ‘stroke-width’ is greater than either the ‘width’ or ‘height’ (at least in the renderers I tested). So what does the SVG specification say about how to stroke a path? Nothing…! One can look to PostScript and PDF on which SVG is partially based for a hint on what it should say. The PostScript and PDF specifications say the same thing. From the PDF 1.7 reference:

The S operator paints a line along the current path. The stroked line follows each straight or curved segment in the path, centered on the segment with sides parallel to it. Each of the path’s subpaths is treated separately…

This seems to indicate that the sweeping the line technique is what is expected and indeed, Adobe’s own product, Adobe Reader, appears to do just that.

Stroke Alignment

Designers often want more control over how a stroke is positioned: only on the inside, only on the outside, or some arbitrary ratio of the two. The new SVG ‘stroke-alignment‘ property offers this control. For a closed path, it is relatively easy to figure out how this property should behave:
A figure eight path showing various methods for offsetting.

Top: the original path. Middle: left: stroke inside; right: stroke outside. Bottom: left: stroke to left; right: stroke to right.

For an open path, it is not quite so easy. What is inside, what is outside? One can define the terms by looking at what is filled: inside is in the fill, outside is not in the fill. With this definition, a single straight line segment would render nothing for an ‘inside’ stroke and a stroke on both sides for an ‘outside’ stroke. The SVG specification has a slightly different definition for ‘outside’ (see figure). For an open path it may make more sense to talk about left/right rather than inside/outside.
A figure eight path showing various methods for offsetting.

Top to bottom: Default stroke. Fill area (in gray). Inside (according to SVG specification?). Outside (implemented here by masking). Inside (another interpretation). Outside (according to SVG specification?). Stroke on left (round end cap in pink).

Handling line joins is fairly straight forward. End caps, at least ’round’ ones, are another matter. Does one draw half an end cap? Or does the radius of the end cap match the width of the (shifted) stroke?
Left: straight lines, right: curved lines.

Round end caps. Top to bottom: Default stroke. Stroke alignment ‘outside’, end-cap radius doubled. Stroke alignment ‘outside’, end-cap radius same as normal.

The ‘stroke-alignment’ property was recently removed from the SVG 2 specification draft and moved into a separate SVG Strokes module, partly due to the difficulty in specifying exactly how it should behave. The ‘stroke-alignment’ ‘inside’/’outside’ values can be simulated via other methods. The new ‘paint-order‘ property allows one to paint the stroke before the fill and thus simulating stroking only the outside of the path (this only works for opaque fill). A mask can also be used to simulate stroking the outside of path. A clip path can be used to simulate stroking the inside of a path.

Offset Paths

We’ve seen that offsetting a path can be used for constructing strokes. What about offsetting a path for the purpose of creating a new path? This is quite useful in mapping. For example you might want to show multiple bus routes going along a road with different offsets for each route. More stylistically, you could produce the shadowing seen around land masses in older, hand-drawn maps.
Section of map showing lines ringing a group of islands.

An excerpt from a submarine cable map showing the use of offset paths to shade around land masses. Note also the use of inside strokes to define country boundaries.

Offsetting paths is in practice extremely tricky! Here are a few of the problems:
  1. Offsets of Bezier segments are not Beziers; in fact they are 10th-order polynomials. In practice, one can do a pretty good job of estimating the offset by breaking up a Bezier path into smaller segments.
  2. Offset paths can have loops at cusps.
  3. Offset paths may require breaking apart left and right offset paths and recombining to form outset and inset paths. It can be difficult to get this right.
Entire scientific papers are written on this topic.[1] Here is a simple example path with offsets both inside and outside:
Path with a series of offsets.

Left: insets, right: outsets. Red path is original.

In this case, the outsets correspond to the outer edge of a stroked path with appropriate width when the ‘stroke-linejoin’ type is ’round’. The insets correspond to the inner edge of such strokes. Taking a closer look at the offset paths shows a number of cusp loops:
Complex path with offsets.

The same original path as in the above figure. Left: the light blue region is created by stroking the original path. As can be seen it matches the corresponding outset (blue) and inset (green) paths. Right: The raw offset paths used to construct the visible outset and inset paths. In this case, the outset path is constructed from the raw outset path (blue) and the inset path is constructed from the raw inset path (green). Cusp loops and overlaps have been removed.

Determining what is outset or inset becomes more difficult as a path loops back on itself. Both the outset and inset paths can consist of parts of both the right-offset and left-offset paths as shown below:
A path that loops back on itself three times.

Left: The left-offset path (blue) and the right-offset path (green), relative to the path’s direction (clock-wise). Right: The resulting outset path (blue) and inset path (green).

Here’s an example where Inkscape’s Linked Offset function gets it wrong:
A circular path segment on top of a figure eight segment.

The resulting outset path (blue) and inset path (green) as found by Inkscape’s Linked Offset function.

The previous examples assumed that the line joins for outside joins are rounded. It would be desirable to be able to specify the type of join to use. This can maintain the feel of the original path.
A triangle path with 's' shaped sides with various offsets.

Left: Outset path with three different types of joins: ‘bevel’, ’round’, and ‘arcs’. Right: Outset paths with various offsets and with the ‘arcs’ line join. Note: the ‘arcs’ line join fails for the outer most path as the generated arcs do not intersect; this results in falling back to a ‘miter’ line join.

Allowing more freedom to define stroke position and being able to offset strokes are highly desirable features for designers, but as this post shows, they are not so simple to implement. Before we can add such features to SVG, we need to define robust algorithms for generating proper offset paths.


  1. An offset algorithm for polyline curves Xu-Zheng Liu, Jun-Hai Yong, Guo-Qin Zheng, Jia-Guang Sun.
An image for the sole purpose of having a good PNG image to show in Google+ which doesn’t support SVG images, bad Google+. Complex path with offsets.

April 13, 2015 12:20 PM

February 27, 2015

Inkscape Tutorials

This April, developers of Inkscape are meeting up to hold a hackfest, where they will spend 3 solid days planning for the future of Inkscape, fixing bugs, and adding new features to Inkscape.

How can you help? Donate to help cover the cost of getting the developers together so they can make Inkscape better!

February 27, 2015 08:00 PM

February 24, 2015

Ryan Lerch

After a 6-month hiatus, I have finally gotten the GIMP 2.9.1 development builds working again for Fedora 21. These development builds are built from the upstream git master branch of what will be GIMP 2.10 when it is released.

Check out the COPR page for these builds for futher details on enabling and installing from this repo, but also note that this is an experimental repo of unstable software, so tread cautiously.

The one major feature that is of most interest is the ability to do image manipulations with 32bit float precision; which is possible in version 2.9.1 of GIMP via the power of GEGL.


February 24, 2015 08:11 PM

February 20, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { } div.figure p { font-size: 10px; } The SVG Working Group had a four day face-to-face meeting in Sydney this month. The first day was a joint meeting with the CSS Working Group. I would like to thank the Inkscape board for funding my travel. This was an expensive trip as I was traveling from Paris and Sydney is an expensive city… but I think it was well worth it as the SVG WG (and CSS WG, where appropriate) approved all of my proposals and worked through all of the issues I raised. Unfortunately, due to the high cost of this trip, I have exhausted the budgeted funding from Inkscape for SVG WG travel this year and will probably miss the two other planned meetings, one in Sweden in June and one in Japan in October. We target the Sweden meeting for moving the SVG 2 specification from Working Draft to Candidate Recommendation so it would be especially good to be there. If anyone has ideas for alternative funding, please let me know. Highlights:

A summary of selected topics, grouped by day, follows:

Joint CSS and SVG Meeting

  • SVG sizing in HTML.

    We spent some time discussing how SVG should be sized in HTML. For corner cases, the browsers disagree on how large an SVG should be displayed. There is going to be a lot work required to get this nailed down.

  • CSS Filter Effects:

    We spent a lot of time going through and resolving the remaining issues in the CSS Filter Effects specification. (This is basically SVG 1.1 filters repackaged for use by HTML with some extra syntax sugar coating.) We then agreed to publish the specification as a Candidate Recommendation.

  • CSS Blending:

    We discussed publishing the CSS Blending specification as a Recommendation, the final step in creating a specification. I raised a point that most of the tests assumed HTML content. It was requested that more SVG specific test be created. (Part of the requirement for Recommendation status is that there be a test suite and that two independently developed renderers pass each test in the suite.)

  • SVG in OpenType, Color Palettes:

    The new OpenType specification allows for multi-colored SVG glyphs. It would be nice to set those colors through CSS. We discussed several methods for doing so and decided on one method. It will be added to the CSS Fonts Level 4 specification.

  • Text Rendering:

    The ‘text-rendering‘ property gives renderers a hint on what speed/precision trade-offs should be made. It was pointed out that the layout of text flowed into a box will change as one zooms in and out on a page in Firefox due to font-hinting, font-size rounding, etc. The Google docs people would like to prevent this. It was decided that the ‘geometricPrecision’ value should require that font-metrics and text-measurement be independent of device resolution and zoom level. (Note: this property is defined in SVG but both Firefox and Chrome support it on HTML content.)

  • Text Properties:

    Text in SVG 2 relies heavily on CSS specifications that are in various states of readiness. I asked the CSS/SVG groups what is the policy for referencing these specs. In particular, SVG 2 needs to reference the CSS Shapes Level 2 specification in order to implement text wrapping inside of SVG shapes. The CSS WG agreed to publish CSS Shapes Level 2 as a Working Draft so we can reference it. We also discussed various technical issues in defining how text wraps around excluded areas and in flowing text into more than one shape.

SVG Day 1

  • CamelCase Names

    The SVG WG decided some time ago to avoid new CamelCase names like ‘LinearGradient’ which cause problems with integration in HTML (HTML is case insensitive and CamelCase SVG names must be added by hand to HTML parsers). We went through the list of new CamelCase names in SVG 2 and decided which ones could be changed, weighing arguments for consistency against the desire to not introduce new CamelCase names. It was decided that <meshGradient> should be changed to <mesh>. This was mostly motivated by the ability to use a mesh as a standalone entity (and not only as a paint server). Other changes include: <hatchPath> to <hatchpath>, <solidColor> to <solidcolor>, …

  • Requiring <foreignObject> HTML to be rendered.

    There was a proposal to require any HTML content in a <foreignObject> element to be rendered. I pointed out that not all SVG renderers are HTML renderers (Inkscape as an example). It was decided to have separate conformance classes, one requiring HTML content to be rendered and one not.

  • Requiring Style Sheets Support:

    It was decided to require style sheet support. We discussed what kind of style sheets to require. We decided to require basic style sheet support at the CSS 1 or CSS 2.1 level (that part of the discussion was not minuted).

  • Open Issues:

    We spent considerable time going through the specification chapter by chapter looking at open issues that would block publishing the specification as a Candidate Recommendation. This was a long multi-day process.

SVG Day 2


Note: Day 2 and Day 3 minutes are merged.

  • Superpaths:

    Superpaths is the name for the ability to reuse path segment data. This is useful, for example, to define the boundary between two shapes just once, reusing the path segment for both shapes. SVG renderers might be able to exploit this information to provide better anti-aliasing between two shapes knowing they share a common border. The SVG WG endorses this proposal but it probably won’t be ready in time for SVG 2. Instead, it will be developed in a separate Path enhancement module.

  • Line-Join: Miter Clipped:

    It was proposed on the SVG mailing list that there be a new behavior for the miter ‘line-join’ value in regards to the ‘miter-limit’ property. At the moment, if a miter produces a line cap that extends farther than the ‘miter-limit’ value then the miter type is changed to bevel. This causes abrupt jumps when the angle between the joined lines changes such that the miter length crosses over the ‘miter-limit’ value (see demo). A better solution is to clip the line join at the ‘miter-limit’. This is done by some rendering libraries including the one used on Windows. We decided to create a new value for ‘line-join’ with this behavior.

  • Auto-Path Closing:

    The ‘z’ path command closes paths by drawing a line segment to the first point in the path. This is fine if the path is made up of straight lines but becomes problematic if the path is made up of curves. For example, it can cause rendering problems for markers as there will be an extra line segment between the start and end of the path. If the last point is exactly on top of the first point, one can remove this closing line segment but this isn’t always possible, especially if one is using the relative path commands with rounding errors. A more detailed discussion can be found here. We decided to allow a ‘z’ command to fill in missing point data using the first point in the path. For example in: d=”m 100,125 c 0,-75 100,-75 100,0 c 0,75 -100,75 z” the missing point of the second Bezier curve is filled in by the first point in the path.

  • Text on a Shape:

    An Inkscape developer has been working on putting text on a shape by converting shapes to paths while storing the original shape in the <defs> section. It would be much easier if SVG just allowed text on a shape. I proposed that we include this in SVG 2. This is actually quite easy to specify as we have already defined how shapes are converted to paths (needed by markers on shapes and putting dash patterns on shapes). A couple minor points needed to be decided: Do we allow negative path offsets? (Yes) How do we decide which side of a path the text should be put? (A new attribute) The SVG WG approved adding text on a shape to SVG 2.

  • Marker knockouts, mid-markers, etc:

    A number of new marker features still need some work. To facilitate finishing SVG 2 we decided to move them to a separate specification. There is some hesitation to do so as there is fear that once removed from the main SVG specification they will be forgotten about. This will be a trial of how well separating parts of SVG 2 into separates specifications works. The marker knockout feature, very useful for arrowheads is one feature moved into the new specification. On day 3 we approved publishing the new Markers Level 1 specification as a First Public Working Draft.

  • Text properties:

    With our new reliance on CSS for text layout, just what CSS properties should SVG 2 support? We don’t want to necessarily list them all in the SVG 2 specification as the list could change as CSS adds new properties. We decided that we should support all paragraph level properties (‘text-indent’, ‘text-justification’, etc.). We’ll ask the CSS working group to create a definition for CSS paragraph properties that we can then reference.

  • Text ‘dx’, ‘dy’, and ‘rotate’ attributes:

    SVG 1.1 has the properties ‘dx’, ‘dy’, and ‘rotate’ attributes that allow individual glyphs to be shifted and rotated. While not difficult to support on auto-wrapped text (they would be applied after CSS text layout), we decided that they weren’t really needed. They can still be used on SVG 1.1 style text (which is still part of SVG 2).

SVG Day 3


Note: Day 3 minutes are at end of Day 2 minutes.

  • Stroking Enhancements:

    As part of trying to push SVG 2 quickly, we decided to move some of the stroking enhancements that still need work into a separate specification. This includes better dashing algorithms (such as controlling dash position at intersections) and variable width strokes. We agreed to the publication of SVG Strokes as a First Public Working Draft.

  • Smoothing in Mesh Gradients:

    Coons-Patch mesh gradients have one problem: the color profile at the boundary between patches is not always smooth. This leads to visible artifacts which are enhanced by Mach Banding. I’ve discussed this in more detail here. I proposed to the SVG WG that we include the option of auto-smoothing meshes using monotonic-bicubic interpolation. (There is an experimental implementation in Inkscape trunk which I demonstrated to the group.) The SVG WG accepted my proposal.

  • Motion Path:

    SVG has the ability to animate a graphical object along a path. This ability is desired for HTML. The SVG and CSS working groups have produced a new specification, Motion Path Module Level 1, for this purpose. We agreed to publish the specification as a First Public Working Draft


February 20, 2015 06:53 AM

February 06, 2015

Ryan Lerch

Corebird 0.9 was released a few months ago, and it is now finally available in the official Fedora repos. Check out my previous post for details on some of the new features in this update.

Update via the Software application in Fedora, or on the command line with yum or dnf.



February 06, 2015 09:33 PM

February 04, 2015

Inkscape Tutorials

Here is a neat written tutorial (with a bonus video tutorial too) on creating a cartoony style scroll with Inkscape.

The result of this tutorial would make a great image for your asset library or as a video game element.


February 04, 2015 04:18 AM

February 03, 2015

Ryan Lerch

Now that Inkscape 0.91 is now released, I have done a bit of housecleaning and moved the Inkscape Development builds for Fedora into a new COPR called inkscape-devel.

The version numbers for these builds are a little different from what I have done in the past, and now are more in line with the upstream way of naming these builds. The development versions now have a version number of 0.91+devel. This may mean that you have to remove older versions of devel builds from the older repos I did before using these repos.


February 03, 2015 05:37 PM

Inkscape Tutorials

Inkscape 0.91 has only been out for a few days, and tutorials that cover some of the new features are already being published. One of the new features in Inkscape 0.91 is the new Trace Pixel Art feature that allows you to take a PNG or some other bitmap of pixel art and trace it neatly into vector objects.

Aaron from GoInkscape! has just posted an awesome little tutorial on how to use this new 0.91 feature.


February 03, 2015 07:53 AM

Learn how to create simple isometric blocks and create a scene.

Here is workflow tutorial on creating a simple isometric block using inkscape, and then using that block to make a little landscape scene. AS with most of the tutorials on the 2D game art blog, it is fairly sparse on low-level inkscape instructions, mainly just showing the workflow to achieve this look.

February 03, 2015 05:58 AM

January 30, 2015

Ryan Lerch

So excited that the new version of Inkscape is now finally out! I have been using development versions of Inkscape 0.91 for over a year now, and it is packed full of useful new features and improvements.

The updated package for Fedora should be hitting the repos soon, but the builds are available in koji if you can’t wait and want to install directly from there. I also did a writeup about the release for Fedora Magazine outlining some of the features that I use on a daily basis in Inkscape 0.91.



January 30, 2015 10:49 PM

This is a little render I recently did of the GNOME Builder robot by Jimmac using the Blender Freestyle renderer.

January 30, 2015 07:35 PM

Earlier this week, the Inkscape upstream made the final tarballs available for the long-awaited new 0.91 version of Inkscape. This version has not been announced by upstream yet, but thanks to the awesome Fedora Inkscape package maintainer Limb, this version is now available for testing on Fedora 21. Please try it out, and give karma to the package in Bodhi.

This updated package is the next major release of Inkscape after the 0.49 version of Inkscape that was released several years ago.

This major update provides many additional features and enhancements as well as hundreds of bug fixes and stability improvements. A detailed list of the new features in this version of Inkscape is available in the upstream release notes

Some of the notable new features in Inscape 0.91 include:

  • A new measurement tool that allows the artist to measure distances and angles in their drawing in realtime.
  • Updates to the text tool including the ability to customise the unit of measurement for text size, and support for choosing font style variants in the text toolbar.
  • The align and distribute dialog now features a new set of features that allow the user to exchange position of selected objects.
  • A new “Select Same” that allows an artist to select objects that have the same properties as the currently selected object. For example, you could select an object that has a fill of blue. Then, using the new feature select all other objects in the drawing with a fill set to that same shade of blue.
  • A new path effect, Power Stroke that allows you to easily create variable width strokes.
  • The Gradient view in the fill and stroke dialog now displays a list of all the gradients in the document. The list displays the gradient, the gradient name, and number of uses of that gradient in the document.
  • The new greyscale display mode that shows a preview of your drawing in greyscale.
  • Improved rendering performance with the new Cairo-based renderer, and the addition of multi-threaded rendering of SVG filters
  • A new feature in the node tool (targeted at type designers) that allows you to insert new nodes at the selected segments extreme values.

January 30, 2015 07:10 PM

Version 0.9 of Corebird is now in the updates-testing repo for Fedora 21 and Rawhide.

Please check it out, test and give karma!

This update makes this already awesome twitter client much better, with a bunch of updates, including:

  • Mentions, hashtags and links now get highlighted directly in the dialog where tweets are composed.
  • The avatar icon in the top left of the main Corebird window is now clickable. When clicked, every account configured in Corebird is displayed in a list, allowing a quicker way of switching accounts.
  • The dark theme setting in the Corebird user preferences is now removed. If you previously set the dark theme, it will continue to work, but is not really a supported feature of corebird, so the theme may render strangely. It is also still possible to turn the dark theme on or off using the GNOME dconf editor.
  • The arrow keys on the keyboard can now be used to navigate between images if a tweet has multiple images or videos attached.
  • Avatars in tweets and profiles now show if the user is a Twitter verified account.
  • Corebird now has a back button in the main window to easily navigate between panes.
  • Many tweaks to the user interface, including better spacing of elements in the user interface, and updated icons.

January 30, 2015 03:47 PM

Inkscape Tutorials


The Inkscape project just announced the availability of the next major version of Inkscape, version 0.91. It has been several years since the last major update of inkscape and version 0.91 comes packed with a bunch of new and exciting features, improved performance and many, many bugfixes.

Download it now at the Inkscape website.

January 30, 2015 07:21 AM

January 14, 2015

Kees Cook

I had a mess of loyalty cards filling my wallet. It kind of looked like this:

Loyalty cards, from Flickr, joelogon

They took up too much room, and I used them infrequently. The only thing of value on them are the barcodes they carry that identify my account with whatever organization they’re tied to. Other folks have talked about doing consolidation in various ways like just scanning images of the cards and printing them all together. There was a site where you typed in card details and they generated barcodes for you, too. I didn’t want to hand my identifiers to a third party, and image scanning wasn’t flexible enough. I wanted to actually have the raw numbers, so I ended up using barcode. I didn’t use the Debian nor Ubuntu package, though, since it lacked SVG support, which was added in the latest (cough March 2013) version.

I used the Android Barcode Scanner app, and just saved all the barcodes and their encoding details to a text file, noting which was which. For example:

Albertsons "035576322436","UPC_A"
Multnomah County Library "01237035218482","CODABAR"
Supportland "!0000005341632030145420","CODE_128"

I measured the barcode area, since some scanners can’t handle their expected barcodes being resized, (that’s another project: find out which CAN handle it), and then spat out SVG files. I compared the results to my actual cards, since some times encodings have different options (like dropping checksum characters, “-c” below):

barcode-svg -S -u in -g 1.5x0.5 -e upc-a      -b '035576322436' > albertsons.svg
barcode-svg -S -u in -g   2x0.5 -e codabar -c -b '01237035218482' > library.svg
barcode-svg -S -u cm -g 4.5x1   -e code128    -b '!0000005341632030145420' > supportland.svg

With Inkscape, I opened them all and organized them onto a wallet-card-sized area, printed it, and laminated it. Now my wallet is 7 cards lighter. More room for HID cards or other stuff:

Emergency Pick Card

© 2015, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.
Creative Commons License

January 14, 2015 01:33 AM

January 08, 2015


div.figure { padding: 5px; margin-bottom: 20px; text-align: center; background: #cccccc; } div.figure img { } div.figure p { font-size: 10px; } This post got delayed due to work on ‘units’ for the 0.91 Inkscape release followed by the holidays. The SVG Working Group had a two day meeting in Santa Clara as part of TPAC (the yearly meeting of all W3C working groups) at the end of October. This is an occasion to meet in person with other groups who have some shared interests in your group’s work. I would like to thank the Inkscape board for partially funding my attendance and W3C for waiving the conference fee. Here are some highlights of the meeting:

Day 1, Morning

Minutes The morning session was divided into two parts: the first part was an SVG only meeting while the second part was a joint meeting with the Task Force for Accessibility.
  • SVG blending when embedded via <img>:

    This is probably not a real interesting topic to readers of this blog other than it can give one a flavor of the types if discussions that go on inside the SVG working group. We spent considerable time debating if elements inside an SVG that are included into a web page by the HTML <img> tag should blend with elements outside the SVG (other than following the simple “painters model” where transparency is allowed). Recall that in SVG 2 (and CSS) it is possible to select blend modes using the ‘mix-blend-mode’ CSS property (see my blog post about blending). So the question becomes should objects like a rectangle (inside the SVG referenced by an <img> element) with a ‘mix-blend-mode’ value of say ‘screen’ blend with an image in the HTML page behind? We finally concluded that an author would expect an external SVG to be isolated and not blend with other objects in the HTML page.

  • Accessibility:

    The Accessibility Task Force asked to meet with us to discuss accessibility issues in graphics. Work has begun on SVG2 Accessibility API Mappings. An example of how accessibility can work with graphics can be found in a Surfin’ Safari blog post.

Day 1, Afternoon

Minutes The afternoon session was a joint meeting with the CSS working group.
  • Text Decoration

    CSS has expanded the possibilities of how text is decorated (underlines, over-lines, etc.) by adding three new properties in CSS Text Decorations Module Level 3. The new properties ‘text-decoration-line’ and ‘text-decoration-style’ are easy to adopt into SVG (and in fact are already read and rendered by Inkscape 0.91). The new property ‘text-decoration-color’ is more problematic. SVG has long supported separate ‘fill’ and ‘stroke’ properties on text which also applies to text decoration. By careful nesting of <tspan>’s one can have a different underline color from the text color. Furthermore, SVG allows various paints to be applied to the text decoration, like a gradent or pattern fill. The ‘text-decoration-color’ property allows the color of the text decoration to be set directly, without the need for nested <tspan>’s so it is a quite attractive idea but how to support the richness found in SVG?

    I proposed a number of solutions (see my presentation). The CSS group agreed that my favorite solution, that adding ‘text-decoration-fill’ and ‘text-decoration-stroke’ was the proper way to move forward. (BTW, the CSS working would like to eventually allow fill and stroke on HTML text.)

  • Fitting Text in a Box

    We’ve had numerous requests for the ability to adjust the size of text to fit it inside a given box (note, this is not the same as wrapping text into a shape). SVG has the attribute ‘textLength’ which allows a renderer to adjust the spacing or glyph width to match text to a given length. It was intended to allow renderers to adjust the length of a given text string to account for differences in font metrics if a the specified font wasn’t available; it was never intended to be an overall solution to fitting text inside a box, in fact the SVG 2 spec currently warns against using it in this way. I received a proposal from another Inkscape developer on expanding ‘textLength’ to be more useful in fitting text in a box. It seems to me that finding a solution to this problem would be of more general interest than just for SVG so I added this topic to the SVG/CSS agenda. I prepared a presentation to provide a starting point for the discussion.

    We had quite a lengthy discussion. The consensus seemed to be that CSS could use a set of simple knobs to make small adjustments to text, mostly for the purpose of labels. This would satisfy most use cases. Large adjustments could (should?) be the domain of script libraries. It was decided to solicit more feedback from users.

  • Image Rendering

    CSS Images 3 has co-opted the SVG ‘image-rendering‘ property and redefined in to specify what about an image is important to preserve when scaling as compared to a speed/accuracy trade off as in SVG 1.1. I prepared a short report on a couple of issues I found. The first is that the specification does not describe very well the meaning of the new ‘crisp-edges’ value. Tab Atkins, one of the spec’s authors has agreed to elaborate and add some figures to demonstrate what is intended. I found the Wikipedia section Pixel art scaling algorithms to be particularly enlightening on the subject.

    The second issue is that some browsers and Inkscape use the now deprecated ‘optimizeSpeed’ value to indicate that the nearest neighbor algorithm should be used for scaling. This is important when scaling line art. I asked, and Tab agreed, that ‘optimizeSpeed’ value should correspond to the new ‘pixelated’ value to not break existing content (and not ‘auto’ as is currently in the spec).

  • Connectors

    I’ve been working on a connectors proposal for SVG. There is renewed interest as being able to show relationships between elements would greatly aid accessibility. We even had a brief meeting with the HTML working group where it was suggested that connectors (possibly without visual links) may be of interest to aid accessibility of HTML. One problem I’ve had is how to reference ports inside a <symbol> element. I asked the CSS group for suggestions (this is obviously not a styling issue but the CSS group members are experts at syntax). Tab Atkins suggested: url(#AndGate1) Out, Mid1, Mid2, url(#AndGate2) InA, where, for example, Out is the point defined inside the symbol with the ‘id’ AndGate1.

Day 2

Minutes The SVG working group met for entire day covering a real hodge-podge of topics, some not well minuted. Here are a few highlights:
  • NVidia presentation.

    NVidia gave a quite impressive demonstration of their OpenGL extensions for rendering 2D vectors, (think SVG), showing an entire HTML web page from the New York Times being rotated and scaled in real time on their Tegra based Shield tablet with all the text rendered as vectors (they can render 700,000 paths per second). They are trying to get other vendors interested in the extensions but it doesn’t seem to be a high priority for them.

  • CTM Calculations

    For mapping applications, a precision of greater than single precision is necessary for calculating the Current Transformation Matrix (CTM) due to rounding errors. It was proposed and accepted that SVG dictate that such calculations be done as double precision (as Inkscape already does). (Note: single precision is sufficient for actual rendering.)

  • Going to Last Call Working Draft

    We discussed when we’ll get SVG 2 out the door. It is a very large specification with various parts in various stages of readiness. We decided to target the February face-to-face meeting in Sydney as the date we move to the next stage in the specification process… where no new features can be added and incomplete ones removed.

  • HTML in SVG

    There has been a desire by some for quite awhile to allow HTML directly inside SVG (not wrapped by a <foriegnElement> tag). I personally am quite hesitant to see this happen. SVG as at the moment a nice stand-alone graphics specification that doesn’t necessarily have to be rendered in a Web browser. Incorporating HTML would threaten this.

  • SVG in HTML

    This is the opposite of the previous topic, allowing SVG to be directly embedded in HTML without using a name space.

  • Non-scaling Patterns

    Just as it often useful to have non-scaling stroke widths (especially for technical drawings), it would also be useful to have non-scaling patterns and hatches. We agreed that this should be added to the specification.

  • Minimum Stroke Width

    It would be useful to have a minimum stroke-width so that certain strokes do not disappear when a drawing is scaled down. It was claimed that this will be handled by vector-effect but I don’t see how.

  • SVG in Industry

    It was mentioned that Boeing is moving all their 787 docs to SVG so they can be viewed in browsers.

Unfortunately, we ran out of time before we could cover some of my other topics: stroke-miterlimit, text on a shape, and auto-path closing.

January 08, 2015 01:59 PM

January 07, 2015

Inkscape Tutorials

Blender 2.73 was released today, and it contains an awesome new feature that allows you to export Blender Freestyle renders into SVG format that can be further edited in Inkscape. Blender is a free and open source 3D computer graphics application that is used for a wide range of different things, including 3D modeling and animation. One of the features in blender is a line based nonphotorealistic (NPR) rendering engine that can be used to create lineart-style stills and animations such as this render I created of the GNOME Builder robotic crane:

The new feature that was added to the Blender version 2.73 allows exporting of an SVG from a Freestyle render. This creates the ability to model a 3D object in blender, create a Freestyle render, export it to SVG, and then open it up in Inkscape to edit and tweak it further. Here is a sample frame I rendered of the GNOME Builder crane, after opening it in inkscape and fine-tuning all the paths and strokes, and playing with different colours:


January 07, 2015 07:57 PM

December 23, 2014



This post is more geared to Inkscape developers than Inkscape users. I hope that by recording my trials and tribulations here it can help others in their coding efforts. I have been working on adding support for ‘context-fill’ and ‘context-stroke’ to Inkscape. These magical ‘fill’ ans ‘stroke’ property values will allow Inkscape to finally match marker fill (e.g. arrowhead color) to path stroke (e.g. arrow tail) in a simple way. These new property values are part of SVG 2. Adding this support is a multi-step process. First one must be able to read the new values and then one must be able to apply the values. The former part is rather straight forward. It simply required modifying the SPIPaint class by adding a new ‘enum’ SPPaintOrigin with entries that keep track of where the paint originates. The previous ‘currentColor’ boolean has been incorporated into this new ‘enum’. The latter part proved to be much more of a challenge.

Where does the ‘apply’ code go?

The ‘context-fill’ and ‘context-stroke’ values are applicable to things that are cloned. The driving force for these values is certainly the <marker> element but <symbol> and <pattern> elements could also find the values useful as could anything cloned by the <use> element. For the moment, I concentrated on implementing the values in markers and things cloned by the <use> element. The first question that comes to mind is: Where in the code is styling applied? This turns out to not be best starting question for cloned objects. A better question is: How does the cloning take place? To answer this question I implemented three routines with the same name: recursivePrintTree(); but, as member functions of different classes: SimpleNode, SPObject, and DisplayItem. These represent different stages in Inkscape’s processing of an SVG document. Here are the findings:
XML Tree (SimpleNode)
The XML Tree matches the structure of the XML file with some extra elements possibly added by Inkscape such as <metadata> and <sodipodi:namedview>. This is the tree that is shown in the XML editor dialog. No cloning is evident.
Object Tree (SPObject)
The object tree is similar to the XML tree. Its main purpose is to handle the CSS styling which involves merging the various sources of styling (external style sheets (rect: {fill:red;}), styling properties (style=”fill:red”), and presentation attributes (fill=”red”), as well as handling all the necessary cascading of styles from parent to child. A few non-rendering elements are missing such as <RFD:rfd> and some new elements appear. Here is our first clue: the object tree includes the unnamed clones of elements created by the <use> element. It makes sense that they appear here. Cloned objects descending from a <use> element participate in the style cascading process. Marker clones, however, are no where to be seen.
Display Tree (DisplayItem)
The display (or rendering) tree includes only elements that will be rendered. All the styling has been worked out; all the placement and sizing of graphical items has been calculated. The metadata, the Inkscape editing data, and the <defs> section are all gone. But now clones of the markers appear, one clone for each node where a marker is placed, each containing the geometric data of position, scale, and orientation. This is a quite reasonable way to handle markers as each marker clone is identical to its siblings (at least until ‘context-fill’ and ‘context-stroke’ came along).
The above “tree” analysis gives the structure of each tree after it has been built, but doesn’t explain how each tree is created. This has ramifiations of how one can handle the ‘context-fill’ and ‘context-stroke’ values.

Creating the XML tree

There are a couple of ways to create the XML tree. The most common is via sp_repr_read_file(). This is used in SPDocument::createNewDoc() as well as routines to read in filters, templates, etc. Files opened by Inkscape from the command line use XSLT::open() which allows XSLT stylesheets to be applied to the SVG file (something I didn’t know we supported). Both functions call sp_repr_do_read() to read the actual files and both end up with an Inkscape::XML::Document.

Creating the object tree

Once the XML tree is created, it is passed to SPDocument::creatDoc() which builds the object tree top down via the recursive calling of SPObject::invoke_build() starting with the document root <svg> element. SPObject::invoke_build() calls the virtual function SPObject::build() which handles element specific things such as reading in attributes. Attributes are read by calling SPObject::readAttr() which performs a few checks before calling the virtual SPObject::set() function. The set() function for SPUse reads in ‘href’, the reference to the object to be cloned by the <use> element. Reading in the reference inserts a copy of the referenced object (the clone) into the object tree via SPUse::href_changed(). Markers are not cloned; only references to the marker elements are added at this step, in the SPShape::build() function.

Creating the display tree

The display tree is created by calling recursively SPItem::invoke_show() on the root object (SPItem, derived from SPObject, is for visible objects). This is done in SPDesktop::setDocument(). SPItem::invoke_show immediately calls the virtual function SPItem::show() which handles element specific things. (SPRoot::show() calls SPGroup::show() which calls SPGroup::_showChildren.) SPItem::show() creates an instance of an appropriate display class object that is derived from Inkscape::DrawingItem(). The virtual function DrawingItem::setStyle() is called to set the style information. One thing to note is that the a child is constructed (with styling) before adding it to the tree so a child’s style cannot be directly dependent on an ancestor in the tree. But ‘context-fill’ and ‘context-stroke’ need ancestor style information so we need to supply that in a different way. Markers are tracked by a map of vectors of pointers to Inkscape::DrawingItem instances. This map is stored in SPMarker. The map is indexed by a key for each type of marker (start, mid, end) on a particular path. The vector has an entry for each position along the path a marker is to be placed. The DrawingItem instances are created in a two step process from SPShape::show(). First a call to sp_marker_show_dimensions() ensures that the vector is of the correct size. Then a call to sp_shape_update_marker_view() calls sp_marker_show_instance() which creates a new Inkscape::DrawingItem instance if it doesn’t already exist.

Setting the style of a clone

As mentioned above, style is handled in the virtual function DrawingItem()::setStyle(). The DrawingShape and DrawingText setStyle() functions call NRStyle.set() where the work of translating the style information from the object tree form to the display tree form takes place (in the display tree, the styling information is in a form used by the Cairo rendering library). To handle ‘context-fill’ and ‘context-stroke’ we would like to walk up the display tree to find the style of the element that references the clone, i.e. the <use> element or the <path> or <shape> elements in the case of markers. But at the point the setStyle() function is called on an element in the clone, the clone has not yet been inserted into the display tree, so one cannot walk up the display tree. What we can do is hand two sets of styling information from the object tree to to the setStyle() function, the first being the stying information for the object at hand and the second being the styling information that should be used in the case of ‘context-fill’ and ‘context-stroke’. We know the later for the <use> element as its clone is in the object tree. All that is required is setting a pointer to the context style information in the SPUse class and then passing it down to its children. This solution doesn’t work for markers as their clones are not in the object tree. The solution for markers is calling a function that walks down the tree setting the correct styling information after the cloned marker elements are added to the display tree.

Future work

There are still quite a few things to be done. In particular, before we can switch to using ‘context-fill’ and ‘context-stroke’, as well as the ‘orient’ attribute value ‘auto-start-reverse’ (which allows us to handle both start and end arrows with just one marker) we’ll need a fallback solution for SVG 1.1 renderers. Here is a list of things to do:
  • Handle gradients and patterns.
  • Handle text (appendText()).
  • Export to SVG 1.1.
  • Redo markers.svg (source of markers in Inkscape).


All the code is now in trunk. To implement ‘context-fill’ and ‘context-stroke’, I added about 200 lines of code. I don’t know the exact amount of time it took, but I would guess a minimum of 20 hours. That works out to about 10 lines per hour… not very productive. The first part, reading in ‘context-stroke’ and ‘context-fill’ took about an hour. I am quite familiar with this part of the code, having C++ified the SPStyle and related classes and having implemented other new properties and property values. It was the second part that took so long. Although I have worked with parts of this code before, it was often quite opaque as to which code is doing what (and why). I ended up going down many false paths. There is a serious lack of comments and often confusing variable and function names (what the heck is an ‘arenaitem’?). A few comments at the appropriate places could have shaved up to 90% of the time it took. In this case, the different way markers and clones are handled required solving the same problem twice. When you begin a project, it is very hard to estimate the time it will take. I would have thought this project could be done in less than 5 hours, possibly in just a couple. It didn’t turn out that way. On the otherhand, implementing the new CSS property ‘paint-order’ which I thought would take considerable time, took only a couple of hours.

December 23, 2014 10:25 AM

December 10, 2014

Kees Cook

Needing a new car, and wanting to never purchase another gas-fuelled motor, I bought a Nissan LEAF. (Trivia: LEAF appears to be a backronym for “Leading, Environmentally friendly, Affordable, Family car”.)


This vehicle has effectively a 22kWh battery and goes maybe 80 miles on a charge, which is more than enough for running errands.

The 15-Amp (“Level 1″) EVSE (Electric Vehicle Supply Equipment) that comes with the LEAF plugs into a standard wall socket. It tells the car’s charger to draw only 12A, so it doesn’t pop the house’s circuit. This will fully charge the batteries in about 20 hours, which is not sufficient for daily use.


The thing on the end that plugs into the LEAF is the J1772 connector. You’ll note it is not just an extension cord, even though it feeds the car AC power. The EVSE communicates with the vehicle to negotiate a charging current. Then the LEAF’s on-board charger takes the AC the EVSE makes available, converts it to DC, and stores it in the batteries. (My model LEAF also has a second plug for DC fast charging, which uses an entirely different connector: CHAdeMO.)

Most folks with an Electric Vehicle end up installing a “Home Charger”. (Though calling it a “charger” is a misnomer since, as mentioned, the charger is in the car.) This is actually a “Level 2″ wall-mounted EVSE, which uses a dedicated high-amperage circuit. Like the Level 1, it has communication logic to do the protocol negotiation with the vehicle. However, the price of Level 2 EVSEs is crazy high (low-end $1000, high-end $3000), and that doesn’t even include the cost of getting the dedicated circuit run by an electrician.

To make matters worse, none of the standard EVSEs are Open Source, and only the high-end ones have remote access, etc. Luckily, I am hardly the first person to notice this, and since I’m so “late” to the EV world, there are several Open projects for building one’s own EVSE.

I went with OpenEVSE, since I can build it (so I understand all the components in the system), and I can change/improve the firmware (like adding a wifi board). Under Ubuntu, I was up and running after installing the arduino and avrdude packages.

Now I can charge from empty in under 8 hours, since the 30A unit charges at 24A nominal.


While I was at it, I 3D printed a socket to hold the J1772 plug when it’s not in the car.

J1772 Holder

© 2014 – 2015, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.
Creative Commons License

December 10, 2014 08:53 PM

November 17, 2014

Inkscape Tutorials

Here is a neat little workflow tutorial on creating a cartoon cactus using Inkscape. Most of the steps in this tutorial are pretty simple, using simple path manipulations, boolean operations and the circle tool to draw and simply shade your very own cactus.


November 17, 2014 03:33 PM

November 13, 2014

Inkscape Tutorials

Here is a tutorial on drawing a candle in a candle holder using Inkscape. Using basic inkscape fundamentals like the circle tool, the pencil tool and boolean operations, you will learn to draw this neat simple cartoon candle. In addition, you will learn how to edit your candle image to make a few frames that can be used to create an animation. (note that Inkscape itself cant do animation though)



November 13, 2014 02:25 AM

November 10, 2014

Inkscape Tutorials

Learn how to draw this adorable little pink elephant using inkscape. This a great tutorial to learn some of the basics of inkscape including the circle tool, using basic Boolean operations to create simple shading, and some creative use of the spiral tool to make the elephant’s trunk.


November 10, 2014 09:34 PM

November 09, 2014

Inkscape Tutorials

Here is a great tutorial for Inkscape on using gradients, blur and opacity to create a simple landscape scene with misty, cloudy hills in the background.hills

November 09, 2014 03:37 PM

In addition to the @inkscapetuts on twitter, the inkscape tutorials blog is now also on google+, and also on Facebook. Going forward, both the twitter, g+ and Facebook streams will be updated with all the new posts that show up here on the blog. So if you prefer to use either of those services, follow us there.

Speaking of google+, there is also the official inkscape google+ page, which features news and updates from the inkscape project. Also, there is the inkscape community on google+, that has tutorials, a gallery, and general inkscape posts and discussions.


November 09, 2014 02:51 PM

November 07, 2014

Inkscape Tutorials

Here is a super simple way of creating an egg shape oval using the Circle / Ellipse tool, and a little known feature of the Node Tool, called Node Sculpting.

Draw a circle

First up, use the circle / ellipse tool to draw a circle. Remember to hold down the control key on your keyboard to make sure it is a perfect circle.


Convert the circle to a path

Use the select tool to select your circle, and convert it to a path with Path > Object to Path. Now when you switch to the node tool, you will see your 4 nodes of your path.


Sculpt the Nodes

Using the Node Tool, select all the nodes in your circle path either by dragging a box around them, or using the keyboard shortcut Control + A. Now press the alt key on your keyboard, and click and drag the top node of the shape. Your simple egg shape is now complete!


Check out Tav’s book for more information on Node Sculpting

November 07, 2014 06:36 PM

Here is a super quick tutorial on how to draw pacman in inkscape. This tutorial is short and sweet, but is a great introduction on how to use the circle/arc tool in Inkscape.


November 07, 2014 05:55 PM

November 06, 2014

Inkscape Tutorials

Here is a 8-class lesson plan & curriculum by Máirín Duffy for teaching the basics of Inkscape to primary school children. (the class was specifically designed for teaching a US 7th grade class.) The course is themed around the students creating a logo for their fake rock band, and then creating different items based on that logo, such as posters and t-shirts.Each of the 8 lessons has a bunch of resources to run the class, including lesson plans, student handouts and exercise sheets to print out and give to the students during the lesson.

All the resources and course outline is available on this page. Máirín has already tested and run this class on a class of 7th graders, and blogged about the progress of each day — well worth a read too if you want to see how well this class performs in real life.

Even though this class is aimed at 7th graders, following along the course is also a great introduction to the basics of Inkscape for kids of all ages.

inkscape class


November 06, 2014 06:16 PM

Here is a neat two-part tutorial explaining how to draw a cute cartoon tractor. This tutorial has both written instructions and screencasts, so whatever your favourite way of consuming inkscape tutorials is, it should have you covered. The tractor that you learn how to draw in this tutorial is also featured in a neat little game that is currently being developed called Tractor Trample.


November 06, 2014 05:41 PM

November 04, 2014

Inkscape Tutorials

Have you ever noticed that in Inkscape when you have objects that are perfectly butted up against each other, that there is still a small gap rendered between them, exposing the background colour underneath?


Objects without space between, but gaps are still rendered.

This is a known issue with the way the SVG renderer in Inkscape does antialiasing, and there is even an Inkscape FAQ entry with a few ideas on how to workaround the issue.

However, I find that there is a simple workaround for this issue in a lot of cases. Simply group your objects together, and duplicate them twice:


One issue with this approach is that it doesn’t work very well if the objects you are using have any transparency, as you are duplicating objects below, which changes the way the top object looks. Also in drawings with many thousands of objects, duplicating them does tend to make inkscape a perform a lot slower. However in most cases, this technique works great as the finishing step in your workflow to remove the pesky gaps.

November 04, 2014 03:13 PM

November 03, 2014

Inkscape Tutorials

Here is another tutorial from , where you learn how to design a star-shaped badge motif with a bendy banner laid over the top. This tutorial is also a great explanation for different ways to put text on curves, bending paths with live path effects, and using the interpolate extension to easily make a line of the same objects.


November 03, 2014 09:31 PM

October 30, 2014

Inkscape Tutorials

After the tutorial last week on how to create rope with Inkscape, I was playing around with the technique outlined in the tutorial, and came up with a few vector rope assets that you all can now download and use. These three designs are all licensed CC0 1.0 Universal.That means they are all royalty free and free for both commercial and personal use without attribution.

These artworks will be great for use as a border or flourish in nautical, sailing and boating designs. Also suitable for cowboy and wild west style artwork, or anything that requires a rope or string design.

Rope border

Rope Border is an SVG vector clipart of rope in the shape of a rounded rectangle border.



Rope ring

Rope Ring is an SVG vector clipart of a single unbroken rope in a circle loop


Rope ring with a granny knot

Rope Ring with a granny knot is an SVG vector clipart of a single piece of rope tied in a circle loop by a granny knot at the bottom. Also known in heraldry as a Bourchier knot, the granny knot is visually similar to the reef knot, square knot or grief knot.


October 30, 2014 12:44 AM

October 28, 2014

Inkscape Tutorials

Here is a neat tutorial on creating a simple chat icon using inkscape by . It uses a lot of the essential basics of using inkscape, so some basic knowledge of Inkscape features is required, but


October 28, 2014 02:45 PM