0pxの画像ファイル
序
0px.org というドメインを持っています。このドメインはなるべく短く、かつ意味ありげなドメインが欲しいと思って選んだだけで、特に意味はありません。専らサーバーの alias や短縮 URL に使っています。
さて、0px.org で配布すべきリソースとはなんでしょうか。当然 0px×0px の画像ファイルです。しかし、どんな画像編集ソフトでも大抵キャンパスサイズの最小は 1px×1px です。そもそも 0px の画像を許すフォーマットなどあるのでしょうか。というか画像を2次元的なものとするなら、0px×0px の画像は果たして画像なのでしょうか。
……とりあえず 0px 画像の哲学的な問いかけは一旦忘れることとして、思いついたメジャーな画像フォーマットについて仕様上 0px×0px の画像が許されるのか、調べることにしました。
PNG
3章 File Structure には PNG ファイルは PNG file signature(固定8バイト)と chunks からなるとされています。そのうち必須となる chunks が 4.1 Critical chunks に定められています。この中にある IHDR
ヘッダーに画像サイズが入っています。
The IHDR chunk must appear FIRST. It contains:
Width: 4 bytes
Height: 4 bytes
Bit depth: 1 byte
Color type: 1 byte
Compression method: 1 byte
Filter method: 1 byte
Interlace method: 1 byte
Width and height give the image dimensions in pixels. They are 4-byte integers. Zero is an invalid value.
したがって、残念ながら画像サイズは 1px×1px が最小であり、PNG では 0px×0px の画像は表現できないことになります。
JPEG
厳密には、 JPEG (ISO/IEC 10918 | ITU-T T.81) は画像の符号化についてのフォーマットであり、今日 .jpg .jpeg の拡張子でやり取りされるファイルフォーマットについては JFIF (JPEG File Interchange Format) として ISO/IEC 10918 Part.5 および ITU-T T.871 に規定されています。また、これを拡張した Exif も広く普及しています。
今回はこちらの W3C 掲載のJPEG 仕様書 および JFIF 仕様書 を参照します。
JFIF フォーマットは JPEG の SOI
(Start of Image) マーカーセグメント、JFIF 情報を格納する APP0
セグメントから始まり、画像データをコードした後、EOI
(End of Image) マーカーで終わります。
JPEG の画像データは DCT による量子化情報を記述するテーブル DQT
セグメント、 ハフマン符号化による圧縮を行うためのテーブル DHT
セグメント、実際のスキャンデータを格納する SOS
セグメント、スキャンデータの形式を格納する SOF0
セグメントからなり、これらが合わさり画像データを形成します。(最も基礎的な Baseline DCT の場合)
このうち、画像サイズに直接関わるのはピクセルアスペクト比を決める APP0
の Xdensity, Ydensity (両方 1
で PAR 1:1 となる)と SOF
の X および Y(スキャンデータのサンプル数)ですが
B.2.2 Frame header syntax
Y: Number of lines – Specifies the maximum number of lines in the source image. This shall be equal to the number of lines in the component with the maximum number of vertical samples (see A.1.1). Value 0 indicates that the number of lines shall be defined by the DNL marker and parameters at the end of the first scan (see B.2.5).
X: Number of samples per line – Specifies the maximum number of samples per line in the source image. This shall be equal to the number of samples per line in the component with the maximum number of horizontal samples (see A.1.1).
後続の表 B.2 に X および Y の範囲が記されていますが、X = 1~65535 Y = 0~65535 です。一応 DNL
セグメントの定義も覗いてみますが
B.2.5 Define number of lines syntax
...The DNL (Define Number of Lines) segment provides a mechanism for defining or redefining the number of lines in the frame (the Y parameter in the frame header) at the end of the first scan. ...
NL: Number of lines – Specifies the number of lines in the frame (see definition of Y in B.2.2).
この NL の値も 1~65535 です。よってJPEG でも 0px×0px の画像は表現できません。
一応 JPEG それ自体の仕様では Annex. B.5 Abbreviated format for table-specification data にフレームデータを持たない JPEG フォーマットというのも規定されており、一方 JFIF には APP0
が必須であるため、これに従えば SOI
APP0
EOI
からなる JPEG ファイルというのも考えることはできます。が、これは画像を持たないということであり、0px×0px を正しく表しているとは言えないのではないでしょうか。
BMP
BMP(Windows bitmap) のファイルフォーマットの仕様について調べようとしたんですが、正直 Wikipedia が一番詳しかったです。Windows の GDI による実装が事実上の標準として扱われているんだと思いますが、正式な仕様のありかを知っている方は教えてください……
BMP ファイルは BITMAPFILEHEADER
ヘッダから始まり、直後に画像情報を格納する DIB ヘッダ、ピクセルデータと続きます。まずはメジャーな DIB ヘッダである BITMAPINFOHEADER
を見てみます。
BMP は他の多くのデジタル画像フォーマットと異なり、左下を原点としてボトムアップにピクセルデータを記述するのが特徴的です。
biWidth
The width of the bitmap, in pixels.biHeight
The height of the bitmap, in pixels. If biHeight is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner. If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.
この biWidth および biHeight が画像サイズですが、ここに正の値が入ればボトムアップに、負の値ならトップダウン(BMPとしては一般的ではない)になります。ということは0は……?たぶん未定義動作でしょう。
より古い DIB ヘッダーの BITMAPCOREHEADER
も見てみます。
bcWidth
The width of the bitmap, in pixels.
bcHeight
The height of the bitmap, in pixels.
こちらは特に負数についての規定はありません。暗に正の値でボトムアップとなるようです。
とはいえ、値の型としては WORD
なので、0を入れられます。よって、0px×0px の画像は
|-------------BITMAPFILEHEADER-------------|----- 00000000 42 4d 1e 00 00 00 00 00 00 00 1a 00 00 00 0c 00 BITMAPCOREHEADER--------------|---pixel---| 00000010 00 00 00 00 00 00 01 00 01 00 00 00 00 00 ^^W^^ ^^H^^
こうなります!*1(強調した部分が bcWidth, bcHeight)
(誰か Windows プログラミング環境ある人に GDI で実際何が起きるのか確かめてみてもらいたい)
GIF
https://www.w3.org/Graphics/GIF/spec-gif89a.txtwww.w3.org
GIF ファイルフォーマットで必須とされているのはバージョンを示す Header ブロック(GIF87a
or GIF89a
6バイト)と画像情報を格納した Logical Screen Descriptor ブロック、ファイル終端の Trailer (0x3B 固定)のみです。
Logical Screen Descriptor の定義は以下です。
c. Syntax. 7 6 5 4 3 2 1 0 Field Name Type +---------------+ 0 | | Logical Screen Width Unsigned +- -+ 1 | | +---------------+ 2 | | Logical Screen Height Unsigned +- -+ 3 | | +---------------+ 4 | | | | | <Packed Fields> +---------------+ 5 | | Background Color Index Byte +---------------+ 6 | | Pixel Aspect Ratio Byte +---------------+ i) Logical Screen Width - Width, in pixels, of the Logical Screen where the images will be rendered in the displaying device. ii) Logical Screen Height - Height, in pixels, of the Logical Screen where the images will be rendered in the displaying device.
この Logical Screen Width と Logical Screen Height が画像サイズを規定します。入れられる値について Unsigned
とある以外は特に記述は見当たりませんが、0を入れてもいいはずです!
|-----Header------|----Logical S.D.-----|tr. 00000000 47 49 46 38 39 61 00 00 00 00 00 00 00 3b G I F 8 9 a ^^W^^ ^^H^^ pf bc ar ;
0px 画像に表示すべきデータもなにもないわけですから、Logical Screen Descriptor 以降の画像データは含みません。仕様にも "the entity Data may be repeated any number of times, including 0 times."(Appendix.B) と明記されていますから、これで最低限 GIF の仕様は満たしているはずです。
結
そういうわけで、 0px.org ではより小さく、より正しそうな上記14バイトの GIF 画像を配布することにしました。適当なパスの GET でも固定で 200 と GIF を返すので ping 代わりにお使いください。
画像フォーマットも改めて厳密に調べてみると色々分かって面白かったです。まあ大抵 0px×0px の画像は画像ではないとして考慮されていない雰囲気でしたが…… 当然大半のデコーダ/ライブラリで上に示した例はエラーになると思います。ちゃんちゃん
おまけ
TIFF
ちゃんと読み込んでいませんが、TIFF の ImageWidth と ImageLength はデータ型(SHORT
or LONG
)の指定があるのみで値域が明示されていないので、0px 画像を表現できる可能性があります。TIFF の中に JPEG を入れることも一般的なため、SOI
~EOI
だけの JPEG を入れて 0px JPEG をつくれるかも知れません。
SVG
ラスター画像でなければ、SVG は 0px×0px の画像を表現可能です。
<svg version="1.1" width="0" height="0" xmlns="http://www.w3.org/2000/svg"/>
例えばこのように書けると思います。
そのほか参考になったサイト
様々なファイルフォーマットについて、仕様上許される最小サイズのものを集めたリポジトリです。GIF ファイルはこの記事の解説によるもののようで、1px×1pxを Logical Screen Descriptor に書いているようです*2。JPEG は最低限 1px が表示できるような DCT テーブルとフレームのみを含んだ 107 バイトのものなのですが、前述のように JFIF には SOI
直後の APP0
が必須なので JFIF 準拠ではない生 JPEG ストリームです。逆にフレームを含まず JFIF 準拠な最小*3を提案できる気がするんですが…… Issue 立ててみようかな
JPEG フォーマット、GIF フォーマットに関する日本語文献です。特に JPEG は重厚でちゃんと読めてる自信がないので助かりました。