前回までは割と堅い感じでしたので、今回は少し気分を変えて画像を扱ってみましょう。といっても、今回は基本UNIX系のみです。とは言えテキストベースなので改行コード等に注意すればWindows 10でも作成できます。
ちなみにUNIX系だと画像処理の定番はImageMagicでしょう。macOSの場合はsipsがあり、コマンドラインから扱う事ができます。これに関しては、また別の機会に解説したいと思います。

画像形式

 今回扱うのはPBM、PGM、PPMの3つのうちPBMです。PBM、PGM、PPMいずれもテキストエディタで作成する事ができます。簡単な画像ならテキストエディタがなくてもコマンドラインから入力して作成できます。
 PBM、PGM、PPMは、それぞれ以下のような画像形式になっています。

・PBM (Portable Bit Map)
 白黒2値の画像(ビットマップ画像)

・PGM (Portable Gray Map)
 グレースケール画像(灰色の輝度情報だけを持つ画像)

・PPM (Portable Pixel Map)
 カラー画像(色の段階は任意。32bit固定ではなく64bitでも128bitでも可)

それにしてもPBM,PGM,PPMとは化石みたいな形式を出してきたなと思う人がいるかもしれません。 昔から画像形式には様々なものがありましたが、これらの画像形式はかなりパフォーマンスが悪いと言えます。なにせ、基本的にテキストなのでJPEG形式などと比べても格段にデータサイズが大きくなります。おまけに非圧縮。バイナリ形式でも非圧縮。まさに富豪的画像形式です。こんな感じなので、あまり使われる事もなく初めて知ったという人もいるかもしれません。
ただ、登場から40年以上経過しディスク容量も使えるメモリもCPUのパワーも桁違いに向上した今なら、富豪的画像形式も許されるのではないでしょうか。

という事で実際にテキストから画像にしてみましょう。今回は白黒のビットマップ画像を作成します。画像のサイズは8×8ドットです。

PBMは最初に画像形式、情報を示すヘッダーを書きます。最初の一行にはP1の文字を指定します。これがPBM形式である事を示す文字列になります。多くの場合、最初の数文字(数バイト)で画像の形式が判別できるようになっています。これはマジックナンバーと呼ばれます。拡張子で判別するだけの場合もありますが、拡張子と画像形式が一致している保証はありません。ファイルの拡張子が間違っていても、マジックナンバーにより正しい画像形式がわかる仕組みです。もちろん全ての画像形式でマジックナンバーがあるわけではありません。例えば画像の生データであるRaw形式には判別するマジックナンバーはありません。

P1のマジックナンバーの次の行には画像の横幅と縦幅を指定します。横幅と縦幅の間には半角空白を入れます。

その次の行からビットマップパターンを記述していきます。ビットマップは白黒2値なので0と1になります。0が白で1が黒になります。 以下のようにすると8×8ドットで真っ黒な画像になります。8×8ドットなので64個の1が並ぶことになります。

P1
8 8
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1

PBMの場合、数値の間には区切りとなる半角空白や改行があってもなくても問題ありません。以下のPBMデータは上記と同じ結果になります。

P1
8 8
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111

テキストエディタで作成しても構いませんが、ここはひとつ無理矢理コマンドラインから入力してみましょう。

コマンドラインから画像を作成

 基本的にはechoとリダイレクト(>)を使えば簡単にできます。ここらへんがテキストベースの画像形式のいいところです。
 作成する画像ファイル名はsample.pbmとします。作成するディレクトリはデスクトップとします。その方が分かりやすいからです。とりあえず、cdコマンドでカレントディレクトリをデスクトップにしておきます。

cd ~/Desktop

まず、ヘッダーは以下のようにして作成します。echoで指定している文字列は、これまでの連載とは異なりシングルクオート(')で囲んでいます。シングルクオートで囲むと囲んだ部分の文字列は、そのまま出力されます。今回はこのようにしないと期待通りにいかないことがあるためです。シングルクオート がないとecho 1 1>a.pbmとした時に、a.pbmファイルには1 1でなく1しか書き込まれません。これはコマンドラインから1>, 2>のように指定した場合、リダイレクト処理され、それぞれ標準出力先、エラー出力先とみなされてしまうからです。

echo 'P1'>black.pbm

これでヘッダーができました。本当にできたか不安なら以下のようにcatコマンドやless,moreコマンドで確認しましょう。

cat black.pbm

次に画像のサイズを追加します。テキストファイルに追加するには>>を使います。

echo '8 8'>>black.pbm

確認する場合はcatなどを使います。

確認したらビットマップ画像データとなる値を一行ずつ追加します。今回は真っ黒な画像なので全部1になります。0が白で、1が黒です。以下の例では見やすくするために数値と数値の間に半角空白を入れています。

echo '1 1 1 1 1 1 1 1'>>black.pbm

これを残り7回繰り返します。とりあえず手作業でカーソルキーの上を押してリターンキーを押すのを7回繰り返します。このくらいなら手作業の方が簡単かつ高速でしょう。

終わったらcatコマンドで確認します。

cat black.pbm
macOSでのアイコン表示

macOSでのアイコン表示

ただ、これでは本当に画像になっているのかわかりません。という事で画像を扱うアプリケーションで開いてみましょう。PBM形式に対応したアプリケーションで開くと8×8ドットの真っ黒な画像が表示されます。macOSなら画像ファイルとして作成した段階で自動的にアイコンで表示してくれるので便利です。また、macOS標準のプレビュー.appもPBM,PGM,PPMに対応しています。

  • macOSでのプレビュー表示

    macOSでのプレビュー表示

  • Adobe Photoshopで開いたところ

    Adobe Photoshopで開いたところ

  • RaspberryPIでのコマンド入力

    RaspberryPIでのコマンド入力

  • RaspberryPIでのプレビュー表示

今度は真っ白な画像を作成してみましょう。1を0にすれば真っ白な画像になります。先ほどと同じように作成しても構いません。 が、せっかくのコマンドなのでsedで0を1に置換して作成してみましょう。すでにあるblack.pbmを利用してwhite.pbmを作成します。

 sed s/'1 1 1 1 1 1 1 1'/'0 0 0 0 0 0 0 0'/ black.pbm > white.pbm

作成したファイルをアプリケーションで開くと真っ白な画像が表示されます。

0と1のパターンを以下のようにすると市松模様が表示されます。

P1
8 8
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0

今ではほとんど使われませんがビットマップフォントみたいなものも表示できます。まあ、テキストさえあれば手軽にビットマップフォントが作成できるとも考えられます。

P1
8 8
0 0 0 1 1 0 0 0
0 0 1 1 1 1 0 0
0 1 1 0 0 1 1 0
0 1 1 0 0 1 1 0
0 1 1 1 1 1 1 0
0 1 1 0 0 1 1 0
0 1 1 0 0 1 1 0
0 0 0 0 0 0 0 0