今回も前回に引き続いてGhostScript/PostScriptを使って図形を描きます。

四角形を表示する(rectfill, rectstroke)

 次に四角形を表示してみましょう。塗りつぶされた四角形を描く場合はrectfill、線だけの四角形を描くにはrectstrokeを使います。どちらの命令も値は4つで以下の順番で指定します。

X座標 Y座標 横幅 縦幅

以下の例では座標(20,80)に横幅、縦幅ともに100の四角形が描かれます。

【rect1.ps】

%!PS
1 0 0 setrgbcolor
20 80 100 100 rectfill
showpage

線だけの場合は以下のようになります。

【rect2.ps】

%!PS
1 0 0 setrgbcolor
20 80 100 100 rectstroke
showpage

次に四角形の色を変えて描いてみます。色を変えるにはプログラムで言うところの変数を使います。GhostScript/PostScriptでは名前と値を辞書に登録することで変数と同じように使うことができます。
辞書に登録するには/の後に名前を書いて、その後に定義内容を書きます。そして最後にdefを指定します。
以下の例ではRという名前の内容を0にしています。一般的なプログラム言語では「R=0」と同じです。

/R 0 def

変数の値を計算する場合も同様に名前と辞書への登録になります。以下の例ではRに0.2を足します。一般的なプログラム言語では「R=R+0.2」と同じです。

/R R 0.2 add def

次に繰り返しですが、単純に繰り返すだけであれば以下のようになります。

繰り返し回数 {
 繰り返す内容
} repeat

四角形をずらすためにtranslateを使って座標系を変えます。translateは横方向のずれと縦方向のずれ(オフセット/相対座標)を示す2つの値が必要です。以下の例では横方向に100、縦方向に0だけ座標系を移動されます。これにより原点座標が変わるためrectfillなどで指定した図形をずらして描画することができます。

100 0 translate

以下のようにすると四角形が5つ色を変えながら横に描画されます。

【rect3.ps】

%!PS
/R 0 def
0 400 translate
5 {
 R 0 0 setrgbcolor
 0 0 100 100 rectfill
 100 0 translate
 /R R 0.2 add def
} repeat
showpage

repeatは入れ子にすることができます。せっかくなので赤と緑の4色グラデーションのような感じで描いてみましょう。
横と縦方向に座標をずらして描画しますが、座標系を保存するためにgsave、座標系を復元するためにgrestoreを使います。

【rect4.ps】

%!PS
/G 0 def
10 100 translate
5 {
 /R 0 def
 gsave
 5 {
  R G 0 setrgbcolor
  0 0 100 100 rectfill
  100 0 translate
  /R R 0.2 add def
 } repeat
 grestore
 0 100 translate
 /G G 0.2 add def
} repeat
showpage

もっと細かく描画したい場合は繰り返しの数と移動量、色の変化量などを変更します。本当は移動量や変化量などは/で始まる名前で定義した方がいいのですが、気になる人は挑戦してみてください。

【rect5.ps】

%!PS
/G 0 def
10 100 translate
50 {
 /R 0 def
 gsave
 50 {
  R G 0 setrgbcolor
  0 0 10 10 rectfill
  10 0 translate
  /R R 0.02 add def
 } repeat
 grestore
 0 10 translate
 /G G 0.02 add def
} repeat
showpage

四角形を表示する(パスでつなぐ方法)

 次に四角形を直線のパスをつなげて表示してみましょう。単純な四角形であればrectstrokeやrectfillで問題ありませんが、四角形っぽい複雑な図形やAdobe Illustratorなどの編集ソフトを作るような場合には図形はパスで構築した方が便利な面があります。(既存アプリケーションに不満がある人は挑戦してみるといいかもしれません)
 パスで四角形を構築するにはmovetolinetoを組み合わせます。その際、newpath/closepathを使って複数の直線の組み合わせを1つのパスとして構築します。
 また、作成したパスを再利用する場合は/名前 {〜} として作成したパスに名前を付けておきます。
 以下の例では四角形にboxという名前を付けて赤い線で描画しています。

【path1.ps】

%!PS
/box {
 newpath
 0 0 moveto
 0 100 lineto
 100 100 lineto
 100 0 lineto
 closepath
} def

20 400 translate
1 0 0 setrgbcolor
box
stroke
showpage

