Notes on Stoking Lines

Or the Arcane Art of Stoking

Last updated 1 October 2015

How is a line stroked? That seems like such a basic question that it surely must be answered in the SVG specification. But it's not. One can look to PostScript for a hint as that was one of the inspirations for SVG. The PostScript reference has little to say about exactly how to stroke a line. What it does say is regurgitated in the PDF 1.7 reference (page 231), adding only a comment on stroking zero length line segments. Here is the relevant text extract from the PDF spec:

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 sub-paths is treated separately. The results of the S operator depend on the current settings of various parameters in the graphics state (see Section 4.3, “Graphics State,” for further information on these parameters):

Hmm, that doesn't help too much.

Here are some possible ways of stroking:

  1. Take a line segment of length 'stroke-linewidth', place it at the start of a path so it is centered on and orthogonal to the path and then stroke it along the path till the end of the path. Any point that the line crosses is filled as part of the stroke. This appears to be what the PDF reference says to do.
  2. Take a circle of radius 'stroke-linewidth'/2.0, center it on the start of the path, and then stroke it along the path until you reach the end. At the start and end of the path, remove the hemisphere that sticks out past the path (if the 'line-endcap' type is 'butt'). This should be equivalent to the previous method.
  3. Calculate two paths, one one each side of the path with an offset of 'stroke-linewidth'/2.0 from the path. Connect the two start points and the two end points of these paths and the fill the enclosed region. This appears to be what Cairo and Adobe Reader do. It is not equivalent to the previous methods as it leaves holes in the path if the path curvature is small near the ends.

Normal stroking

The gray shows the result of stroking the red path with a 'stroke-width' of 40px. As this is an SVG file, results will differ between browsers.

Firefox: Stroking seems to be done according to option "1".

Chrome: Stroking seems to be done according to option "3".

Opera (Presto): Stroking seems to be done according to option "3".

Inkscape: Stroking seems to be done according to option "3". Inkscape relies on Cairo for path stroking.

Batik: Stroking seems to be done according to option "3".

Acroread: Stroking seems to be done according to option "1".

Evince: Stroking seems to be done according to option "3".

Here the offset paths are explicitly shown.

The blue paths show the offset paths as calculated.

Stroking with a dash pattern

The gray shows the result of stroking the red path with a 'stroke-width' of 40px and a 'stroke-dasharray' of '3 1'. As this is an SVG file, results will differ between browsers.

Chrome, Opera (Presto), and Squiggle all render the dashed stroke the same. Firefox and Inkscape render it the same.

Chrome.

Firefox.

Other considerations

It is useful to look at other paths. For example, there seems to be consistency between renderers when the stroke self-overlaps in the middle of the path.

The gray shows the result of stroking the red path with a 'stroke-width' of 40px. Top to bottom: Two straight lines; two path segments smoothly connected; one Bezier curve. As this is an SVG file, results may differ between browsers; however, most (all?) browsers agree on the rendering.

Stroke alignment presents another set of problems.

Stroking with 'stroke-alignment' value 'right'. The original paths are show in red. Top: The blue paths show the "raw" offset path. Bottom: The desired result.