diff --git a/tools/buildimage b/tools/buildimage index 74519fd6358..7075bc917cb 100755 --- a/tools/buildimage +++ b/tools/buildimage @@ -20,7 +20,7 @@ use strict; use warnings; -use XML::Parser; +use XML::LibXML; use MIME::Base64; use File::Copy; @@ -58,6 +58,13 @@ $SIG{"HUP"} = "cleanup"; $SIG{"TERM"} = "cleanup"; $SIG{"__DIE__"} = "cleanup"; +my %label = +( + 'ico' => 'icon:(\d*)-(\d*)', + 'cur' => 'cursor:(\d*)-(\d*)', + 'bmp' => 'bitmap:(\d*)-(\d*)', +); + # run a shell command and die on error sub shell(@) { @@ -65,105 +72,18 @@ sub shell(@) system(@args) == 0 or die "@args failed: $?"; } -sub svg_element_start +# add an image to the icon/cursor +sub add_image($$) { - my($expat, $element, %attr) = @_; - - # Parse the id for icon/bitmap render directives - my $id = $attr{'id'}; - return unless defined($id); - - my $size = 0; - my $depth = 0; - my $width = 0; - my $height = 0; - - if ($id =~ /hotspot:(\d*)/) - { - $hotspot[$1] = [ $attr{x}, $attr{y} ]; - return; - } - - if($ext eq "ico") { - return unless $id =~ /icon:(\d*)-(\d*)/; - $size = $1; - $depth = $2; - } elsif($ext eq "cur") { - return unless $id =~ /cursor:(\d*)-(\d*)/; - $size = $1; - $depth = $2; - } elsif($ext eq "bmp") { - return unless $id =~ /bitmap:(\d*)-(\d*)/; - $size = $1; - $depth = $2; - } - - return unless defined($size) and defined($depth); - - warn "Unexpected depth" unless - $depth == 1 or $depth == 4 or $depth == 8 or $depth == 24 or $depth == 32; - my $pngFileName = "$outName-$size-$depth.png"; - - if($element eq "svg") { - - if ($ext eq "bmp") { - if ($depth == 24) { - shell $convert, $renderedSVGFileName, "+matte", $outFileName; - } else { - shell $convert, $renderedSVGFileName, $outFileName; - } - cleanup(); - exit(0); - } - - # The whole file is tagged - $pngFileName = $renderedSVGFileName; - - } elsif($element eq "rect") { - - # Extract SVG vector images - my $x = $attr{'x'}; - my $y = $attr{'y'}; - $width = $attr{'width'}; - $height = $attr{'height'}; - - if(defined($x) and defined($y)) { - if($x =~ /\d*/ and $y =~ /\d*/) { - shell $convert, $renderedSVGFileName, "-crop", "${width}x${height}+$x+$y", "-depth", $depth, $pngFileName; - } - } - } elsif($element eq "image" ) { - - # Extract Base64 encoded PNG data to files - my $xlinkHref = $attr{'xlink:href'}; - if(defined($xlinkHref)) { - $xlinkHref =~ /data:image\/png;base64(.*)/; - my $imageEncodedData = $1; - if(defined $imageEncodedData) { - open(FILE, '>' . $pngFileName) or die "$!"; - print FILE decode_base64($imageEncodedData); - close FILE; - } - } - } else { - return; - } - + my ($file, $size) = @_; + if (defined $hotspot[$size]) { my @coords = @{$hotspot[$size]}; push @icotool_args, "--hotspot-x=$coords[0]", "--hotspot-y=$coords[1]"; } - - if ($width >= 128 && $height >= 128) - { - push @icotool_args, "--raw=$pngFileName"; - } - else - { - push @icotool_args, $pngFileName; - } - push @pngFiles, $pngFileName; + push @icotool_args, $size >= 128 ? "--raw=$file" : $file; + push @pngFiles, $file; } # Render the SVG image @@ -175,9 +95,67 @@ push(@rsvgCmd, $renderedSVGFileName); shell @rsvgCmd; # Render the images in the SVG -my $parser = new XML::Parser( - Handlers => {Start => \&svg_element_start}); -$parser->parsefile("$svgFileName"); +my $xml = XML::LibXML->load_xml( location => $svgFileName ); +my $xc = XML::LibXML::XPathContext->new($xml); +$xc->registerNs('x', 'http://www.w3.org/2000/svg'); + +if ($ext eq "bmp") +{ + foreach my $element ($xc->findnodes("/x:svg")) + { + next unless $element->{id} =~ /bitmap:(\d*)-(\d*)/; + my $size = $1; + my $depth = $2; + if ($depth == 24) { + shell $convert, $renderedSVGFileName, "+matte", $outFileName; + } else { + shell $convert, $renderedSVGFileName, $outFileName; + } + cleanup(); + exit(0); + } +} + +# fetch hotspot rectangles for the various sizes + +if ($ext eq "cur") +{ + foreach my $element ($xc->findnodes("/x:svg/x:rect")) + { + next unless $element->{id} =~ /hotspot:(\d*)/; + $hotspot[$1] = [ $element->{x}, $element->{y} ]; + } +} + +# extract rectangles from the rendered svg + +foreach my $element ($xc->findnodes("/x:svg/*[\@id]")) +{ + next unless $element->{id} =~ /$label{$ext}/; + my $size = $1; + my $depth = $2; + warn "Unexpected depth" unless + $depth == 1 or $depth == 4 or $depth == 8 or $depth == 24 or $depth == 32; + my $file = "$outName-$size-$depth.png"; + + my $x = $element->{x}; + my $y = $element->{y}; + my $width = $element->{width}; + my $height = $element->{height}; + if ($element->{'xlink:href'}) + { + # extract base64-encoded png image + (my $data = $element->{'xlink:href'}) =~ s/data:image\/png;base64//; + open FILE, ">$file" or die "$!"; + print FILE decode_base64($data); + close FILE; + } + else + { + shell $convert, $renderedSVGFileName, "-crop", "${width}x${height}+$x+$y", "-depth", $depth, $file; + } + add_image( $file, $size ); +} die "no render directive found in $svgFileName" unless @pngFiles;