本連載で今回扱うのはPostScriptです。この言語はプリンターで実行されることを想定して開発されたページ記述言語の一種です。PostScripはスタック指向のプログラミング言語です。プログラミングを楽しめる上に、図形や文字を描画できるので、遊んで楽しい言語でもあります。今回はPostScriptで遊んでみましょう。

  • PostScriptを使ってPDFを生成してみよう

    PostScriptを使ってPDFを生成してみよう

PostScriptについて

PostScriptは1984年にアドビによって開発されたページ記述言語です。1985年にAppleのレーザープリンターに採用されて普及しました。なぜ印刷とプログラミング言語が関係するのか不思議に思うかもしれません。PostScriptが登場した時代、電子印刷はそれほど普及していませんでした。というのも、コンピューターとプリンターの通信速度は遅く、高品質な印刷データをプリンタに転送するのに膨大な時間がかかっていました。

それで、PostScriptでは印刷データを転送時間を短縮する目的のため、プリンター自身に計算能力を持たせることで転送時間の短縮を行ったのです。PostScriptデータをプリンターに送信すると、プリンター側でプログラムが実行されて、描画データを生成し印刷するという仕組みです。

単に長方形を描画するPostScriptであれば、長方形を描画するというコマンドと座標データだけ、つまり数バイトで済むのに対して、描画済みのビットマップデータを転送すると、その数百倍のデータ(例えば、600x800ピクセルに展開すれば48万バイト)を転送しなくてはなりません。PostScriptがいかに優れていたかが分かります。

PostScriptを書いてみよう - Ghostscriptのインストール

それでは、実際にPostScriptを書いてみましょう。現在、PostScriptを実行する最も簡単な方法はPostScript互換のフリーソフトのGhostsciptを使う方法です。

Windowsの場合、こちらGhostscriptのWebサイトからGhostscriptをダウンロードしましょう。ここでは、GNU Affero General Public Licenseのものを選びます。ダウンロードしたインストーラーをダブルクリックするとGhostscriptがインストールされます。

  • Ghostscriptのダウンロードサイト

    Ghostscriptのダウンロードサイト

macOSでGhostscriptをインストールするにはHomebrewを利用するのが簡単です。ターミナル.appを開いて以下のコマンドを実行します。

 brew install ghostscript

PostScriptでHello,World!

Hello, World!と表示する簡単なプログラムは以下のようになります。以下のプログラムを「hello.ps」という名前で保存します。

/Courier findfont 64 scalefont setfont
50 700 moveto
(Hello, World!) show
showpage

このプログラムの1行目ではフォントの設定を行います。そして、2行目で描画位置を指定します。「(x) (y) moveto」のように書きます。なお、PostScriptでは左下が座標の(0, 0)で右上に行くにしたがって座標が大きくなります。3行目では文字列(Hello, World!)を出力し、showpageでページを印刷します。

macOSでは以下のようなコマンドを実行すると、hello.pdfというPDFが作成されます。

gsc -sDEVICE=pdfwrite -o hello.pdf hello.ps

Windows版をインストールした場合、以下のようなバッチファイルを作成して実行するのが簡単です。一行目にGhostscriptのインストールパスにあるgswin32c.exeのフルパスを指定します。なお、インストールするバージョンによってフォルダ名などが異なりますので、一行目はインストール先に合わせて書き換えてください。

set GHOST="C:\Program Files\gs\gs9.53.3\bin\gswin32c.exe"
set INFILE="hello.ps"
set OUTFILE="hello.pdf"
%GHOST% -sDEVICE=pdfwrite -o %OUTFILE% %INFILE%
pause

すると、以下のようなPDFを作成します。

  • Hello,World!と表示するPostScript

    Hello,World!と表示するPostScript

PostScriptはスタック指向の言語であるため、座標を指定する命令movetoは『50 700 moveto』のように記述し、文字を描画する命令showも『(文字列) show』のように記述します。

FizzBuzz問題を解いてみよう

次に、PostScriptらしい計算のプログラムを作ってみましょう。なお、PostScriptはスタック指向型のプログラミング言語です。スタック指向の『スタック』というのは、コンピューターで用いられる基本的なデータ構造の一つです。スタック指向型のプログラミング言語は、このスタックの仕組みを使って計算を行うため、プログラムの解釈がしやすいというメリットがあります。

