PNM (画像フォーマット)

PNM (Portable Any Map 形式、Netpbm形式) は簡素な2次元ラスター画像形式のひとつである。PNMは特定の1種類の画像フォーマットではなく、異なるカラーモードをサポートするための3種類の画像形式をまとめて呼ぶときに使われる総称である。これらの形式は、それぞれ portable pixmap format (PPM 形式)、portable graymap format (PGM 形式)、portable bitmap format (PBM 形式) と呼ばれ、いずれも異なるプラットフォーム間でも高い互換性を保てる画像形式として開発されたものである。

 開発の経緯 

PBM形式はプレーンテキストとして電子メールで受送信でき、ASCII コードが廃れた後でも使える画像フォーマットを開発する目的で、1980年代にJef Poskanzerが考案した白黒二値のビットマップ画像のデータ形式である。

PBM形式の画像を扱うツールを開発するために、Pbmplusというライブラリが開発された。これはPBM提案者のJef Poskanzerによるもので、1988年にリリースされた。続いて彼はPGM形式およびPPM形式を提唱し、それを扱うために拡張したPbmplusをリリースした。Pbmplusは1991年12月10日までリリースが続いた。

1993年に、そのときにはすでに開発が止まっていたPbmplusの代替となるライブラリとしてNetpbmが開発された。これはPbmplusに世界各地から寄せられた修正案を適用し、まとめ直したものであった。現在、PBM、PGM、PPM形式画像を扱うライブラリとして最も多く利用されているのはNetpbmであろうと考えられている。

 データ形式 

各形式は、色をどう表現するかという点で異なっている。
 PBM は本当の意味でのビットマップである (白と黒の二値しか表現しない)
 PGM はグレイスケールを表現できる
 PPM は RGB でフルカラーを表現できる、"pixmaps" である

どの形式でも最初の2バイト (テキスト形式) がマジックナンバーとなっており、ファイル形式 (PBM、PGM、PPMのどれか) と、データがテキストかバイナリかを表している。その2バイトの最初は大文字の P で、その後に続く1つの数字が種類を表す。
 File Descriptor Type Encoding P1 Portable bitmap ASCII P2 Portable graymap ASCII P3 Portable pixmap ASCII P4 Portable bitmap Binary P5 Portable graymap Binary P6 Portable pixmap Binary

テキスト形式のデータは、テキストエディタなどで見るのも、他の形式に変換するのも容易である (そういう作業を行うプラットフォームで ASCII コードが正しく扱えるのであれば)。バイナリ形式ではファイルサイズが節約でき、ファイル中に空白文字がないため簡便な方法でファイルを解析できる。また、どちらの形式でも圧縮は行なわない。

バイナリ形式のとき、1ピクセルはPBM形式では1ビットで、PGM形式では8ビット (明度最大値が256未満の場合) または16ビットで、PPM形式では8ビット×3 (明度最大値が256未満の場合) または16ビット×3で表される。PPM形式では、赤(R)、緑(G)、青(B)のそれぞれが8ビットまたは16ビットで表される。不透明度 (アルファチャンネル) やクロマキーはサポートされない。ラスター行に関して、PBMは8ビット (1バイト) 境界を持ち、幅が8の倍数でない場合、最後の8ビットにはパディングのための不要なビットが含まれる。PGMおよびPPMは8ビット境界を持ち、他の多くの画像形式で必要とされる32ビット (4バイト) 境界のパディングは必要ない。

 PBM の例 

以下にPBM形式の簡単な例を示す。

 P1
 # This is an example bitmap of the letter "J"
 6 10
 0 0 0 0 1 0
 0 0 0 0 1 0
 0 0 0 0 1 0
 0 0 0 0 1 0
 0 0 0 0 1 0
 0 0 0 0 1 0
 1 0 0 0 1 0
 0 1 1 1 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0

最初の "P1" という文字列で、これがPBM形式であることが示されている。番号記号 (シャープ記号) は、その行がコメント行であることを示す。その下の2つの数値はそれぞれ画像の横幅と高さを示す。その後にピクセルの値 (PBMは白黒画像なので、0 か 1 のどちらかだけ) が続く。各ピクセルデータを表す数字 (0/1) の間には、空白があってもなくてもかまわない。通例1は黒を、0は白を表す。

以下に、このデータが表す画像を示す。

 

以下に、この画像を20倍に拡大したものを示す。

 PGM の例 

PGMとPPMの各形式では、テキスト形式でもバイナリ形式でも、画像中に現れるピクセルの明度の最大値（）を、画像のサイズの後に示す必要がある。

 P2
 # Shows the word "FEEP" (example from Netpbm man page on PGM)
 24 7
 15
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0
 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0
 0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0
 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0
 0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

このデータが示す画像 (を25倍に拡大したもの) は以下のようになる:

 PPM の例 

 P3
 # The P3 means colors are in ASCII, then 3 columns and 2 rows, then 255 for max color, then RGB triplets
 3 2
 255
 255 0 0
 0 255 0
 0 0 255
 255 255 0
 255 255 255
 0 0 0

上のデータが示す画像 (を64倍に拡大したもの):

P6 (バイナリ形式) では、各ピクセルのR、G、Bの各成分が、この順番でそれぞれ1バイトで表される (したがって各ピクセルが3バイトで表される)。ファイルサイズはテキスト形式の1/2~1/4程度に小さくなるが、データを直接見ても分かりにくい。

PBM/PGM/PPM形式はデータの圧縮を行なわないため、圧縮を行なう形式の画像と比べるとファイルサイズが大きくなる。たとえば上のPNG画像はサイズが192x128で166バイトだが、これを同じサイズのPPM画像に変換すると約72Kバイトになる。PPM形式は適当なライブラリの支援を受けずに画像の操作を行なうときや、圧縮伸張のコストを掛けずに画像の操作を行ないたいときに使い、最終的にはPNGなどの可逆圧縮をサポートする、より効率のよい形式にするのがいいだろう。

 16ビット拡張 
PGM形式とPPM形式の元々のバイナリ形式 (P5およびP6) では、ビット深度は8ビットまでしかサポートしていなかった。テキスト形式でこれを拡張するのは容易だが、それにより画像の操作に時間がかかるようになり、またファイルサイズも大きくなる。そこで、多くの拡張法が試みられた。しかしビット深度を8ビットよりも大きくすると、エンディアンの問題が生じ、様々な実装でバイトオーダーが一致しないという事態が生じた。なお、実装のデファクトスタンダードであるNetpbmではビッグエンディアンである。