13

カメラから特定の (メモリに適した) サイズのビットマップを取得するにはどうすればよいですか?

私はカメラの意図を始めています:

Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
cameraIntent.putExtra("return-data", true);

photoUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "mytmpimg.jpg"));
cameraIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoUri);        

startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);

ここで結果を処理します。

//  Bitmap photo = (Bitmap) intent.getExtras().get("data");

Bitmap photo = getBitmap(photoUri);

ここで、コメント行を使用すると、ビットマップを直接取得すると、常に 160 x 120 のビットマップが取得されますが、これは小さすぎます。私が見つけたいくつかの標準的なもの (メソッド getBitmap) を使用して URI からロードすると、2560 x 1920 ビットマップ (!) がロードされ、ほぼ 20 MB のメモリが消費されます。

たとえば 480 x 800 (カメラのプレビューで表示されるのと同じサイズ) を読み込むにはどうすればよいですか?

2560 x 1920 をメモリにロードして縮小する必要はありません。

4

1 に答える 1

2

これは、古い Android バージョンから削除されたクロップ ライブラリの getBitmap() というメソッドに基づいて、私が思いついたものです。私はいくつかの変更を行いました:

private Bitmap getBitmap(Uri uri, int width, int height) {
    InputStream in = null;
    try {
        int IMAGE_MAX_SIZE = Math.max(width, height);
        in = getContentResolver().openInputStream(uri);

        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        BitmapFactory.decodeStream(in, null, o);
        in.close();

        int scale = 1;
        if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
            scale = (int)Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
        }

        //adjust sample size such that the image is bigger than the result
        scale -= 1;

        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        in = getContentResolver().openInputStream(uri);
        Bitmap b = BitmapFactory.decodeStream(in, null, o2);
        in.close();

        //scale bitmap to desired size
        Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, width, height, false);

        //free memory
        b.recycle();

        return scaledBitmap;

    } catch (FileNotFoundException e) {
    } catch (IOException e) {
    }
    return null;
}

これが行うことは、BitmapFactory.Options() + いくつかのサンプル サイズを使用してビットマップをロードすることです。この方法では、元の画像はメモリにロードされません。問題は、サンプルサイズが段階的に機能することです。コピーした数学を使用して画像の「最小」サンプルサイズを取得し、最小値を生成するサンプルサイズを取得するために1を減算します。必要なサイズよりも大きいビットマップ。

そして、正確に要求されたサイズのビットマップを取得するために、 で通常のスケーリングを行いBitmap.createScaledBitmap(b, width, height, false);ます。そしてすぐに、より大きなビットマップをリサイクルします。たとえば、私の場合、480 x 800 のビットマップを取得するために、より大きなビットマップは 1280 x 960 であり、4.6 MB のメモリを占有するため、これは重要です。

よりメモリに優しい方法は、調整しないことscaleです。したがって、より小さいビットマップが必要なサイズに合わせて拡大されます。しかし、これは画像の品質を低下させます。

于 2012-07-29T22:03:54.103 に答える