Daniel Beer Atom | RSS | About

PDF jumper diagrams with a simple Perl script

2 Jan 2020

I recently needed to generate documentation in TeX for a board which was configured via jumpers placed on header pins. I wrote the Perl script shown here to quickly generate high-quality PDF images of different jumper settings for inclusion in the documentation. The script is approximately 200 lines, has no dependencies aside from the Perl interpreter itself, and can easily be modified to draw other kinds of diagrams.

To use it, specify a template consisting of a string of one of more of the following characters:

For example, invoking as:

./jd.pl OIOOoo > example.pdf

Gives the following output:

Example PDF produced by the script, shown here as a 600-dpi PNG.

Example PDF produced by the script, shown here as a 600-dpi PNG.

The script and the above example output can be downloaded here:

The script itself is broken into three packages. The first package, called PDF, handles low-level PDF operations. It contains output functions which keep track of the current position, and facilities for allocating PDF objects and emitting a final xref table.

The second package is called PDFDrawing and is higher-level. It provides a function for adding graphics commands to a single content-stream. Finally, PDFDrawing::finish is called, which uses the PDF package to build a PDF file containing a single page, cropped to the specified size and containing the given content. The PDFDrawing package also contains a helper function to approximate circles using Bezier splines.

Finally, the main package parses the template and calls functions in PDFDrawing to emit primitives. The package is shown here in its entirety:

my $tmpl = shift // die "Specify a template";
my $size = 10;
my $n = 0;

for my $c (split //, $tmpl) {
    if (($c eq 'o') or ($c eq 'O')) {
        PDFDrawing::put "q 0.75 G" if $c eq 'o';
        PDFDrawing::bz_circle $n * $size + $size / 2, $size / 2, $size / 4;
        PDFDrawing::put "S";
        PDFDrawing::put "Q" if $c eq 'o';
        $n++;
    } elsif ($c eq 'I') {
        my $x1 = $n * $size + $size / 8;
        my $y1 = $size / 8;
        my $y2 = $size * 7 / 8;
        my $x2 = ($n + 2) * $size - $size / 8;

        PDFDrawing::put "$x1 $y1 m";
        PDFDrawing::put "$x2 $y1 l";
        PDFDrawing::put "$x2 $y2 l";
        PDFDrawing::put "$x1 $y2 l";
        PDFDrawing::put "h S";
    }
}

PDFDrawing::finish $size * $n, $size;

By replacing the main package, this script can be easily repurposed. For a reference on PDF graphics commands, see section 8 ("Graphics") of the PDF specification.