AndroidStudio・画像のリサイズ

画像でメモリリークを防いでみる

画像のサイズを変更する

 

アプリ起動時にたくさん画像を使ったら[ OutOfMemory ]が発生することがありました。

画像をリソースするだけの処理でコード上でもエラーが出ないため、まだ未熟な私ではその原因が画像が大きすぎる、と言うことにしばらく気づけませんでした。

 

普通にサイズを変更する

 

最初の頃に使いそうなサイズ変更方法です。

// 画像の見た目を縮小する
imageView.setScaleX(0.5f);
imageView.setScaleY(0.5f);

表示している画像のサイズを0.5倍にする処理です。

 

見た目は小さくなるのですが、これだと根本的な解決になりません。

原因は、見た目を小さくしても画像の容量は変化しないからです。

 

そこで容量を小さくするクラスを作成して見ました。

 

画像をリサイズするクラス

public class BitmapSize {

    /*
    * 元画像情報を受け取り、必要な場合表示サイズに合わせて画像を縮小して生成するためのメソッド
    *
    * @param 元画像リソース、 元画像Id、 元画像の幅、 元画像の高さ
    * @return 元画像リソース、元画像Id、 生成した画像
    */
    public static Bitmap createBitmap ( Resources res, int id, int width, int height ) {
        //受け取った画像情報を読み込む
        BitmapFactory.Options option = new BitmapFactory.Options();
        option.inJustDecodeBounds = true;   //trueの場合、画像を読み込まずサイズの情報のみを取得
        BitmapFactory.decodeResource(res, id, option);

        //取得したサイズと画像サイズから倍率を測定
        float scaleWidth = (float) width / option.outWidth;
        float scaleHeight = (float) height / option.outHeight;

        int sampleSize;  //取得画像のサイズと目的のサイズを比較して得る倍率

        //目的のサイズと実際のサイズに差があれば画像を縮小する
        if ( scaleWidth >= 1.0f && scaleHeight >= 1.0f ) sampleSize = 1;
        else if ( scaleWidth >= 0.5f || scaleHeight >= 0.5f ) sampleSize = 2;   // 1/2に縮小
        else if ( scaleWidth >= 0.33f || scaleHeight >= 0.33f ) sampleSize = 3; // 1/3に縮小
        else if ( scaleWidth >= 0.25f || scaleHeight >= 0.25f ) sampleSize = 4; // 1/4に縮小
        else sampleSize = 5;    // 1/5に縮小

        option.inJustDecodeBounds = false;  //falseの場合、画像とサイズを読み込む
        option.inSampleSize = sampleSize;   //設定する値を代入

        return BitmapFactory.decodeResource( res, id, option );
    }

    /*
    * 縮小した画像をリサイズするためのメソッド
    *
    * @param 元画像リソース、 元画像Id、 目的とする画像の幅、 目的とする画像の高さ
    * @return 変換後の画像
    */
    public static Bitmap resize ( Bitmap bitmap, int newWidth, int newHeight ) {

        //Bitmapがnullだった場合、nullを返す
        if ( bitmap == null ) {
            return null;
        }

        //元画像のサイズ
        int oldWidth = bitmap.getWidth();
        int oldHeight = bitmap.getHeight();

        //縮小した画像サイズが同じ場合はそのまま使用する
        if ( oldWidth == newWidth && oldHeight == newHeight ) {
            return bitmap;
        }

        //縮小した画像サイズが異る場合はリサイズする
        float scaleWidth = ((float) newWidth ) / oldWidth;
        float scaleHeight = ((float) newHeight ) / oldHeight;
        float scaleFactor = Math.min( scaleWidth, scaleHeight );    //width, heightのどちらか小さい方を取得

        Matrix scale = new Matrix();
        scale.postScale( scaleFactor, scaleFactor );    //縮小する

        Bitmap resizeBitmap = Bitmap.createBitmap( bitmap, 0, 0, oldWidth, oldHeight, scale, false );
        bitmap.recycle();
        return resizeBitmap;
    }
}

 

メソッドは2つ作りました。

// 元の画像を目的のサイズと比較して容量を小さくする
public static Bitmap createBitmap (Resources res, int id, int width, int height) {}

// createBitmapで小さくした画像を改めて縮小する
public static Bitmap resize(Bitmap bitmap, int newWidth, int newHeight ) {}

 

あとは使用したい場所でメソッドを呼び出します。

// BitmapクラスかDrawableクラスにリサイズしたものを格納
public Bitmap bitmap;
public BitmapDrawable drawable;

/*
ID            : 縮小したい画像のID
width, height : 目的のサイズ(加工したい画像のサイズ)
*/
bitmap = BitmapSize.createBitmap([Resources], [ID], [width], [height])

// drawableにする場合は BitmapDrawableをインスタンス
// 第二引数に上で縮小したBitmapを使用
bitmapDraw[i] = new BitmapDrawable([Resources], BitmapSize.resize([Bitmap],
                    [width], [height]);

 

これでメモリリークが起きにくくなります。

画面サイズを大幅に超えた画像や、容量の重いものをそのまま使っていくとすぐに怒られちゃうんで注意してください。

 

あ、あと使い終わった画像は処分してくださいね。

.recycle()    // bitmapを処理
bitmap = null // 参照も外した方がいいかも

 

以上、画像のサイズについてでした。

Additional Images




Comments

Add your comment

user-symbol

Stay in touch

Get Practical Tips For Business and Developers.

Learn about PieceX Community Needs for Source Code Projects.

Be the First to Know PieceX Newest Free Community Code Projects.