EPSとは何か

ぐぐれ

EPSをテキストエディタで書くメリット

  1. マウスより正確に書けるし、微調整がしやすい
  2. 数値データを図形に変換できる
  3. PerlやRubyなどのスクリプトから図を出力できるようになる
  4. 描いたあとでIllustrator等に取り込んで編集できる
  5. SSHでリモートアクセスしてその場で図が書ける
  6. 周囲の人に変態認定される
筆者は主にPythonのプログラムからPostScriptを出力して、論文に載せるための図を描いています。

基本的な書き方

EPSはJPEGやGIFなどのいわゆる画像ファイルとは異なり、「ページ記述言語」と呼ばれるプログラミング言語の一種です。 基本は「キャンパスの上で仮想的な筆を動かして図を描く」という考え方をします。

試しに、以下のようなソースを書いて test.eps という名前で保存すれば、「点(100,100)を起点とした、1辺が100の正方形」を描くことができます。

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 300 300

newpath        % 新しいパスを生成
100 100 moveto % ペンを(100,100)に移動
200 100 lineto % (200,100)まで直線を引く
200 200 lineto % (200,200)まで直線を引く
100 200 lineto % (100,200)まで直線を引く
100 100 lineto % (100,100)まで直線を引く
stroke         % このパスの輪郭を描く

%%EOF

線の色を設定する

線の描写を指示するstrokeより前に、色を指定するコマンドであるsetrgbcolorを入れると、線の色をRGB形式で指定できます。 RGB (赤、緑、青) の値はそれぞれ0〜1の範囲です。

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 300 300

newpath        % 新しいパスを生成
100 100 moveto % ペンを(100,100)に移動
200 100 lineto % (200,100)まで直線を引く
200 200 lineto % (200,200)まで直線を引く
100 200 lineto % (100,200)まで直線を引く
100 100 lineto % (100,100)まで直線を引く
1 0 0 setrgbcolor % 赤色に設定
stroke         % このパスの輪郭を描く

%%EOF

線の太さを指定する

太さは色と同様にsetlinewidthコマンドで

3 setlinewidth
このように指定します。 デフォルトの太さは1です。

塗りつぶし

「パスの輪郭を描写」を意味するstrokeの代わりにfillを使えば塗りつぶしができます。 線と塗りつぶしを両方使いたいときは、gsaveを使ってパスを一旦保存し、塗りつぶしを行ったあとでgrestoreで保存したパスを開いて輪郭の描写を行います。 (順番を逆にすると、輪郭の一部が潰れてしまいます。)

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 300 300

newpath        % 新しいパスを生成
100 100 moveto % ペンを(100,100)に移動
200 100 lineto % (200,100)まで直線を引く
200 200 lineto % (200,200)まで直線を引く
100 200 lineto % (100,200)まで直線を引く
100 100 lineto % (100,100)まで直線を引く
gsave          % パスを保存
1 0 0 setrgbcolor % 赤色に指定
fill           % パスを塗りつぶす
grestore       % 保存したパスを開く
0 0 0 setrgbcolor % 黒色に指定
stroke         % パスの輪郭を描く

%%EOF

正三角形を描く

次に正三角形を描いてみましょう。

正三角形の座標を指定するためには、sinやcosを使ってあらかじめ計算してもいいのですが、 せっかくなのでEPSの計算機能を使用してみましょう。

EPSでは、100 100 addと書くと、200と同じ意味になります。 20 30 mulならば600と同じです。 通常のプログラミング言語ならば100 + 100と書くところですが、 EPSは演算子が最後に来ます。このような記法を逆ポーランド記法といいます。

さて本題に戻りますが、三角形を書くためには「ある点から、120度の方向に、距離100だけペンを進める」という表記を使います。 これは数式にすると、x座標が100*cos(120), y座標が100*sin(120)という値になります。 100*cos(120)をPostScriptの記法で描くと、 100 120 cos mul となり、100*sin(120)は 100 120 sin mul となります。よって、上述の「120度の方向に、距離100だけペンを進める」というコマンドは

100 120 cos mul 100 120 sin mul rlineto
と書きます。 これを解釈すると、まず120 cosの部分が計算されて-0.5に、 120 sin0.866となるので、このコードは
100 -0.5 mul 100 0.866 mul rlineto
と同じ意味になります。 次に、100 -0.5 mulは掛け算なので-50、100 0.866 mulは86.6となるので
-50 86.6 rlineto
となります。 最後のrlinetoは、linetoと違って「現在のペンの位置から、指定された座標だけ移動する」という相対座標を表しています。 以上のことを踏まえて、三角形を描くEPSは以下のようになります。
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 300 300

