Beamer用に複数のEPSを生成する

このエントリーをはてなブックマークに追加

概要

LaTeXのbeamerでプレゼンテーションを作る時,複数のEPSファイルを使ってアニメーションをしたいが,複数のEPSファイルを作成するのが面倒だ.そこで,Inkscapeを使って作成したSVGから複数のEPSファイルを作る方法を考えてみた.

multisvg

#!/usr/bin/perl
use strict;
use Getopt::Std;
use XML::Simple;
use Data::Dumper;
$Data::Dumper::Indent = 1;

use vars qw($opt_h $opt_e $opt_d);

&getopts("hed");

my $inkscape = "inkscape";
if ($opt_h) {
    print "Usage: $0 file.svg file.txt\n";
    print "\tgenerates files file_000.svg, file_001.svg, ...\n";
    print "  -e : generates EPS files instead of SVG by using inkscape\n";
    print "  -d : dump file.svg in perl syntax\n";
    exit(1);
}
my $svg_file = shift(@ARGV);
my $anim_file = shift(@ARGV);
my $eps = $opt_e;
my $svg = XMLin($svg_file, KeepRoot => 1, KeyAttr => {});
my $output0 = $svg_file;
$output0 =~ s/\.svg$//;

my $frame = 0;
my ($tag0, $attr0);
open(ANIM, "<", $anim_file) || die "$0: $anim_file $!";
while (<ANIM>) {
    chomp;
    next if /^\s*$/ || /^\#/;
    if (/^save$/i) {
	my $output = sprintf("%s_%03d", $output0, $frame);
	if ($opt_d) {
	    print "##### $output\n";
	    print Dumper($svg);
	}
	&save($svg, "$output.svg");
	if ($eps) {
	    system("$inkscape -z -E '$output.eps' '$output.svg'");
	    unlink "$output.svg";
	}
	$frame++;
    } else {
	my @rule = split(/\t/);
	$rule[0] ||= $tag0;
	$rule[1] ||= $attr0;
	&replace("", $svg, \@rule);
    }
}
close(ANIM);
exit 0;

sub replace {
    my ($tag, $data, $rule) = @_;
    if (ref($data) eq "ARRAY") {
	foreach my $d (@{$data}) {
	    &replace($tag, $d, $rule);
	}
    } elsif (ref($data) eq "HASH") {
	if ($tag && $tag =~ /^$rule->[0]$/
	    && $data->{id} =~ /^$rule->[1]$/) {
	    foreach my $x (keys %{$data}) {
		if ($x =~ /^$rule->[2]$/) {
		    my $pattern = $rule->[3];
		    my $replace = $rule->[4];
		    my $opt = $rule->[5];
		    $_ = $data->{$x};
		    if ($opt eq "e") {
			s/\b$pattern\b/eval $replace/e;
		    } else {
			s/$pattern/$replace/;
		    }
		    $data->{$x} = $_;
		}
	    }
	}
	foreach my $x (keys %{$data}) {
	    &replace($x, $data->{$x}, $rule);
	}
    }
}

sub save {
    my ($svg, $svg_output) = @_;
    my $fh;
    open($fh, ">:encoding(UTF-8)", $svg_output) || die;
    XMLout($svg, OutputFile => $fh, KeepRoot => 1, NoIndent => 1, KeyAttr => {},
	   XMLDecl => '<?xml version="1.0" encoding="UTF-8" standalone="no"?>');
    close($fh);
}

使い方

