8

I have a cartoon with multiple layers; among those layers I have a German and an English layer. They have the text in their respective languages. The idea is to hide the German layer and show the English layer and export as an English cartoon or to hide the English layer and show the German layer for a German version of the cartoon. I'd like to script that export.

Here is a part of my SVG file:

  <g
     inkscape:groupmode="layer"
     id="layer3"
     inkscape:label="English"
     style="display:inline">
     <text
         xml:space="preserve"  
         <!-- .... --> 
         id="text3255">
         <tspan id="tspan3257">I don't think</tspan>
         <!-- ... -->

and

 <g
     inkscape:groupmode="layer"
     id="layer4"
     inkscape:label="German"
     style="display:none"> 
     <text
           xml:space="preserve"
           <!-- ... -->
           id="text3284">   
           <tspan id="tspan3286">Ich glaube nicht,</tspan> 
           <!-- ... -->

I've seen https://stackoverflow.com/questions/9652573/inkscape-command-line-programming and tried this command (and plenty of variations to it):

inkscape -z --file=cartoon.svg --select=English --verb=LayerHideAll --select=German --verb=LayerShowAll --export-png=cartoon-de.png --export-area-drawing

But I keep getting the English text, probably because when I saved the file, the English layer was visible and the German layer wasn't.

I've also tried selecting the layers by their IDs (in the code above layer3 and layer4, respectively), and selecting the actual <text> elements; I've tried various combinations of Inkscape verbs. But no luck either.

How can I script this export, hiding or showing the language layer as needed? Can I do this with Inkscape verbs or should I work with the XML and try setting the style attribute to display:inline or display:none?

3

Ok, I messed around with various XML parsing modules and ended up with the following code.

use XML::LibXML;
use XML::LibXML::XPathContext;

my $xml = XML::LibXML->load_xml(location => $file);
my $xpath = XML::LibXML::XPathContext->new($xml);  
$xpath->registerNs("defNs", 'http://www.w3.org/2000/svg');
foreach my $layer ($xpath->findnodes('/defNs:svg/defNs:g[@inkscape:groupmode="layer"])) {
    my $label = $layer->{'inkscape:label'};
    foreach my $otherLang (@languages) {
        if ($label =~ m/$other_lang$/) {
            $layer->{'style'} =~ s{\bdisplay:inline\b}{display:none};
        }
    }
    if ($layerLang eq $lang) {
        $layer->{'style'} =~ s{\bdisplay:none\b}{display:inline};
    }
}
$xml->toFile($tempFileName);

This solves my problem. Hopefully it is useful to someone else as well.

  • 1
    @StephenEglen Actually, this is buggy... you can't just set the style to display:... cause this will break if you already have other style attributes like opacity. I've updated the answer. – Robert Aug 4 '16 at 21:55
  • Thanks. Do you mean that sometimes the "style" item for the layer can contain multiple attributes? in which case we should search/replace display:inline <--> display:inline accordingly? – Stephen Eglen Aug 6 '16 at 8:32
  • 1
    @StephenEglen Yes, exactly. I noticed it with opacity, but there can probably be others as well. Hence the regex to replace only the display:... and leave everything else as is. – Robert Aug 6 '16 at 17:56
2

I know it is a little bit late but I found this hide-latyer-svg Github Project which uses a python script to create new files with certain layers shown and hidden based on a xml node that you create on layer lever.

Best, Christoph

2

As to why the command-line testing wasn't working, I believe the answer is that you first need to select an item in the layer (and not the layer itself) to be "in" the layer. After that, the correct verb would be LayerToggleHide. (Not sure if this verb was available when this question was asked.) And, yes, objects can only be selected by ID, and not name.

Furthermore, because there are no LayerHide and LayerShow verbs (why?), to reliably script this you would first need to use LayerHideAll or LayerShowAll to set all layers one way or the other before then using LayerToggleHide to achieve the final result.

I haven't tested this command-line route so I can't show a definitive working solution. Instead, after thinking through the command-line route a great deal and realizing how much scripting it would take to make it work for my needs, I decided to just go all-in and write an Inskape extension that handles needs like this. I call it the SLiCk Layer Combinator and it can be found here: https://github.com/juanitogan/slick

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.