[解決済み] アンドロイドでビットマップのサイズを変更する最もメモリ効率の良い方法とは?
質問
画像を多用するソーシャルアプリを構築しており、画像がサーバーからデバイスに送信されます。デバイスの画面解像度が小さい場合、デバイス上でビットマップのサイズを変更し、意図した表示サイズに合わせる必要があります。
問題は createScaledBitmap は、大量のサムネイル画像のサイズを変更した後に、多くのメモリ不足のエラーに遭遇する原因となります。
Android でビットマップのサイズを変更する最も効率的なメモリ方法は何ですか?
どのように解決するのですか?
この回答は、以下を要約したものです。 大きなビットマップを効率的に読み込む で、inSampleSizeを使用して縮小されたビットマップを読み込む方法を説明しています。 のバージョンです。
特に プリスケーリングビットマップ では、さまざまな の詳細、それらをどのように組み合わせるか、そしてどれが最もメモリ効率が良いかについて説明します。
Android でビットマップのサイズを変更するには、異なるメモリ特性を持つ 3 つの主要な方法があります。
このAPIは、既存のビットマップを取り込み、選択された正確な寸法で新しいビットマップを作成します。
プラス面では、探している画像サイズを正確に得ることができます(それがどのように見えるかは関係なく)。しかし、欠点もあります。 は、この API が 既存の ビットマップが必要です。 . つまり、画像を読み込み、デコードし、ビットマップを作成してから、新しい小さいバージョンを作成する必要があります。これは、正確な寸法を得るという点では理想的ですが、メモリのオーバーヘッドが増えるという点では恐ろしいことです。そのため、メモリを重視する傾向のあるほとんどのアプリ開発者にとって、これは一種の破格の問題です。
BitmapFactory.Options
には、以下のようなプロパティがあります。
inSampleSize
これは、一時的なビットマップへのデコードの必要性を避けるために、デコード中に画像のサイズを変更するものです。ここで使用されるこの整数値は、1/xに縮小されたサイズで画像を読み込みます。例えば
inSampleSize
を 2 に設定すると半分の大きさの画像が読み込まれ、 4 に設定すると 1/4 の大きさの画像が読み込まれる。基本的に画像サイズは常にソースサイズより2のべき乗小さいサイズになります。
メモリの観点からは
inSampleSize
は実に高速な処理です。事実上、画像の X 番目のピクセルを結果のビットマップにデコードするだけです。には主に2つの問題があります。
inSampleSize
とはいえ
-
正確な解像度が得られない . ビットマップのサイズを 2 のべき乗で減少させるだけです。
-
最高品質のリサイズを生成しない . ほとんどのリサイズ フィルタは、ピクセルのブロックを読み込んで、問題のリサイズ ピクセルを生成するために重み付けを行うことで、見栄えのよい画像を生成します。
inSampleSize
は、数ピクセルごとに読み取るだけで、これらすべてを回避します。その結果、非常にパフォーマンスが高く、メモリも少なくて済みますが、品質は低下します。
もし、画像をpow2サイズだけ縮小することだけを扱い、フィルタリングが問題でないなら、メモリ効率の良い(あるいは性能の良い)方法として
inSampleSize
.
inScaled, inDensity, inTargetDensity フラグ
もし、画像を2の累乗に等しくない寸法に拡大縮小する必要がある場合、そのためには
inScaled
,
inDensity
と
inTargetDensity
のフラグが
BitmapOptions
. このとき
inScaled
フラグが設定されている場合、システムはビットマップに適用するスケーリング値として
inTargetDensity
を
inDensity
の値で指定します。
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
この方法を使うと、画像のサイズが変更され、さらに「リサイズフィルタ」が適用されます。つまり、リサイズステップの間にいくつかの追加の計算が考慮されるため、最終結果はより良く見えるようになります。しかし、注意してください。 その余分なフィルタリングのステップは、余分な処理時間がかかります 大きな画像の場合、リサイズに時間がかかったり、フィルタ自体に余計なメモリが割り当てられたりして、あっという間に増えてしまいます。
一般に、希望するサイズよりかなり大きな画像にこの手法を適用するのは、余分なフィルタリングのオーバーヘッドのため、良いアイデアとは言えません。
魔法の組み合わせ
メモリとパフォーマンスの観点から、これらのオプションを組み合わせると、最良の結果を得ることができます。(設定することで
inSampleSize
,
inScaled
,
inDensity
と
inTargetDensity
フラグ)
inSampleSize
はまず画像に適用され、目標サイズより 2 のべき乗大きいサイズになります。次に
inDensity
を追加します。
inTargetDensity
は、結果を正確な寸法に拡大縮小するために使用され、画像をきれいにするためにフィルタ操作を適用します。
この2つを組み合わせることで、より高速な操作が可能になります。
inSampleSize
ステップによって、結果として得られる密度ベースのステップがリサイズフィルタを適用する必要のあるピクセル数が減少するためです。
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
画像を特定の寸法に合わせる必要がある場合。 と といったフィルタリングが必要な場合、このテクニックは正しいサイズを得るための最良の橋渡しとなりますが、高速で低メモリ フットプリントの操作で実行されます。
画像の寸法を取得する
画像全体をデコードすることなく画像サイズを取得する
ビットマップのサイズを変更するには、入力される寸法を知る必要があります。そのためには
inJustDecodeBounds
フラグを使用すると、実際にピクセルデータをデコードすることなく、画像の寸法を取得することができます。
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
このフラグを使用して、まずサイズをデコードし、次にターゲットとする解像度にスケーリングするための適切な値を計算することができます。
関連
-
[解決済み] AndroidでPythonを実行する方法はありますか?
-
[解決済み] Androidで'Context'を取得する静的な方法?
-
[解決済み] Androidでアプリケーションのメモリ使用量を確認するにはどうすればよいですか?
-
[解決済み】Androidでビットマップのサイズを変更する方法は?
-
[解決済み】pandasでdataframeをループする最も効率的な方法は何ですか?
-
[解決済み] Androidの連絡先リストを呼び出すには?
-
[解決済み] OnScreen KeyboardのDoneキー押下を検出するAndroid
-
[解決済み] Android Studioで複数のデバイスでアプリを自動実行する
-
[解決済み] RelativeLayoutレイアウトパラメータをxmlではなくコードで設定するには?
-
[解決済み] Android Studioのユニットテスト: データ(入力)ファイルの読み込み
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] SDカードからファイルを削除する方法を教えてください。
-
[解決済み] CardView layout_width="match_parent "が親のRecyclerViewの幅と一致しない。
-
[解決済み] Androidでビットマップから円形領域を切り取る方法
-
[解決済み] エラーです。ステータス{statusCode=DEVELOPER_ERROR, resolution=null}.
-
[解決済み] AndroidのimageviewがmaxWidthを無視する?
-
[解決済み] エラー Android Studioで名前'default'を持つ構成が見つかりません。
-
[解決済み] Fragment ActionBarCompatの内部からgetSupportActionBarを取得する。
-
[解決済み] 複数のローダーを持つLoaderManager: 正しいカーソルローダーを取得する方法
-
[解決済み] Android: 複数の選択オプションを持つポップアップを作成する
-
[解決済み] Android: ActionBarのホームアイコンをアプリのアイコンでないものに変更するには?