newpath        % 新しいパスを生成
100 100 moveto % ペンを(100,100)に移動
100 0 rlineto % 相対座標(100,0)だけ線を引く
100 -0.5 mul 100 0.866 mul rlineto % 相対座標(100cos(120),100sin(120))まで直線を引く
closepath      % パスを閉じる
stroke         % パスの輪郭を描く

%%EOF

円を描く

円弧を描くときはarcというコマンドを使います。 角度の範囲が指定でき、0から360までにすると円になります。

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 50 50 150 150

newpath        % 新しいパスを生成
100 100 20 0 360 arc % (100,100)を中心に、0度から360度へ半径20の円弧を描く
stroke         % パスの輪郭を描く

%%EOF

変数・関数の使用

上に描いた方法で、この円を塗りつぶすことができます。 試しに、赤で塗りつぶし、黒で輪郭をつけた円を、x座標だけ変えて3個書いてみます。

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 50 200 150

newpath        % 新しいパスを生成
50 100 20 0 360 arc % (50,100)を中心に、0度から360度へ半径20の円弧を描く
gsave          % パスを保存
1 0 0 setrgbcolor % 赤色に指定
fill           % パスを塗りつぶす
grestore       % 保存したパスを開く
0 0 0 setrgbcolor % 黒色に指定
stroke         % パスの輪郭を描く

newpath        % 新しいパスを生成
100 100 20 0 360 arc % (100,100)を中心に、0度から360度へ半径20の円弧を描く
gsave          % パスを保存
1 0 0 setrgbcolor % 赤色に指定
fill           % パスを塗りつぶす
grestore       % 保存したパスを開く
0 0 0 setrgbcolor % 黒色に指定
stroke         % パスの輪郭を描く

newpath        % 新しいパスを生成
150 100 20 0 360 arc % (150,100)を中心に、0度から360度へ半径20の円弧を描く
gsave          % パスを保存
1 0 0 setrgbcolor % 赤色に指定
fill           % パスを塗りつぶす
grestore       % 保存したパスを開く
0 0 0 setrgbcolor % 黒色に指定
stroke         % パスの輪郭を描く

%%EOF
やたら同じコードの繰り返しで嫌になってしまいますね。 こういう場合は、プログラミング言語的な考え方として、変数・関数を使います。

EPSでは変数に値を代入するときはdefというコマンドを使います。 たとえばxに200という値を代入するときは

/x 200 def
と書きます。これを用いて
/x 200 def
/y 100 def
x y 20 0 360 arc
と書けば、
200 100 20 0 360 arc
と同じ意味になります。 代入時には/x、参照時にはxと書くので注意しましょう。

またEPSでは、数値だけでなく「図形そのもの」を変数に代入することができます。

/fig { (図形の描写) } def
このように書けば、変数figに図形を代入できる(つまり参照した時に図形の描写が行われる)ことができます。

たとえば、circleという変数に円の描写を代入すると

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 50 200 150

/circle {
	newpath        % 新しいパスを生成
	100 100 20 0 360 arc % (100,100)を中心に、0度から360度へ半径20の円弧を描く
	gsave          % パスを保存
	1 0 0 setrgbcolor % 赤色に指定
	fill           % パスを塗りつぶす
	grestore       % 保存したパスを開く
	0 0 0 setrgbcolor % 黒色に指定
	stroke         % パスの輪郭を描く
} def

circle % 定義した変数を呼び出し、円を描写

%%EOF
このようにして円を描くことができます。 しかし、これでは最初に指定した(100,100)の位置にしか円が出せません。 そこで、座標を引数で指定できるようにします。これにはexchコマンドを使います。

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 50 200 150

/circle {
	/y exch def    % 引数の値を変数yに代入
	/x exch def    % 引数の値を変数xに代入
	newpath        % 新しいパスを生成
	x y 20 0 360 arc % (x,y)を中心に、0度から360度へ半径20の円弧を描く
	gsave          % パスを保存
	1 0 0 setrgbcolor % 赤色に指定
	fill           % パスを塗りつぶす
	grestore       % 保存したパスを開く
	0 0 0 setrgbcolor % 黒色に指定
	stroke         % パスの輪郭を描く
} def

50 100 circle  % 引数(50,100)を指定してcircleを呼び出す
100 100 circle % 引数(100,100)を指定してcircleを呼び出す
150 100 circle % 引数(150,100)を指定してcircleを呼び出す

%%EOF
これで先ほどと同じ画像を描写することができます。

おまけ

こないだ(2012/12/02)書いた第五使徒ラミエル。

ソースコードはこちら。
製作時間は30分。

Last Modified: 2012/11/15