#!/usr/bin/perl -w # Extract path data from walking mushroom image. # # perl extract_shapes.pl walking_mushroom.svg > paths.txt use strict; use XML::LibXML; use constant INPUT_LAYER => "simplified"; # Extract color and path attributes from a single element. sub parse_path($) { my ($node) = @_; print 'style="', $node->{"style"}, '", '; # All coordinate values must be integer. my $d = $node->{"d"}; if( index($d, ".") >= 0 ) { die "Path data contains floating point\n$node\n"; } # First command must be a move to a positive integer coordinate, and # last command must be a close path event. $d =~ /^[Mm]\s+(\d+)[, ](\d+)(.*)\s+[Zz]\s*$/ or die "Bad path\n$node\n"; my ($x0, $y0, $points) = ($1, $2, $3); print "path={{$x0,$y0}"; # Consume curve commands. my $cmd = undef; while( $points !~ /^\s*$/ ) { if( $points =~ s/^\s*([[:alpha:]])\s+(\S.*)$/$2/ ) { # Change command. We only accept relative and absolute curve commands. $cmd = $1; unless( $cmd eq "c" || $cmd eq "C" ) { die "Unexpected command $cmd\n$node\n"; } } else { # Continue previous command. $points =~ s/^\s*([-]?\d+)[, ]([-]?\d+) \s+([-]?\d+)[, ]([-]?\d+) \s+([-]?\d+)[, ]([-]?\d+) (.*)$/$7/x or die "Unparsable path\n$node\n"; my ($x1, $y1, $x2, $y2, $x3, $y3) = ($1, $2, $3, $4, $5, $6); # Convert relative coordinates. if( $cmd eq "c" ) { $x1 += $x0; $y1 += $y0; $x2 += $x0; $y2 += $y0; $x3 += $x0; $y3 += $y0; } print ", {$x1,$y1},{$x2,$y2},{$x3,$y3}"; $x0 = $x3; $y0 = $y3; } } print "}\n"; } # Load input. my $dom = XML::LibXML->load_xml(string => join "", ); # Iterate through all group nodes. foreach my $group ($dom->getElementsByTagName("g")) { if( defined $group->{"inkscape:groupmode"} && defined $group->{"inkscape:label"} && $group->{"inkscape:groupmode"} eq "layer" && $group->{"inkscape:label"} eq INPUT_LAYER ) { # Process elements. foreach my $child ($group->childNodes()) { my $name = eval('$child->nodeName'); if( defined($name) && $name eq "path" ) { parse_path($child); } } } }