Converting SVG to DXF

Posted on May 3, 2016
Tags: making, software

I’ve been starting to play with OpenSCAD, after having outgrown TinkerCAD. Specifically, TinkerCAD did not have the ability to take a 2D shape I’d drawn in Inkscape and revolve it to make a 3D object.

OpenSCAD does have this ability, but it isn’t able to directly use SVG files, which is what Inkscape creates. Instead, OpenSCAD wants DXF files. The OpenSCAD WikiBook explains how to convert SVG files to DXF files in a two-step process, by way of EPS. This sounded Rube Goldbergian, but it actually worked just fine.

However, I wanted to be able to do this on my MacBook Pro, which is slightly complicated by the fact that the inkscape command-line program is hidden inside the Inkscape.app bundle. And even then, inkscape is a shell script which wraps the real binary, and one of the things the shell script does is change the current directory. Therefore, relative paths don’t work.

So, I decided to write a little script to encapsulate all the necessary shenanigans. Although I considered writing the script in Haskell, I ended up using Perl:

#!/usr/bin/perl -w

# svg-to-dxf.pl - convert SVG files to DXF files on Mac OS X
# by Patrick Pelletier, public domain (or cc0)
# based on the commands suggested here:
# https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_2D_formats
# assumes Inkscape.app is installed in /Applications
# and pstoedit is installed in PATH, such as via "brew install pstoedit"

use Cwd qw(abs_path);
use File::Temp ();

die "Usage: $0 filename.svg\n" if ($#ARGV != 0); # 0 means 1 argument
my ($src) = @ARGV;
$src = abs_path($src); # because inkscape changes current directory

my $dest = $src;
$dest =~ s/\.svg$/.dxf/;
die "filename doesn't end in .svg" if ($src eq $dest);

my $intermediate = File::Temp->new(SUFFIX => '.eps');

system ("/Applications/Inkscape.app/Contents/Resources/bin/inkscape", "-E",
        $intermediate, $src) == 0 or die "inkscape failed";
system ("pstoedit", "-q", "-dt", "-f", "dxf:-polyaslines -mm",
        $intermediate, $dest) == 0 or die "pstoedit failed";

Also available as a gist.