User:Mysid/scripts

From Wikipedia, the free encyclopedia

This script is now outdated – see Wikipedia:WikiProject Chemistry/Structure drawing workgroup/Mysid's script

The exported chemical structures from BKchem are tiny in dimensions, not cropped, and use some SVG features not supported by librsvg (the library used by MediaWiki). Thus I use the following bloated Perl script to correct this (as well as to make the files more compact):

# scale.pl
# Scales an SVG image produced by bkchem up by 400 % and removes some
# things to circumvent bugs in MediaWiki
 
# Rounding
sub round {
    ($_[0]*10 - int ($_[0]*10) >= .5) ? int ($_[0]*10)/10 + .1 : int ($_[0]*10)/10;
}
 
for (qx!cat $ARGV[0]!) {
 
    # Scale viewbox up
    if(/<svg .*viewBox="0 0 (\d+) (\d+)"/) {
        $w = $1*2;
        $h = $2*2;
        $_ = "<svg width=\"".$w."px\" height=\"".$h."px\" version=\"1.0\" viewBox=\"0 0 $w $h\"
               xmlns=\"http://www.w3.org/2000/svg\">\n";
    }
 
    # Replace baseline-shift with a y-offset tspan
    if (/y="([\d\.]+)">.*<tspan baseline-shift="sub"/) {
        $vy = $1;
        $oy = $1+3.25;
        s/baseline-shift="sub"/y="$oy"/g;
        s/<\/tspan>([^<]+)</<\/tspan><tspan y="$vy">$1<\/tspan></g;
    }
 
    # Scale vectors up; also save space by rounding down to 1/10 pixel resolution & removing redundant declarations
    s/(\d+\.\d+)/round($1*4)/gee unless(/version/);
    s/font-family="helvetica" font-size="12pt" //;
 
    # Scale fonts up by 400 %
    s/12pt/48pt/;
    s/75\%/36pt/g;
 
    $lines .= $_;
}
 
# Remove redundant grouping tags
$lines =~ s/<\/g>\s+<g stroke="\#000000" stroke-width="4">\s//g;
 
# Write out a preliminary version
open(out,">".$ARGV[0]."_tmp.svg");
 
print out $lines;
 
close (out);
 
 
# Get the actual dimensions of the rendered image, cropped, by rendering it in Inkscape
@dime = qx!perl dim.pl $ARGV[0]_tmp.svg!;
chomp(@dime[-1]);
($w,$h) = split(/ /,@dime[-1]);
 
# Set the output filename
$fname = "output";
if ($ARGV[0] =~ /(.+)\.svg/) {
    $fname = $1."2";
}
open (out,">".$fname.".svg");
 
# Write out the final image
for(qx!cat $ARGV[0]_tmp.svg!) {
    if(/<svg .*viewBox="0 0 \d+ \d+"/) {
        $_ = "<svg width=\"".$w."px\" height=\"".$h."px\" version=\"1.0\" viewBox=\"0 0 $w $h\"
               xmlns=\"http://www.w3.org/2000/svg\">\n";
    }
    print out $_;
}
 
close(out);
 
unlink($ARGV[0]."_tmp.svg");
 
print "$fname.svg done\n";

where dim.pl contains

use Image::Magick;
 
$a = $ARGV[0];
 
unlink("tmp.png");
print STDERR "inkscape...\n";
 
# Render the image
system("inkscape -e tmp.png $a");
 
# Initialize Imagemagick
$image = Image::Magick->new;
$image->Read("tmp.png");
$he = $image->Get('height');
$wi = $image->Get('width');
 
$maxy = $maxx = 0;
$miny = $he;
$minx = $wi;
 
unlink("tmp.gray");
print STDERR "convert...\n";
 
# Make a raw 8-bit grayscale version for simple perl input
system("convert tmp.png -depth 8 tmp.gray");
 
print STDERR "crop...\n";
open(img,"tmp.gray");
 
# Find the borders of the actual black data inside the image canvas
for $y (1..$he) {
    for $x (1..$wi) {
        read(img,$b,1);
        if (ord($b) < 255) {
            $miny = $y if ($y<$miny);
            $minx = $x if ($x<$minx);
            $maxy = $y if ($y>$maxy);
            $maxx = $x if ($x>$maxx);
        }
    }
}
 
# Pad them a little and output
print ($maxx+$minx+($maxx*0.05));
print " ".($maxy+$miny+($maxy*0.05))."\n";

Usage: perl scale.pl oldpic.svg

Produces oldpic2.svg

Requires: Linux, Perl, Inkscape, Imagemagick (I haven't really considered portability as I was the only one supposed to use this script)