そして、スタック指向のプログラミング言語では計算式を逆ポーランド記法で記述することになります。逆ポーランド記法とは「3 5 add」のように記述する記法です。実際のところ、この逆ポーランド記法は日本語と相性がよく、「3に5を足す」と読むと意味を理解しやすいものとなっています。

もう一つ考えてみましょう。例えば、「2 3 mul 8 add」という逆ポーランド記法は、「2に3を掛けて8を足す」と読むことができます。値の後に適当な助詞を補うと日本語としてよく意味が分かるのです。筆者が開発している日本語プログラミング言語「なでしこ」も、ある意味逆ポーランド記法で書いていると言えないこともないです。 それでは、FizzBuzzのプログラムを見てみましょう。スタック指向であるため、初見の方はプログラムを読みづらいと思いますが、ゆっくり眺めてみてください。

% FizzBuzzのプログラム --- (*1)
/Courier findfont 20 scalefont setfont
/canvas_h 720 def % 描画サイズの高さ
/line_h 25 def    % 一行の高さ

% FizzBuzzの条件を定義 --- (*2)
/IsFizzBuzz { 15 mod 0 eq } def
/IsFizz     {  3 mod 0 eq } def
/IsBuzz     {  5 mod 0 eq } def

% 1から100まで1ずつ足して繰り返す --- (*3)
1 1 100 {
  % 描画位置を計算 --- (*4)
  /i 2 1 roll def % ループ変数の値を得る
  /j i 1 sub def
  /x j 25 idiv 130 mul 50 add def
  /y canvas_h j 25 mod line_h mul sub def
  x y moveto
  % FizzBuzzの条件を確認 --- (*5)
  i IsFizzBuzz { (FizzBuzz) } {
  i IsFizz     { (Fizz)     } {
  i IsBuzz     { (Buzz)     } { 
    i 100 string cvs 
  } ifelse } ifelse } ifelse
  show
} for

プログラムを実行してみましょう。macOSの場合以下のようなコマンドを実行するとPDFが生成されます。

gsc -sDEVICE=pdfwrite -o fizzbuzz.pdf fizzbuzz.ps

Windowsの場合、先ほどと同じように以下のようなバッチファイルを作ると良いでしょう。同様にGhostScriptのパスは書き換えてください。

set GHOST="C:\Program Files\gs\gs9.53.3\bin\gswin32c.exe"
set INFILE="fizzbuzz.ps"
set OUTFILE="fizzbuzz.pdf"
%GHOST% -sDEVICE=pdfwrite -o %OUTFILE% %INFILE%

プログラムを実行すると、FizzBuzz.pdfというPDFファイルが生成されます。PDFビューワーで開いてみると、次のように描画されます。

  • FizzBuzzのプログラムを実行した結果

    FizzBuzzのプログラムを実行した結果

簡単にプログラムについて解説します。(*1)ではフォントを指定し、描画サイズ、一行の高さを定義します。『/変数名 値 def』で変数の定義です。(*2)ではFizzBuzzの条件を判定する関数を定義します。『/関数名 { ... } def』で関数を定義します。PostScriptでは関数も変数も同じdefで定義します。(*3)では1から100まで1ずつ加算して繰り返すforを記述します。(*4)では描画位置を計算します。そして、(*5)でFizzBuzzの条件をifelseで判定し画面に描画します。なお条件分岐のifelseの書式は『条件式 { 真の時の処理 } { 偽の時の処理} ifelse』となっています。

まとめ

以上、今回はPostScriptについて紹介してみました。もちろん手書きで直接PostScriptデータを記述する人は多くないかもしれません。しかし、PostScriptの偉業は開発から何十年経った今でも動かすことができる環境があることからも分かります。美しいPDFが生成できるPostScript、皆さんも遊んでみてください。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。直近では、「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」「すぐに使える!業務で実践できる! PythonによるAI・機械学習・深層学習アプリのつくり方 TensorFlow2対応(ソシム)」「マンガでざっくり学ぶPython(マイナビ出版)」など。