Plottie: Driving a Silhouette Portrait plotter/cutter

Plottie is an open source (and cross platform) tool for cutting and plotting SVG graphics using Silhouette plotters and cutters.

The Silhouette Portrait is a desktop paper cutter and pen plotter which can be used to cut intricate shapes out of paper and card. They are fantastic devices, robust, remarkably accurate and include precision optical registration to allow cutting out of printed designs.

A Silhouette Portrait

This project started back in 2013 when I originally reverse engineered the USB protocol used by the Silhouette Portrait and built myself a rough-and-ready cutting and plotting tool. In the intervening years I've used the plotter (and my rudimentary software) more than I ever imagined for all manner of projects.

Various photographs of items produced with the plotter

Unfortunately I never put the time in to finishing the software and more recently (around 2018), I finally got fed up with fixing things and vowed to start again and do a proper job and, so, Plottie was born.

Reverse engineering the plotter

I bought my Silhouette Portrait in 2013 to make our wedding invitations. Unfortunately, however, the Silhouette Studio software which came with the device only worked with Windows and macOS, but not on Linux. At the time, the open source and cross platform Robocut software was in its infancy, supporting only a fraction of the functionality I wanted and lacking in robustness. However, it demonstrated that the USB protocol used by Silhouette devices was relatively simple.

To reverse engineer the USB protocol I spun up a Windows virtual machine and then used Wireshark to capture the USB protocol messages on their way to and from the plotter. After lots of trial and error I managed to work out how all of the basic functions were controlled -- and what all of the commands sent by the Silhouette Studio software did. (A snapshot of some of this exploration from 2013 can be found here.)

Based on this work I built a library, py_silhouette, which provides an easy-to-use Python API for controlling the plotter at a low level.

The py_silhouette source code includes extensive comments and documentation on the underlying protocol, explaining every command in detail (see device.py). The py_silhouette manual goes into the meaning of the various parameters and construction of registration marks in detail.

Converting SVGs into line segments

With the device under control, the next task was to provide it with something to cut out. SVG is a widely used vector graphics format and the native format of my graphics editor of choice: Inkscape. As a full-featured vector graphics format, SVG is complex to parse and defines shapes in terms of curves, text and other shapes with sophisticated styling options. As a consequence, converting from SVG to a list of straight line segments -- all the plotter understands -- proved challenging.

An rendered SVG image alongside an equivalent set of line segments

Inkscape itself provides numerous export formats, including (in earlier versions) HP-GL -- a file format used by certain plotters. Unfortunately, this functionality was fairly limited and a large number of basic SVG features simply did not work.

After briefly considering writing my own SVG interpreter, I discovered a neat trick used by Robocut to read SVG files. The Qt GUI library provides its own SVG renderer which is able to render onto any of a number of QPaintDevice back ends. Thanks to the outstanding level of care by the Qt developers it is possible to create a custom QPaintDevice implementing just a 'draw straight line' primitive which is then used by all other drawing operations.

Using this Qt SVG trick gets you 90% of the way to a working SVG-to-straight-line-segments conversion. Unfortunately there are a few subtle things which still need some manual intervention (which the inspirational Robocut implementation did not include).

Unfortunately the Qt API does not implement dashed strokes for you and instead sets a flag indicating the expected dash pattern. Implementing dashed strokes correctly proved slightly fiddly but was extremely useful for producing perforated edges and fold lines).

In addition, Qt's SVG Renderer operates on screen coordinates and so accurately converting coordinates to millimetres requires manual parsing of the SVG. This is further complicated by the fact that until recently Inkscape had been using the wrong DPI in all generated SVGs requiring a special-case to correctly handle scale these files.

Back in 2013, Qt's Python bindings weren't quite up to allowing you to provide a Python implementation of QPaintDevice and so, like Robocut, I ended up writing my first implementation in C++. However more recently Qt for Python (a.k.a. PySide2) has brought vast improvements to Python Qt compatibility and a Python implementation is now possible!

The svgoutline Python library contains a self-contained implementation of all of the above with an easy-to-use API. It achieves the best SVG-to-straight-line conversion support I'm aware of, though still isn't perfect. Its only major limitations are due either to Qt SVG only supporting the SVG Tiny 1.2 subset of SVG or bugs in its implementation. The library also has a fairly extensive test suite which verifies exact conversion of a wide variety of SVG features.

The plottie user interface

The Plottie command-line tool ties all of this work together in a ready to use SVG-to-tiny-bits-of-cut-out-paper-all-over-the-place tool. Plottie has replaced my earlier unpublished (and near-unpublishable(!)) plotting software bringing with it numerous helpful features. These include:

  • Robust automatic detection of registration marks within an SVG file. This includes things like handling trivial floating point precision errors and not being put-off by other registration-mark-like items in the drawing.

  • Automatic plot-vs-cut mode selection based on Inkscape Layer names. If a layer called something like 'Cut' or 'Plot' is found, Plottie will guess the correct mode to use.

  • Flexible object selection. What to cut can be chosen by layer name, colour, SVG object ID or class. Further Plottie will automatically hide and show layers (and objects) in the file. This means that cutting outline layers can remain hidden in the SVG file (keeping the file in a ready-to-print state to avoid mistakes!) and Plottie will still be able to find and use them while ignoring the rest of the design.

  • Sensible cut re-ordering. Though Plottie doesn't go to the lengths of some tools to manipulate the cut order to support mat-free cutting, it does try to cut inner-most shapes first and otherwise cut in a sensible order.

As such, 99% of the time plotting or cutting can be performed using no more than:

$ plottie path/to/drawing.svg

All of the software I developed during this project can be found on GitHub or installed from PyPI using pip: