3 minute read

Most graphics that we use in publications or reports are vector graphics, such as SVGs, PDFs, sometimes also WMFs, EMFs, EPSs, or PS files. It is often necessary to convert between them, most often between PDF and SVG. This can be done via Inkscape. Here I provide the little script vec2vec.sh, which does this in the terminal. It basically just executes Inkscape with the correct parameters.

All you have to do is to provide the path to the source vector graphics document and either the path to a destination document or the extension to convert. If you call vec2vec.sh mydoc.pdf svg, then it will create a file mydoc.svg. If you call vec2vec.sh mydoc.svg svg ../result.wmf, then it creates the document result.wmf in the parent folder of the current folder. As output format, the script additionall supports PNG, which is a raster graphic. For the input format PDF, you can additionally specify the optional argument flatten, in which case all text is rendered as vector graphics, which may help in some cases where font issues mess up the output.

The script will check if Inkscape is installed and abort if not. In that case, an appropriate error message is printed. You can install GhostScript via sudo apt-get install inkscape. The script will also fail with an error if either the input file does not exist or if the expected output file is not produced for some reason.

Here you can download this script and the complete collection of my personal scripts is available here. In that collection, there also is a script convertTo.sh, which bundles different conversion scripts between different formats. It decides based on the file extensions which scripts to use (or fails if no fitting script is available). Another related script is office2pdf.sh.

#!/bin/bash -

# Convert one vector graphic format to another.
# Supported input formats include svg, pdf, wmf, emf, eps, and ps.
# Supported output formats include svg, pdf, wmf, emf, eps, ps, and png.
#
# The script expects the following parameters:
# 1. The path to a source document.
# 2. Either a file extension or a path to a destination document.
#    The file extension will then be taken from that path.
# 3. Optional: For PDF input documents, you may specify "flatten", which
#              converts text to vector drawings. This may help in some
#              cases of corrupted output.
#
# This script is basically a wrapper around inkscape.
#
# strict error handling
set -o pipefail  # trace ERR through pipes
set -o errtrace  # trace ERR through 'time command' and other functions
set -o nounset   # set -u : exit the script if you try to use an uninitialized variable
set -o errexit   # set -e : exit the script if any statement returns a non-true return value

package="inkscape"
if ! ( (dpkg-query -W -f='${Status}' "$package" 2>/dev/null | grep -q "ok installed") || (snap list | grep "^$package" -q) ); then
  echo "$(date +'%0Y-%0m-%0d %0R:%0S'): $package is not installed but needed."
  echo "$(date +'%0Y-%0m-%0d %0R:%0S'): You can install it via 'sudo apt-get install $package'."
  exit 1
fi

srcDocument="$(realpath "$1")"
srcExtension="${srcDocument##*.}"
if [ -f "$srcDocument" ]; then
  echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Got source document '$srcDocument' with file extension '$srcExtension'."
else
  echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Source document $srcDocument' does not exist."
  exit 1
fi

outSpec="$2"
dstExtension="${outSpec##*.}"
if [[ "$dstExtension" != "$outSpec" ]]; then
  dstDocument="$(realpath "$outSpec")"
else
  dstExtension="$outSpec"
  dstDocument="$(realpath "${srcDocument%.*}.$dstExtension")"
fi
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We will convert document '$srcDocument' to '$dstDocument'."

moreArgs="--export-type=$dstExtension --export-background-opacity=0.0 --export-area-page --vacuum-defs"
if [ "$srcExtension" == "pdf" ]; then
  if [ "$dstExtension" != "ps" ]; then
    moreArgs="$moreArgs --pdf-page=1"
  fi
fi
if [ "$dstExtension" == "pdf" ]; then
  moreArgs="$moreArgs --export-pdf-version=1.5"
elif [ "$dstExtension" == "svg" ]; then
  moreArgs="$moreArgs --export-plain-svg"
elif [ "$dstExtension" == "ps" ]; then
  moreArgs="$moreArgs --export-ps-level=3"
elif [ "$dstExtension" == "eps" ]; then
  moreArgs="$moreArgs --export-ps-level=3"
fi

if [ $# \> 2 ]; then
  if [ "$3" == "flatten" ]; then
      if [ "$srcExtension" == "pdf" ]; then
        echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Try to flatten input PDF."
        moreArgs="${moreArgs} --pdf-poppler"
      else
        echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Flattening is only supported for PDF input."
      fi
  fi
fi

echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Now using $package to convert '$srcDocument' to '$dstDocument' with arguments '$moreArgs'."
inkscape --export-filename="$dstDocument" $moreArgs "$srcDocument"

if [ -f "$dstDocument" ]; then
  echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Finished converting '$srcDocument' to '$dstDocument'."
else
  echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Destination document '$dstDocument' was not created."
  exit 1
fi