62

を使用してSDカードからビットマップをデコードしBitmapFactory.decodeFileます。ビットマップがアプリケーションが必要とするものやヒープが許可するものよりも大きい場合があるためBitmapFactory.Options.inSampleSize、サブサンプリングされた(小さい)ビットマップを要求するために使用します。

問題は、プラットフォームがinSampleSizeの正確な値を強制しないことであり、ビットマップが小さすぎるか、使用可能なメモリに対して大きすぎる場合があります。

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSizeから:

注:デコーダーはこの要求を実行しようとしますが、結果のビットマップは、要求されたものと正確に異なる次元を持つ場合があります。また、2の累乗は、多くの場合、デコーダーが尊重する方が高速で簡単です。

SDカードからビットマップをデコードして、デコードに必要なメモリをできるだけ少なくしながら、必要な正確なサイズのビットマップを取得するにはどうすればよいですか?

編集:

現在のソースコード:

BitmapFactory.Options bounds = new BitmapFactory.Options();
this.bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, bounds);
if (bounds.outWidth == -1) { // TODO: Error }
int width = bounds.outWidth;
int height = bounds.outHeight;
boolean withinBounds = width <= maxWidth && height <= maxHeight;
if (!withinBounds) {
    int newWidth = calculateNewWidth(int width, int height);
    float sampleSizeF = (float) width / (float) newWidth;
    int sampleSize = Math.round(sampleSizeF);
    BitmapFactory.Options resample = new BitmapFactory.Options();
    resample.inSampleSize = sampleSize;
    bitmap = BitmapFactory.decodeFile(filePath, resample);
}
4

11 に答える 11

47

あなたは正しい方向に進んでいますが、一度に2つのことを行おうとしています。ファイルを読み込んで、適切なサイズに拡大縮小します。

最初のステップは、BitmapFactory.Options.inSampleSizeを使用して、必要なサイズよりもわずかに大きいビットマップにファイルを読み取ることです。これにより、小さいサムネイルまたは画面解像度の画像だけが必要な場合に、大きなビットマップを読み取るために過剰なメモリを消費しないようにします。

2番目のステップは、Bitmap.createScaledBitmap()を呼び出して、必要な正確な解像度で新しいビットマップを作成することです。

一時ビットビットの後でクリーンアップして、メモリを再利用してください。(変数をスコープ外にしてGCに処理させるか、大量の画像をロードしていてメモリが不足している場合は、変数に対して.recycle()を呼び出します。)

于 2010-07-29T16:57:02.577 に答える
17

を使用することをお勧めしますinJustDecodeBounds。に設定しTRUE、ファイルをそのままロードします。

画像はメモリにロードされません。ただし、BitmapFactory.Optionsのoutheightおよびoutwidthプロパティには、指定された画像の実際のサイズパラメータが含まれますそれをサブサンプリングしたい量を計算します。つまり、1/2または1/4または1/8などで、inSampleSizeに応じて2/4/8などを割り当てます

次に、に設定inJustDecodeBoundsFALSEて呼び出しBitmapFactory.decodeFile()、上記で計算した正確なサイズの画像を読み込みます。

于 2010-04-17T16:56:31.660 に答える
7

まず、ビットマップがメモリ効率を高めるように、画像を最も近いサンプリング値にサンプリングする必要があります。これについては、完全に説明しました。完了したら、画面に合わせて拡大できます。

// This function taking care of sampling
backImage =decodeSampledBitmapFromResource(getResources(),R.drawable.back, width, height);

// This will scale it to your screen width and height. you need to pass screen width and height.
backImage = Bitmap.createScaledBitmap(backImage, width, height, false); 
于 2012-06-03T08:22:34.700 に答える
1

APIはすでにサンプルサイズが尊重される場合とされない場合があると述べているため、だから私はあなたが使用している間運が悪かったと思いBitmapFactoryます。

しかし、その方法は、独自のビットマップリーダーを使用することです。しかし、かなりよくテストされ、標準化されているBitmapFactoryを使用することをお勧めします。

私は少し余分なメモリ消費についてあまり心配しないようにしますが、なぜそれが値を尊重しないのかを調べてみてください。悲しいことに、私はそれについて知りません:(

于 2010-04-18T14:20:40.490 に答える
1
ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filesPath), THUMBSIZE, THUMBSIZE))

