掴んだ物(技術)はちゃんと食べる記録帳

興味を持ったものに対する足跡を残していくために作成しました。勉強しながら書いているので、間違いや短絡もあると思います。ご指摘いただけると喜びます。

Let's PostScript(4) 関係オペレータで比較する

関係オペレータ

制御をおこなうためには、2つのObjectを比較評価する必要があるわけで、このような処理を行うオペレータを関係オペレータ(Relational Operator)といいます。 Post Scriptの比較評価結果はtruefalseのみです。

文法は object1 object2 xx となり、2つのObjectの関係を評価します。これは、表にしてしまったほうが分かりやすいかもしれません。

関係オペレータ 処理内容
eq 2つのObjectが等しければOperandStackにtrueを格納する
ne 2つのObjectを等しくなければOperandStackにtrueを格納する
ge 2つのObjectの>=の大小比較を行い、結果をOperandStackに格納する
gt 2つのObjectの>の大小比較を行い、結果をOperandStackに格納する
le 2つのObjectの<=の大小比較を行い、結果をOperandStackに格納する
lt 2つのObjectの<の大小比較を行い、結果をOperandStackに格納する

評価可能なオブジェクトは数値と文字列となります。 文字列は一般的なソートのルールが適用されるようです。また文字列はどのような表現方法で指定しても同じ文字列となれば正しく評価されるようです。

GS>(b) (abc) gt ==
true
GS>(abc) <616263> eq ==
true

本を見ると、eqオペレータとneオペレータは任意のObjectが比較できるようなのですが、配列でやってみたところ、うまくいきませんでした。 このあたりよくわからないので、後日の課題としたいと思います。

GS>[1 2 3] [1 2 3] eq ==
false

次回は、手続きオブジェクトと制御オペレータについてみていきたいと思います。

Let's PostScript(3) Operand Stackの操作

今日は久しぶりの飲み会でした。送別会だったのですが。そんなわけで、今日は簡単に済ませます。

StackはLIFO(Last In First Out)

Stackは達磨落としのような感じで最後に入れた(Push)Objectが最初に出てきます(Pop)これをLIFOといいます。 実際に、Ghost Scriptでスタックを積むとこのような感じになります。

GS>1 2 3 4 5
GS<5>stack
5
4
3
2
1

これを取り出すとFILOに基づいて、入れた順番の逆順で取り出されます。

GS<5>==
5
GS<4>==
4
GS<3>==
3
GS<2>==
2
GS<1>==
1

OperandStackの操作をするオペレータ

OperandStackはPostScriptのデータの受け渡しの中核を担い、アルゴリズムによって多様な利用が行われます。 そのため、OperandStackにはたくさんのStack操作用のオペレータが用意されています。

popオペレータ

OperandStackの一番上の要素を破棄する。

GS>1 2 3 4 5
GS<5>pop
GS<4>stack
4
3
2
1

exchオペレータ

OperandStackの上位2つのオブジェクトの位置を入れ替える。

GS>1 2 3 4 5
GS<5>exch
GS<5>stack
4
5
3
2
1

dupオペレータ

OperandStackの一番上の要素をコピーする。

GS>1 2 3 4 5
GS<5>dup
GS<6>stack
5
5
4
3
2
1

copyオペレータ

OperandStackからコピー数を受け取り、OperandStackの一番上からコピー数の要素をコピーする。

GS>1 2 3 4 5
GS<5>3
GS<6>copy
GS<8>clear
GS>1 2 3 4 5
GS<5>3 copy
GS<8>stack
5
4
3
5
4
3
2
1

indexオペレータ

OperandStackから任意の位置を受け取り、OperandStackの上から数えた任意の位置※の要素をコピーする。 ※一番上の要素を0とする。

GS>1 2 3 4 5
GS<5>1 index
GS<6>stack
4
5
4
3
2
1

rollオペレータ

OperandStackから要素数と、回転数を受け取り回転させる。

GS>1 2 3 4 5
GS<5>4 1 roll
GS<5>stack
4
3
2
5
1

clearオペレータ

OperandStackのObjectを破棄する。

GS>1 2 3 4 5
GS<5>clear
GS>

countオペレータ

Operand Stackのオブジェクトをカウントし、カウント数を格納する。

GS>1 2 3 4 5
GS<5>count
GS<6>==
5
GS<5>

markオペレータ

mark ObjectをOperandStackにPushする。 markは配列や処理の終了時の不要となったObjectの破棄等、多様な用途で使用することになる。

counttomarkオペレータ

一番上のmarkの上にある要素数をカウントし、カウント数を格納する。

GS>1 2
GS<2>mark
GS<3>3 4 5
GS<6>counttomark
GS<7>==
3
GS<6>

cleartomarkオペレータ

一番上のmarkの上にある要素とmark自身を破棄する。

GS>1 2
GS<2>mark
GS<3>3 4 5
GS<6>cleartomark
GS<2>stack
2
1

次は、条件判断や反復等の制御公文についてみていこうと思います。

Let's PostScript(2) ObjectとOperand Stack

前回以下の実行結果で出てくるGS<...>のカッコ内の数字は何者かというところで話を切りましたが、これはいまOperand Stackに積まれているStackの段数を示しています。

