14
7

Exif Orientation のうんちく

Last updated at Posted at 2021-12-04

はじめに

画像を表示する際に意図せぬ回転して困る事で有名な Exif Orientation に関するうんちくです。(2021年12月5日作成記事)

Exif Orientation とは

カメラで撮影して保存する JPEG に関する主な規格として、DCF と Exif があります。
そのうち Exif の Orientation 情報は、カメラの向き等によって画像が本来意図するものと違う回転/鏡像で JPEG ファイルに保存される事を示すメタデータとしての値フィールドです。
図のように横長のカメラを縦にして撮影した場合、本来の映像を横に倒した画像が JPEG に保存される事になります。これを表示する際に元に戻すのが一般的な使われ方です。

image.png

画像ビューアによって Orientation が無視される事もあるので、世の中の画像アップローダは Orientation 補正して画像を保存する事が多いでしょう。
また多くの画像ライブラリは画像を読み込む際に自動では Orientation 補正をしないので、縦と横で違いが出るフィルタを実装する場合や、画像認識をする場合に、やはり回転補正する必要があります。

Exif Orientation 仕様

Exif Orientation の仕様はこちらに含まれます。Exif 2.3 (2012年12月改定版)は以下の URL でアクセスできます。

尚、現時点(2021年12月5日)での最新は 2.32 ですが、ドラフトだけ PDF 公開されていて、正式版は売り物です。(ちなみに ¥24,574)

Exif バイナリ形式 (おまけ)

Exif バイナリ形式での Orientation フィールドの入れ方はこちらです。

タグ名称 タグ番号 タイプ カウント
画像方向 Orientation 274(0x0112) SHORT(=2byte) 1

Exif のバイナリ形式は TIFF のサブセットで、その TIFF の画像フォーマットの仕様は Adobe のサイトにあります。

ですが、まずは以下のエントリを参照すると良いでしょう。噛み砕いた説明で分かりやすいです。

サンプル画像

サンプル画像は ImageMagick で以下のように作成しました。文字を入れると鏡写しにすぐ気付けるのでお勧めです。

% convert -size 100x75 -font .New-York-Italic -pointsize 64 \
     -fill white -stroke black -strokewidth 1 -gravity center \
     \( \( xc:red  -annotate 0 R \) \( xc:green1 -annotate 0 G \) +append \) \
     \( \( xc:blue -annotate 0 B \) \( xc:yellow -annotate 0 Y \) +append \) \
     -append -depth 1 RGBY.png

RGBY.png

Orientation つきの JPEG 画像の作り方は、以下のサイトをご参考までに。

% convert RGBY.png RGBY.jpg
% wget https://raw.githubusercontent.com/yoya/misc/master/bash/severalorientation.sh
% sh severalorientation.sh RGBY.jpg

これで全種類の 1〜8までの Orientation のついた JPEG 画像が生成できます。

Orientation の値

回転だけなら 4 種類あれば良いのですが、鏡像反転も対応するので 1〜8 の 8 種類の値を持ちます。
そのため、インカメラのように左右鏡像反転した方が直感的なケースも対応できます。
1 origin の番号体系にも注意が必要です。おそらく 0 は Exif 内に Orientation フィールド不在な場合と区別しにくいので、特別扱いしたものと思われます。(ただ、処理的には Orientation 無しと 0 と 1 は全部同じなので、区別する必要があったかというと微妙)

回転と鏡像反転 (前提知識)

実は画像の90度単位での回転は、鏡像反転処理だけで実現できます。
例えば、90度回転は上下反転と斜め反転の組み合わせで可能です。

元画像 上下反転 更に斜め反転
RGBY.png RGBY-4のコピー.png RGBY-8のコピー.png

つまり、同じ鏡像反転を2回実行すると元に戻りますが、違う種類の鏡像反転を適用すると、回転するのです。

上下+斜め => 90度回転 上下+左右 = 180度回転 左右+斜め = 270度回転
RGBY-8.png RGBY-3.png RGBY-6.png

そんな訳で、Orientation の全ては、上下/左右/斜めの鏡像反転の組み合わせで実現できますし、それら3つのフラグと相互変換もできます。

さて、具体的な画像の変換を紹介します。

変換表

JPEG ファイル内の実画像

Orientation 適用前の JPEG 実画像と、Orientation を適用した時の比較です。
Orientation の番号は回転の順には並んでいません。画像の反転をベースに考えているようです。

Orientaton JPEG 実画像(Orientation無視表示) Orientation適用表示 操作
1 RGBY.png RGBY.png 無し
2 RGBY-2.png RGBY.png 左右反転
3 RGBY-3.png RGBY.png 上下左右反転 = 180度回転
4 RGBY-4.png RGBY.png 上下反転
5 RGBY-5.png RGBY.png 斜め反転
6 RGBY-6.png RGBY.png 2 + 斜め反転 = 270回転
7 RGBY-7.png RGBY.png 3 + 斜め反転
8 RGBY-8.png RGBY.png 4 + 斜め反転 = 90度回転

早見表

2つに分けます。

実画像の配置

Orientation 操作すると RGBY.png になる、元画像を以下に並べます。

1 2 3 4
RGBY.png RGBY-2.png RGBY-3.png RGBY-4.png
5 6 7 8
RGBY-5.png RGBY-6.png RGBY-7.png RGBY-8.png

変換操作

実際に Orientation 適用の実装をする場合、こちらの表が便利だと思います。
元が RGBY.png で、Orientation 操作した後の画像テーブルです。

1 2 3 4
RGBY.png RGBY-2.png RGBY-3.png RGBY-4.png
5 6 7 8
RGBY-5.png RGBY-8.png RGBY-7.png RGBY-6.png

一つ目の早見表との違いは、6 と 8 が入れ替わっているだけです。

Orientation と鏡像反転フラグ

画像のテーブルを見ると分かりますが、Orientation 操作は左右反転、上下反転、斜め反転の3つの鏡像反転で表現できます。
Orientation から 1 を引いてビットで分解すると、その反転のフラグに近いデータが出てきます。

1 2 3 4
そのまま 左右反転 上下左右反転 上下反転
5 6 7 8
1の斜め反転 2の斜め反転 3の斜め反転 4の斜め反転

つまり、Orientation から 1 を引くと、ビットで処理できます。
3 と 4 の意味が逆なら、もっと素直なビット処理になるのが少し残念ですが、仕方なく頑張ると、以下のようなコードで相互変換可能です。

  • Orientation から反転ビットを取り出す処理
function fromOrientation(orientation) {
    const o = orientation - 1;
    const reverse = (o & 1)? true: false;
    const vertical = (o & 2)? true: false;
    const horizontal = reverse !== vertical;  // xor
    const diagonal = (o & 4)? true: false;
    return [horizontal, vertical, diagonal];
}
  • 反転ビットから Orientation 値に戻る処理
function toOrientation(horizontal, vertical, diagonal) {
    const reverse = horizontal !== vertical;  // xor
    const o = (reverse? 1: 0) + (vertical? 2: 0) + (diagonal? 4: 0);
    return o + 1;  // orientation;
}

Orientation 値と反転フラグの関係が実感できるデモを作りました。任意の画像をドロップして試せます。

14
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7