Search code examples
svginkscape

Enable/disable layers via command line


I have a script (below) which exports from an svg file to png files of various sizes. This works, but I need more. I need to be able to enable and disable layers before the export. So, for example, just after the #Android line, I need to enable layer android and disable layer ios

How can I do this?

set -x

# Windows
INKSCAPE="/C/Program Files/Inkscape/inkscape.exe"
OPTS=--export-background-opacity=0

# Note that directories must already exist before exporting to them

SVG=My_Icon.svg
DEST=generated_icons

# Android
"$INKSCAPE" -w36 $OPTS --export-png=$DEST/android/ic_launcher-ldpi.png $SVG
"$INKSCAPE" -w48 $OPTS --export-png=$DEST/android/ic_launcher-mdpi.png $SVG
"$INKSCAPE" -w72 $OPTS --export-png=$DEST/android/ic_launcher-hdpi.png $SVG
"$INKSCAPE" -w96 $OPTS --export-png=$DEST/android/ic_launcher-xhdpi.png $SVG
"$INKSCAPE" -w144 $OPTS --export-png=$DEST/android/ic_launcher-xxhdpi.png $SVG
"$INKSCAPE" -w192 $OPTS --export-png=$DEST/android/ic_launcher-xxxhdpi.png $SVG
"$INKSCAPE" -w512 $OPTS --export-png=$DEST/android/ic_launcher-web.png $SVG

# iOS
"$INKSCAPE" -w57 $OPTS --export-png=$DEST/ios/ios_icon-57.png $SVG
"$INKSCAPE" -w72 $OPTS --export-png=$DEST/ios/ios_icon-72.png $SVG
"$INKSCAPE" -w114 $OPTS --export-png=$DEST/ios/ios_icon-57-2x.png $SVG
"$INKSCAPE" -w144 $OPTS --export-png=$DEST/ios/ios_icon-72-2x.png $SVG

Solution

  • I've come up with a method using xmlstarlet to edit the InkScape SVG on the fly before passing it to InkScape itself.

    Imagine you have an InkScape SVG with three layers, SenateBackground, Caesar and Antonius, and you only want the combinations (SenateBackground,Caesar) and (SenateBackground,Antonius).

    This is how such a layer looks in the SVG:

    <g
     inkscape:label="Caesar"
     id="someID"
     inkscape:groupmode="layer"
     style="display:none"
     sodipodi:insensitive="true"
     transform="...">
    

    Just as a side note: In some other SO questions, the tip of querying the layers using inkscape --query-all <file> | grep "layer" has come up, at least in my findings this is not reliable, as inkscape does not always name the id="someID" as id="layerX" (which the grep looks for). For me, some of the layers simply got group IDs like g12345.

    To generate the PNG with Caesar in the Senate, the steps are now...

    1. Read the SVG/XML
      This can be done with cat
    2. Pipe it through xmlstarlet, showing the senate background
      In my example I handle every layer, so I do not have any restrictions like When modifying the SVG, remember to show/hide layer X/Y before saving, the PNG generation script relies on it!.
    3. Pipe it through xmlstarlet again, showing Caesar
    4. Pipe it through xmlstarlet again, hiding Antonius
    5. Pipe it to InkScape, creating the PNG
      You have to provide the width/height or DPI as this apparently will not be taken from the settings stored in the file.

    Command:

    cat romanSenate.svg | \
    xmlstarlet edit -P -S --update "//*[@inkscape:label='SenateBackground']/@style" -v "display:inline" | \
    xmlstarlet edit -P -S --update "//*[@inkscape:label='Caesar']/@style" -v "display:inline" | \
    xmlstarlet edit -P -S --update "//*[@inkscape:label='Antonius']/@style" -v "display:none" | \
    inkscape -z -e romanSenate.svg.showingCaesar.png -d 300 /dev/stdin
    

    -d 300 specifies the output DPI. We use /dev/stdin as input file because InkScape does not handle anything piped to it.