まずはInkscapeで図を描く
  • Inkscapeで図を描く
  • IDを設定
    • 図形を右クリックして「オブジェクトのプロパティ」を選択し,わかりやすい「id」を設定する.
    • たとえば,テキストなら「text:a」,矩形なら「rect:a」など
  • 図を保存する
  • 以下は,サンプルの図 (multisvg_sample.svg)


  • 以下は,multisvg_sample.svg の内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="579.16846"
   height="263.70392"
   id="svg2"
   sodipodi:version="0.32"
   inkscape:version="0.46"
   version="1.0"
   sodipodi:docname="multisvg_sample.svg"
   inkscape:output_extension="org.inkscape.output.svg.inkscape">
  <defs
     id="defs4">
    <marker
       inkscape:stockid="Arrow1Lend"
       orient="auto"
       refY="0"
       refX="0"
       id="Arrow1Lend"
       style="overflow:visible">
      <path
         id="path3167"
         d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
    </marker>
    <inkscape:perspective
       sodipodi:type="inkscape:persp3d"
       inkscape:vp_x="0 : 526.18109 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_z="744.09448 : 526.18109 : 1"
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
       id="perspective10" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     gridtolerance="10000"
     guidetolerance="10"
     objecttolerance="10"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.90976941"
     inkscape:cx="288.79217"
     inkscape:cy="122.46446"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="741"
     inkscape:window-height="715"
     inkscape:window-x="-4"
     inkscape:window-y="25" />
  <metadata
     id="metadata7">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(-211.6657,-79.168628)">
    <rect
       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
       id="rect:a"
       width="169.75522"
       height="145.33836"
       x="247.83945"
       y="123.2529"
       rx="16.809414"
       ry="19.882915"
       inkscape:label="#rect2383" />
    <rect
       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
       id="rect:b"
       width="138.36212"
       height="174.40604"
       x="605.90924"
       y="115.80508"
       rx="16.809414"
       ry="19.882915"
       inkscape:label="#rect2385" />
    <text
       xml:space="preserve"
       style="font-size:32px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
       x="329.22891"
       y="198.82886"
       id="text:a"
       inkscape:label="#text2389"><tspan
         sodipodi:role="line"
         id="tspan2391"
         x="329.22891"
         y="198.82886">a</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:32px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
       x="676.29956"
       y="200.61957"
       id="text:b"
       inkscape:label="#text2389"><tspan
         sodipodi:role="line"
         id="tspan2385"
         x="676.29956"
         y="200.61957">b</tspan></text>
    <path
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1"
       d="M 415.08637,189.48328 L 605.93041,203.93671"
       id="path:a:b"
       inkscape:label="#path2389" />
  </g>
</svg>
アニメーション設定用のファイルを作成する
  • SVGファイルの中身を眺めながら,以下のようなファイル(multisvg_sample.txt)を作成する.
    • 「#」で始まる行あるいは空白行は,コメント
    • 「save」のみの行は,SVGあるいはEPSの保存
    • その他の行は,タブ区切りで以下を記述する
      • 第1欄: XMLタグ名全体にマッチする正規表現 (rect, text等)
      • 第2欄: id全体にマッチする正規表現
      • 第3欄: 属性名全体にマッチする正規表現
      • 第4欄: 属性値の置換対象部分にマッチする正規表現
      • 第5欄: 第4欄の置換結果の文字列
      • 第6欄: 「e」ならば第5欄を評価する
## multisvg のサンプル

# すべての text を白に
text	.*	style	fill:#?\w+	fill:#ffffff
# すべての path を白に
path	.*	style	stroke:#?\w+	stroke:#ffffff
# path:a:b の Arrow1Lend (pathの最後の矢印)を削除
path	path:a:b	style	marker-end:url\(#Arrow1Lend\)
# svgを保存
save

# rect:a を赤に
rect	rect:a	style	stroke:#?\w+	stroke:#ff0000
# text:a を赤で表示
text	text:a	style	fill:#?\w+	fill:#ff0000
# svgを保存
save

# rect:a を黒に
rect	rect:a	style	stroke:#?\w+	stroke:#000000
# text:a を黒に
text	text:a	style	fill:#?\w+	fill:#000000
# path:a:b を黒に
path	path:a:b	style	stroke:#?\w+	stroke:#000000
# path:a:b の Arrow1Lend (pathの最後の矢印)を表示
path	path:a:b	style	;;	;marker-end:url(#Arrow1Lend);
# rect:b を赤の太線に
rect	rect:b	style	stroke:#?\w+	stroke:#ff0000
rect	rect:b	style	stroke-width:\d+	stroke-width:3
# text:b を赤の太文字に
text	text:b	style	fill:#?\w+	fill:#ff0000
text	text:b	style	font-weight:\w+	font-weight:bold
# svgを保存
save
プログラムを実行
  $ ./multisvg -e multisvg_sample.svg multisvg_sample.txt
  • multisvg_sample_000.eps, multisvg_sample_001.eps, multisvg_sample_002.epsが作成される.
    • multisvg_sample_000.eps


    • multisvg_sample_001.eps


    • multisvg_sample_002.eps