Androidからサーバに画像を保存する際に、Android側で縮小したいなと思った時の備忘録。
特にハマったのはローテート情報...
縮小するだけだとEXIFがないので、ImageViewで表示すると回転しない。。
流れとしては、以下の感じ
全量はこちら
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.support.annotation.NonNull; import android.support.media.ExifInterface; import android.util.Log; import android.util.Size; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.UUID; import static android.support.media.ExifInterface.ORIENTATION_UNDEFINED; import static android.support.media.ExifInterface.TAG_ORIENTATION; public class BitmapHandler { private static final String TAG = BitmapHandler.class.getSimpleName(); private static final double MAX_HEIGHT = 1920.0; private static final double MAX_WIDTH = 1080.0; private Context context; public BitmapHandler(Context context) { this.context = context; } /** * ファイルサイズがHDより大きい場合に、リサイズしてたファイルを返却 * * @param uri リサイズしたいファイルのURI * @return リサイズ後のFile * @throws IOException IOException */ public File getResizedFile(Uri uri) throws IOException { // 元画像のローテーション情報を取得 int orientation = getOrientation(uri); // リサイズ処理。リサイズ後のBitmapを取得 Bitmap resized = resizedBitmap(uri); // ファイルの書き出し処理 // バッファ書き出し後にEXIFを追記 return writeFile(resized); } /** * 画像のORIENTATIONを取得 * * @param uri 対象画像のURI * @return TAG_ORIENTATIONの値 */ private int getOrientation(@NonNull Uri uri) { try (InputStream src = context.getContentResolver().openInputStream(uri)) { if (src == null) return ORIENTATION_UNDEFINED; // 画像の向きを取得 ExifInterface exifInterface = new ExifInterface(src); int orientation = exifInterface.getAttributeInt(TAG_ORIENTATION, ORIENTATION_UNDEFINED); return orientation; } catch (IOException e) { Log.w(TAG, e.getLocalizedMessage(), e); return ORIENTATION_UNDEFINED; } } /** * リサイズ後のBitmapを返却 * * @param uri リサイズ対象画像のURI * @return リサイズ後のBitmap * @throws IOException IOException */ private Bitmap resizedBitmap(@NonNull Uri uri) throws IOException { // 任意の縮尺でビットマップを生成する Size scale = getScale(uri); try (InputStream src = context.getContentResolver().openInputStream(uri)) { Bitmap bitmap = BitmapFactory.decodeStream(src); return Bitmap.createScaledBitmap(bitmap, scale.getWidth(), scale.getHeight(), true); } } /** * リサイズ後のスケールを計算 * * @param uri リサイズ対象画像のURI * @return リサイズ後のサイズ * @throws IOException IOException */ private Size getScale(Uri uri) throws IOException { try (InputStream src = context.getContentResolver().openInputStream(uri)) { // オプションオブジェクトを生成 BitmapFactory.Options options = new BitmapFactory.Options(); // 画像をメモリに展開せずにサイズ情報のみ取得する options.inJustDecodeBounds = true; BitmapFactory.decodeStream(src, null, options); // スケールの計算 double pixels = options.outWidth * options.outHeight; double scale = 1.0; // 最大サイズよりもピクセル数が多い場合のみ縮小 if (pixels > MAX_HEIGHT * MAX_WIDTH) { if (options.outWidth < options.outHeight) { // 縦長の場合 scale = MAX_HEIGHT / options.outHeight; } else { // 横長の場合 scale = MAX_HEIGHT / options.outWidth; } } int newWidth = (int) Math.ceil(options.outWidth * scale); int newHeight = (int) Math.ceil(options.outHeight * scale); return new Size(newWidth, newHeight); } catch (IOException e) { Log.w(TAG, e.getLocalizedMessage(), e); throw e; } } /** * Bitmapのファイル書き出し * * @param bitmap 書き出すBitmap * @param orientation ローテーション情報 * @return 書き出し後のファイル * @throws IOException IOException */ private File writeFile(Bitmap bitmap, int orientation) throws IOException { String fileName = UUID.randomUUID().toString(); File file = new File(context.getCacheDir(), fileName); file.createNewFile(); try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { bitmap.compress(Bitmap.CompressFormat.JPEG, 100 /*ignored for PNG*/, bos); try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(bos.toByteArray()); fos.flush(); } ExifInterface exif = new ExifInterface(file.getPath()); exif.setAttribute(TAG_ORIENTATION, String.valueOf(orientation)); exif.saveAttributes(); } return file; } }
以上!!