Android で Bitmap を安全に操作する(2) ~縮小・ EXIF 情報による回転~

前回は、BitmapFactory.decodeStream(InputStream, Rect, BitmapFactory.Options) を利用し、メモリーの使用量を抑えて Bitmap を読み込んだ。画像を必要最小限の大きさで読み込むことで、メモリー使用量を抑えているわけだが、縮小サイズは2のべき乗に丸められてしまうため細かく指定できない。単純に ImageView に貼り付けるだけなら問題ないが、サムネイルを作成する場合など、幅と高さを正確に指定したい場合に困る。
幅と高さを正確に指定して画像を生成したい場合は、BitmapFactory.decodeStream(InputStream, Rect, BitmapFactory.Options) で読み込んだ画像を、Matrix を使って縮小すればよいだろう。また、デジカメで撮った JPEG 画像は、EXIF の Orientation 属性に画像の回転情報が含まれていることがある。画像の回転も Matrix で行えるので、同時に処理を行えばよさそうだ。

EXIF の Orientation 属性を読み込んで Matrix を生成

EXIF は、写真用のメタデータを含む画像ファイルフォーマットで、絞りやシャッター速度、GPS 情報などを含む。Wikipedia の説明が簡潔でわかりやすい。写真をプリントするのであれば、ホワイトバランスなどが重要になってくるかもしれないが、表示がメインの Android アプリの画像処理で必要になってくるのは Orientation 属性だ。規格書はExif Printのサイトにあるのだが、読んでもさっぱり分からない。Web でいろいろと調べてみると、JPEGのExifタグ情報のOrientaionの定義の早見表 – DQNEO起業日記という記事が見つかった。わかりやすい!と思って感動・・・と、Android の場合は ExifInterface の定数でだいたいわかるようになっていて少し拍子抜け。Java のコードにすると、以下のようになるだろうか。

ExifInterface exifInterface = new ExifInterface(file.getAbsolutePath());
Matrix matrix = new Matrix();
if(null == exifInterface) {
	return matrix;
}
int orientation = exifInterface.getAttributeInt(
		ExifInterface.TAG_ORIENTATION,
		ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_UNDEFINED:
	break;
case ExifInterface.ORIENTATION_NORMAL:
	break;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
	matrix.postScale(-1f, 1f);
	break;
case ExifInterface.ORIENTATION_ROTATE_180:
	matrix.postRotate(180f);
	break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
	matrix.postScale(1f, -1f);
	break;
case ExifInterface.ORIENTATION_ROTATE_90:
	matrix.postRotate(90f);
	break;
case ExifInterface.ORIENTATION_TRANSVERSE:
	matrix.postRotate(-90f);
	matrix.postScale(1f, -1f);
	break;
case ExifInterface.ORIENTATION_TRANSPOSE:
	matrix.postRotate(90f);
	matrix.postScale(1f, -1f);
	break;
case ExifInterface.ORIENTATION_ROTATE_270:
	matrix.postRotate(-90f);
	break;
}
return matrix;

file は対象となる画像ファイルを引数で受け取っている。これをメソッドにして用意し、Matrix を戻すようにしておこう(実際には若干違ったコードになりましたが・・・)。

幅と高さを指定して、縮小した画像を生成

画像の縮小は簡単で、Matrix.postScale(float sx, float sy) メソッドを使うだけだ。EXIF の Orientation 情報と同時に処理するために、引数に BitmapFactory.decodeStream(InputStream, Rect, BitmapFactory.Options) で読み込んだ Bitmap、希望する高さ(desireHeight)と幅(desireWidth)、EXIF の Orientation 属性を読み込んで生成した Matrix を持ち、生成した Bitmap を戻すメソッドを用意してみた。内部のコードは、以下のような感じ。引数の Bitmap を再度利用することがないならば、内部で bitmap.recycle() を呼び出すようにしたほうがよさそうだ。

final int width = bitmap.getWidth();
final int height = bitmap.getHeight();

float scaleX = desireWidth / width;
float scaleY = desireHeight / height;
float scale = Math.min(scaleX, scaleY);

matrix.postScale(scale, scale);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

画像を指定した幅・高さで EXIF 情報を考慮して読み込むには

以下の順序で処理を行って、指定した幅・高さでサムネイルを生成することができた。

  1. BitmapFactory.decodeStream(InputStream, Rect, BitmapFactory.Options) で読み込む(前回参照)
  2. EXIF の Orientation 属性を読み込んで Matrix を生成
  3. 幅と高さを指定して、縮小した画像を生成

1 thoughts on “Android で Bitmap を安全に操作する(2) ~縮小・ EXIF 情報による回転~

  1. ピンバック: Android で Bitmap を安全に操作する(3) ~画像の編集・コピー~ | UB Lab.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.