カメラで撮影した画像は、基本的には横向きで保存されているようです。そのため、縦構図の写真をそのまま処理すると、横向きで処理されてしまいます。この問題は、画像のメタデータ(Exif)に含まれる「向き」に関する情報を利用することで解決できます。
今回は、大きな画像を小さくリサイズし、一時ディレクトリに保存する流れについて述べます。利用シーンとしては、ネット上のストレージにアップロードする前の下ごしらえと言った感じです。
#基本的な流れ
処理の流れは以下のとおりです。画像を処理するマトリクスを用意し、マトリクスにリサイズ比と回転の値をセットします。リサイズと回転の処理は、それぞれメソッドにまとめることにします。メソッドの詳細は、下で述べます。
File file = new File(originalFilePath);
Matrix matrix = new Matrix();
matrix = getResizedMatrix(file, matrix);
matrix = getRotatedMatrix(file, matrix);
resizedFile = getTemporaryFile(file, matrix);
#処理メソッド
リサイズ
以下は、画像リサイズ用のメソッドです。ここでは、画像のサイズに関する情報以外は必要ないため、**BitmapFactory.Optionsのインスタンスを作成し、inJustDecodeBounds = true;**を設定します。このオプションを付けると、画像そのもののデータは読み込まないため、処理が早くなります。
/**
* リサイズするマトリクスを取得
* 縮小の場合のみ、縮小のマトリクスをセットして返す
*
* @param file 入力画像
* @param matrix 元のマトリクス
* @return matrix リサイズ後のマトリクス
*/
private Matrix getResizedMatrix(File file, Matrix matrix) {
// リサイズチェック用にメタデータ読み込み
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getPath(), options);
int height = options.outHeight;
int width = options.outWidth;
// リサイズ比の取得(画像の短辺がMAX_PIXELになる比を求めます)
float scale = Math.max((float) MAX_PIXEL / width, (float) MAX_PIXEL / height);
// 縮小のみのため、scaleは1.0未満の場合のみマトリクス設定
if (scale < 1.0) {
matrix.postScale(scale, scale);
}
return matrix;
}
画像の回転
画像に含まれるExif情報を利用して、画像を回転します。それぞれの詳しい説明は別のサイトにお任せして、とりあえずは、Androidに用意されている**ExifInterfaceを活用して、マトリクスをセットします。[getAttributeInt](http://developer.android.com/reference/android/media/ExifInterface.html#getAttributeInt(java.lang.String, int))(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);**の処理で、Exifの向き情報のタグ値を取得します。
/**
* 画像の回転後のマトリクスを取得
*
* @param file 入力画像
* @param matrix 元のマトリクス
* @return matrix 回転後のマトリクス
*/
private Matrix getRotatedMatrix(File file, Matrix matrix){
ExifInterface exifInterface = null;
try {
exifInterface = new ExifInterface(file.getPath());
} catch (IOException e) {
e.printStackTrace();
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:
// 180度回転
matrix.postRotate(180f);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
// 垂直方向にリフレクト
matrix.postScale(1f, -1f);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
// 反時計回り90度回転
matrix.postRotate(90f);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
// 時計回り90度回転し、垂直方向にリフレクト
matrix.postRotate(-90f);
matrix.postScale(1f, -1f);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
// 反時計回り90度回転し、垂直方向にリフレクト
matrix.postRotate(90f);
matrix.postScale(1f, -1f);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
// 反時計回りに270度回転(時計回りに90度回転)
matrix.postRotate(-90f);
break;
}
return matrix;
}
ファイルの読み込み・処理・保存
最後に、ファイルを読み込み、リサイズ処理を行い、ファイルを保存します。重要な部分は、**Bitmap.[createBitmap](http://developer.android.com/reference/android/graphics/Bitmap.html#createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean))(originalPicture, 0, 0, width, height, matrix, true);**の部分です。このメソッドは、デコード済みのBitmap(originalPicture)を元に、指定した範囲(0, 0, width, height = 画像全体の範囲)をクロップし、matrixで変形することができます。trueをつけることで、ジャギー(ギザギザ)の目立たない滑らかな変形が可能です。
/**
* リサイズ・回転後の画像を取得
* 一時ファイルを作成する
*
* @param file オリジナル画像
* @param matrix 回転・縮小を設定したマトリクス
* @return file 一時保存先のファイル
*/
private File getTemporaryFile(File file, Matrix matrix) {
// 元画像の取得
Bitmap originalPicture = BitmapFactory.decodeFile(file.getPath());
int height = picture.getHeight();
int width = picture.getWidth();
// マトリクスをつけることで縮小、向きを反映した画像を生成
Bitmap resizedPicture = Bitmap.createBitmap(originalPicture, 0, 0, width, height, matrix, true);
// 一時ファイルの保存
try {
File destination = new File([画像の一時保存先パスファイル名] + ".jpg");
FileOutputStream outputStream = new FileOutputStream(destination);
resizedPicture.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.flush();
outputStream.close();
// ファイルのインスタンスをリサイズ後のものに変更
file = destination;
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
参考資料
JPEGのExifタグ情報のOrientaionの定義の早見表・DQNEO起業日記
Android で Bitmap を安全に操作する(2) ~縮小・ EXIF 情報による回転~ | UB Lab.
Y.A.M の 雑記帳: Exif
Bitmap | Android Developers
BitmapFactory | Android Developers
accessed 2015-07-02