線でなく赤色で塗りつぶしたい場合は以下のようにfillを使います。

【path2.ps】

%!PS
/box {
 newpath
 0 0 moveto
 0 100 lineto
 100 100 lineto
 100 0 lineto
 closepath
} def

20 400 translate
1 0 0 setrgbcolor
box
fill
showpage

塗りを赤色、線を青色にする場合は以下のようになります。先に塗った後に線を描いていますが、strokeとfillの順番を入れ替えれば線を描画した後に塗り潰した四角形が表示されます。

【path3.ps】

%!PS
/box {
 newpath
 0 0 moveto
 0 100 lineto
 100 100 lineto
 100 0 lineto
 closepath
} def

20 400 translate
1 0 0 setrgbcolor
box
fill
box
0 0.2 1 setrgbcolor
10 setlinewidth
stroke
showpage

ベジエ曲線を表示する

 次にベジエ曲線を表示してみましょう。GhostScript/PostScriptで採用されているベジエ曲線は3次のベジエ曲線です。この3次ベジエ曲線は4つの座標をスムーズに結ぶ曲線です。

ベジエ曲線を描くにはcurvetoを使います。パラメーターはx1 y1 x2 y2 x3 y3の合計6つです。あれ?ベジエ曲線は台形だから4つの点が必要、つまり8つのパラメーターが必要なのでは?と思った人もいるかもしれません。実は残りの1つの座標(開始座標)は現在のペンの位置になります。このようにしておくことで連続した曲線や直線を描くのが容易になるためです。また、多少なりともデータサイズの節約にもなります。と書いても昔と違って今はデータサイズを気にするようなことはないでしょう。

 実際にベジエ曲線を描くコードは以下のようになります。

【bez1.ps】

%!PS
newpath
50 100 moveto
80 140 180 100 250 50 curveto
stroke
showpage

連続したベジエ曲線を描く場合は以下のように続けて座標値とcurvetoを指定します。ちなみに初期のベクトルフォントであるAdobe Type 1 Fontはベジエ曲線の組み合わせでしたが、これはフォントのような角が多い場合に角が作りやすいベジエ曲線はデータサイズが軽減されるから、という理由もあったかもしれません。その後、対抗馬として登場するTrueTypeは3次ベジエ曲線でなく2次ベジェ曲線が採用されています。

・TrueType Reference Manual
https://developer.apple.com/fonts/TrueType-Reference-Manual/

【bez2.ps】

%!PS
newpath
50 100 moveto
80 140 180 100 250 50 curveto
300 100 320 120 340 10 curveto
stroke
showpage

単純な線の組み合わせではなく閉じられた図形としたい場合は、これまでにも出てきたnewpath,closepathを使います。なお、始点と終点は自動的に繋げられます。

【bez3.ps】

%!PS
newpath
50 100 moveto
80 300 180 120 250 50 curveto
closepath
stroke
showpage

fillを使って塗り潰すこともできます。線も描く場合は前に説明した四角形と同様に名前を付けて再利用します。

【bez4.ps】

%!PS
newpath
50 100 moveto
80 300 180 120 250 50 curveto
closepath
1 0 0 setrgbcolor
fill
showpage

ベジエ曲線の制御点なども表示し分かりやすく処理したい場合は以下のプログラムを使ってください。なお、これはChatGPT(AI)を使って作成されたプログラムです。
若干補足しておくと%はPostScriptではコメントになります。%より後の文字は無視されます。ただし、PostScript (EPS) では%%のように連続して%を記述した場合、メタコメントとして扱われ%%の後に続く文字は意味を持ちます。
例えば以下のメタコメントは図形を内包する矩形範囲を座標で示しています。

%%BoundingBox: 0 0 48 31

【bez5.ps】