GS>/Helvetica
GS<1>findfont
GS<1>20
GS<2>scalefont
GS<1>setfont
GS>0 0
GS<2>moveto
GS>(Hello World!!)
GS<1>show
GS>0 0
GS<2>moveto
GS><48656C6C6F20576F726C642121>
GS<1>show
GS>showpage
>>showpage, press <return> to continue<<

Operand Stackに積まれるのはObjectです。PostScriptで扱われるすべてObjectとなっています。 それぞれのObjectには属性が存在していますが、そのうちの一つが属性が実行可能とLiteralの属性です。

PostscriptのインタープリタがObjcetを実行する場合、そのObjectの属性が実行可能か、Literalかによりその動作が変わります。

属性 動作
実行可能 インタープリタによって直ちに実行される
Literal Operand StackにPushされる

OperandStackは実行可能Objectが受け取るLiteralObjectやその結果を格納するために使用されます。 ここで先ほどの実行内容とスタックを整理してみます

GhostScript コメント
GS>/Helvetica /で始まるのはLiteralの名前ObjectなのでStackへPush(0->1)
GS<1>findfont findfontはオペレータで実行可能。OperandStackからフォント名を受け取り(1->0)、フォント定義を格納したフォント辞書をOperandStackに返す(0->1)
GS<1>20 整数(20)は常にLiteral ObjectなのでStackへPush(1->2)
GS<2>scalefont scalefontはオペレータで実行可能、グリフサイズのスケーリングの倍率を受け取り(2->1)、倍率に拡縮したフォント辞書を作成する
GS<1>setfont setfontはオペレータで実行可能、フォント辞書を受け取り(1->0)グラフィックスのフォントパラメータへ反映する
GS>0 0 整数のObject2つをStackへ格納する(0->2)
GS<2>moveto movetoはオペレータで実行可能、x yをOperandStackから受け取り(2->0)、カレントポイントを設定する
GS>(Hello World!!) Literal文字列をOperandStackへPush(0->1)
GS<1>show showはオペレータで実行可能、文字列を受け取り(1->0)グラフィックスのフォントパラメータで描画する
GS>100 100
GS<2>moveto
GS><48656C6C6F20576F726C642121> 16進文字列をOperandStackへPush(0->1)
GS<1>show
GS>showpage カレントページを出力デバイスへ描画する

このような感じで、PostscriptはOperandStackを介してObjectをやり取りし、スクリプトを消費していきます。 そのため、PostScriptには豊富なStack操作を目的としたオペレータが用意されています。

次回はOperandStackの操作を方法を見ていきたいと思います。

Let's PostScript(1) Hello World!!

教材と環境

いまさらながら、PostScript(一部PDF)について、ざっくりと勉強していこうと思います。

使用する教材は、いわゆる赤本です。

環境はGhostScriptのVersion9.52を用います。

対話モードで遊ぶ

引数なしでGhostScriptを起動すると、対話モードで起動するので、これを使って描画してみます。

GPL Ghostscript 9.52 (2020-03-19)
Copyright (C) 2020 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
GS>

Hello world

PostScriptは文字列の表現方法として3つの種類があります。

  • テキスト(Hello World!!)
  • 16進データ<48656C6C6F20576F726C642121>
  • ASCII85データ※今は扱わない。

ASCII85は対話モードで使うには無理があるので、まずは上記二つのHallo world!!を表示します。

文字を表示するには、"どの書体で、どのサイズで、どこに、何を書くかを示す必要があります。

フォントの選択

findfontオペレータで選択します

書式設定

scalefontオペレータで指定します。

座標指定

movetoオペレータで指定します。

文字指定

テキスト(Hello World!!)

16進データ<48656C6C6F20576F726C642121>

で今回はHello Worldします。

初めてのshowpage

これをGhostScriptの対話モードで入力していくとこのような感じになります。

GS>/Helvetica findfont 20 scalefont setfont
GS>0 0 moveto
GS>(Hello world!!) show
GS>100 100 moveto
GS><48656C6C6F20576F726C642121> show
GS>showpage
>>showpage, press <return> to continue<<

最後のshowpageで画像を出力します。出てくる画像は以下のようなものです。ほとんどが空白なのですが、少し下にスクロールすると、Hello Worldが見えてきます。

f:id:hlsme:20200927181453j:plain

リテラルテキストのHello World(座標0,0)が下で、16進データで指定したHellow World(座標100,100)が上です。 違和感を感じますが、この辺りはグラフィックのあたりで勉強していこうと思います。

最後に、先ほどのHello Worldですが、複数のオペレータをまとめて実行しているので、できるだけ細かく指示しなおしてみます。出力される画像は同じです。

GS>/Helvetica
GS<1>findfont
GS<1>20
GS<2>scalefont
GS<1>setfont
GS>0 0
GS<2>moveto
GS>(Hello World!!)
GS<1>show
GS>0 0
GS<2>moveto
GS><48656C6C6F20576F726C642121>
GS<1>show
GS>showpage
>>showpage, press <return> to continue<<

増減するGS<...>は何なんのかってあたりを次回勉強していこうかと思います。