要件に応じてTHUMBSIZEを直接設定できますが、低レベルの実装の詳細、出力画質、およびそのパフォーマンスについてはよくわかりませんが、サムネイルを表示する必要がある場合は通常、THUMBSIZEを使用します。

于 2014-01-25T06:49:04.353 に答える
1

リソースから正確なサイズの画像を探している人のために。

正確な幅の場合はreqHight=0を渡し、正確な高さの場合はreqWidth=0を渡します

public static Bitmap decodeBitmapResource(Context context, int resId, int reqWidth, int reqHeight)
{
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(context.getResources(), resId, options);
    float scale = 1;
    if (reqWidth != 0 && reqHeight == 0)
    {
        options.inSampleSize = (int) Math.ceil(options.outWidth / (float) reqWidth);
        scale = (float) options.outWidth / (float) reqWidth;
    }
    else if (reqHeight != 0 && reqWidth == 0)
    {
        options.inSampleSize = (int) Math.ceil(options.outHeight / (float) reqHeight);
        scale = (float) options.outHeight / (float) reqHeight;
    }
    else if (reqHeight != 0 && reqWidth != 0)
    {
        float x = (float) options.outWidth / (float) reqWidth;
        float y = (float) options.outHeight / (float) reqHeight;
        scale = x > y ? x : y;
    }
    reqWidth = (int) ((float) options.outWidth / scale);
    reqHeight = (int) ((float) options.outHeight / scale);
    options.inJustDecodeBounds = false;
    Bitmap tmp = BitmapFactory.decodeResource(context.getResources(), resId, options);
    Bitmap out = Bitmap.createScaledBitmap(tmp, reqWidth, reqHeight, false);
    tmp.recycle();
    tmp = null;
    return out;
}
于 2016-08-02T07:32:12.543 に答える
0

inSampleSizeを使用しているので、メモリ不足の問題に直面することはもうありません。したがって、inSampleSizeは私にとって非常に安定しています。問題を再確認することをお勧めします。サイズはあなたが要求したものと正確に同じではないかもしれません。しかし、とにかくそれを減らすべきであり、「メモリ不足」はもうないはずです。また、ここにコードスニペットを投稿することをお勧めします。何か問題がある可能性があります。

于 2010-04-21T15:09:14.940 に答える
0

the100rabhが言ったように、BitmapFactoryを使用する場合、実際には多くの選択肢がありません。ただし、ビットマップのデコードは非常に単純であり、使用するスケーリングアルゴリズムによっては、通常、元のビットマップの大部分をメモリに読み込むことなく、オンザフライでスケーリングするのはかなり簡単です(通常は、元のビットマップの1〜2行に必要なメモリの2倍だけが必要です)。

于 2010-04-22T09:41:32.607 に答える
0

inScaledフラグが設定されている場合(デフォルトではTRUE)、inDensityとinTargetDensityが0でない場合、ビットマップは、キャンバスに描画されるたびにスケーリングするグラフィックシステムに依存するのではなく、ロード時にinTargetDensityに一致するようにスケーリングされます。したがって、inScaledをfalseに設定するだけで十分です。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
于 2016-12-25T16:40:11.950 に答える
0

デコードされた画像ファイルをビットマップサイズの70%に再スケーリングすることで、ほぼ「適切なサイズ」を得ることができました。

Bitmap myBitmap = BitmapFactory.decodeFile(path);
if(myBitmap != null)
{
  //reduce to 70% size; bitmaps produce larger than actual image size
  Bitmap rescaledMyBitmap = Bitmap.createScaledBitmap(
                                                  myBitmap, 
                                                  myBitmap.getWidth()/10*7, 
                                                  myBitmap.getHeight()/10*7, 
                                                  false);

  image.setImageBitmap(rescaledMyBitmap);
}                

これがどういうわけかあなたを助けることを願っています!平和!

于 2017-04-04T03:14:26.490 に答える
0

ドキュメントは非常に自明です。最初に私はそこから小さなクリップを作ることを考えましたが、完全に読む方が理解に優れており、メモリで失敗しないようにするために必要であることがわかりました。最後に、それはかなり小さいです。

于 2019-12-05T19:29:26.970 に答える