%!PS
% ---- 制御点+曲線を表示する手続き ----
/showBezier {
    % スタックに P0x P0y  P1x P1y  P2x P2y  P3x P3y の順に積んで呼び出す

    % 値の取り出し
    /y3 exch def  /x3 exch def
    /y2 exch def  /x2 exch def
    /y1 exch def  /x1 exch def
    /y0 exch def  /x0 exch def

    % --- ベジエ曲線(太めの線) ---
    gsave
        2 setlinewidth
        0 0 0 setrgbcolor
        newpath
        x0 y0 moveto
        x1 y1  x2 y2  x3 y3 curveto
        stroke
    grestore

    % --- 制御線目印(P0-P1, P2-P3) ---
    gsave
        0.7 setgray
        1 setlinewidth
        newpath
        x0 y0 moveto  x1 y1 lineto
        x2 y2 moveto  x3 y3 lineto
        stroke
    grestore

    % --- 制御点(丸で表示) ---
    /dot {
        % x y -> 点を描く
        newpath
        3 0 360 arc
        fill
    } def

    1 0 0 setrgbcolor    x0 y0 dot   % 開始点(赤)
    0 0 1 setrgbcolor    x1 y1 dot   % control1(青)
    0 0 1 setrgbcolor    x2 y2 dot   % control2(青)
    0 1 0 setrgbcolor    x3 y3 dot   % 終点(緑)

} def

% ---- 使用例 ----
% P0  P1  P2  P3 の座標
100 100   150 200   200 0   300 100 showBezier

showpage

座標を変えて座標点と曲線の関係を見てみるとよいでしょう。以下の座標はbez1.ps〜bez4.psで使用したものです。

% ---- 使用例 ----
% P0  P1  P2  P3 の座標
50 100   80 300 180 120 250 50 showBezier

ビットマップ/ピクセルデータを表示する

 次にビットマップデータを表示してみます。ビットマップの場合は白黒データになるので値の0と1のビットパターンで示します。
以下の例では8×8サイズのビットパターンを描画します。ただし、そのままでは非常に小さいサイズになってしまうのでscaleを使って縦横80倍に拡大しています。表示する位置はtranslateでX座標、Y座標の順番でしてします。
 肝心のビットマップデータは必要な数だけ<と>に16進数値を書きます。その際、空白はあってもなくても構いません。以下のパターンは市松模様っぽいものが描かれます。(どちらが上下なのか多少わかるパターンにしてあります)

【bit1.ps】

%!PS
/width  8 def
/height 8 def
50 40 translate
80 80 scale
width height 1
[ width 0 0 height neg 0 height ]
{
  <2A 55 AA 55 AA 55 AA 25>
} image
showpage

RGBカラーの場合は1ピクセルにつきRGB8ビットずつの値が必要になります。FF0000なら赤、00FF00なら緑、0000FFなら青になります。この1ピクセルデータを表示する数だけ<と>の間に書きます。
以下の例では赤、緑、青、黒の4つの四角形が表示されます。また、カラーの場合はimageでなくcolorimageになります。

【bit2.ps】

%!PS
/width  2 def
/height 2 def
50 40 translate
80 80 scale
width height 8
[ width 0 0 height 0 0 ]
{
  <FF0000 00FF00 0000FF 000000>
} false 3 colorimage
showpage

GhostScript/PostScriptは印刷向けという面もあるのでCMYKカラーで指定することもできます。この場合、1ピクセルにつきCMYKの4つの値が必要になります。(C:シアン、M:マゼンタ、Y:イエロー、K:黒/ブラック)
また、色空間をCMYKにして正しい色で処理されるようにします。
以下の例では赤、緑、青、黒の4つの四角形が表示されます。RGBと違って若干色褪せた感じになります。

【bit3.ps】

%!PS
/width  2 def
/height 2 def
50 40 translate
80 80 scale
[/DeviceCMYK] setcolorspace
width height 8
[ width 0 0 height 0 0 ]
{
  <00FFFF00 FF00FF00 FFFF0000 000000FF>
} false 4 colorimage
showpage

ビットマップ、RGB、CMYK以外にもグレースケールで指定することができます。この場合、1ピクセルの輝度を16進数値1バイトで示すことになります。これまでと同様に必要な数だけ<と>の間に値を指定します。

【bit4.ps】

%!PS
/width  2 def
/height 2 def
50 40 translate
80 80 scale
[/DeviceGray] setcolorspace
width height 8
[ width 0 0 height 0 0 ]
{
  <00 40 80 E0>
} image
showpage

次回はプログラミング言語っぽく計算などを行ってみます。

著者 仲村次郎
いろいろな事に手を出してみたものの結局身につかず、とりあえず目的の事ができればいいんじゃないかみたいな感じで生きております。