jpegファイルフォーマットについてちょっと調べた

jpegファイルの構造がどうなってるのかなと思ってちょっと調べたのでまとめ。

jpegファイルは大まかに[ヘッダ+画像データ+フッタ]でできている。

jpegファイルは必ずFFD8ではじまる。

FFD8以降はヘッダの部分でJFIF形式になっている。

JFIF形式はこんな感じで最初の2 byteがフィールドの種類(必ずFFで始まるので255種類)、次の2 byteがデータサイズ(最大0xFFFF=65535 byte)、残りがサイズ分のデータ、のセットが順々に並んでいる。

フィールド種類(2 byte) サイズ(符号なし整数2 byte) 中身(サイズ byte)
FFE0 0024 ...
FFD0 0012 ...
FFDB 0022 ...
... ... ...
FFDA 0012 ...

最初は必ずFFE0の「これ以降はJFIF形式ですよ」という意味にフィールドで始まる。

FFDBやFFC4など同じフィールドが何度も出たり、必ず無いといけないものやなくてもいいものが混ざっている。

最後は必ずFFDA(sos)で終わる。これが「これから画像データ読みまっせ」という意味のフィールドだからだ。

各フィールドについては調べた感じ、次のサイトが詳しく解説されていた。 JPG ファイルフォーマット

このフィールドのうち、FFE1(APP1)はデータ部分が"Exif\0\0"の6byteで始まっていればExif形式のデータが入っている。

Exif形式は入っている情報が多く、画像の縦横サイズはもちろん、ピントの深度・カメラの回転方向・撮ったカメラの種類、gps情報まで入っている。flickrに出てくる情報もExifを元に表示しているものと思われる。

そのデータ量は例えばiPhoneで写真を撮ると、およそ12K byteにもなる。 これはバカに出来ないデータ量で、「jpegのメタ情報を削ってファイルサイズを減らそう!」という記事が多くあるのはこのためだ。

因みにiPhonesafariから撮った写真をhtmlフォームの<input type='file'>で送ると、gps等のかなりのデータが勝手に削除された状態で送信される。(2016/08現在、最新のiOSでは勝手にExifを削除しなくなったようだ。)

また、Exif情報のうちのカメラの回転方向を読み取って勝手に回転してくれるブラウザもある。Chrome(39.0.2171.95)では回転せず、iPhonesafariFirefox(34.0.5)では回転が確認できた。ブラウザ依存で動作が変わる厄介な仕様でもある。

うまく全てのブラウザで同じように表示させようとするなら、imagemagickのauto-orientで回転させてしまうのがよいが、オリジナルのExif情報を上書きしてしまう副作用も存在する。(もちろんそんなもんどうでもよいと言うならベストな選択だと思う。)

最後にExif情報だけをまるごと抜き取るスクリプトを書いてみた。 一応画像サイズを削りつつ画像は表示されるが、画像サイズを削減する目的であればimagemagickでstripするのがベターだと思われる。

split exif and other form .jpg image