728x90

하나의 안드로이드 앱에서 다룰 수 있는 메모리의 한계 때문에 큰 사이즈 이미지는 OutofMemory exception이나 퍼포먼스 문제가 생길 수 있다. 작은 뷰의 크기에 맞지 않는 고해상도의 이미지를 불러오는 것은 괜한 리소스를 낭비하게 만든다.


=== BitMap.java ===

 import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.View;

public class BitMap extends View {
    public BitMap(Context context) {
        super(context);
    }

    protected void onDraw(Canvas canvas){
        canvas.drawColor(Color.CYAN);

        // Resource 폴더에 저장된 그림파일을 Bitmap 으로 만들어 리턴해준다
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.car1);
        // 이미지가 너무 크면 화면에서 잘려서 보임
        canvas.drawBitmap(bitmap,10,10,null); // 비트맵 이미지를 캔버스에 출력하는 함수
    }
}

 Bitmap myImage = BitmapFactory.decodeFile(“/sdcard/car1.jpg”);
 BitmapFactory.decodeFile() : 로컬에 존재하는 파일을 그대로 읽어올 때 쓴다.
 파일경로를 파라미터로 넘겨주면 FileInputStream 을 만들어서 decodeStream 을 한다.

 Canvas.drawBitmap() 은 비트맵 이미지를 캔버스에 출력하는 함수
 - 1번째 파라미터는 비트맵 이미지 객체, 2번째 파라미터는 원본 이미지의 영역좌표,
 - 3번째 파라미터는 이미지가 표시되는 화면상의 영역좌표, 4번째 파라미터는 Paint 객체
 - 2번째와 4번째파라미터는 생략 가능하다.

 === MainActivity.java ===

 import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);

        BitMap myView = new BitMap(this);
        setContentView(myView);
    }
}



https://ringsterz.wordpress.com/2014/11/27/imageview%EC%97%90-%EB%8C%80%EC%9A%A9%EB%9F%89-bitmap-%ED%9A%A8%EA%B3%BC%EC%A0%81%EC%9C%BC%EB%A1%9C-%EB%A1%9C%EB%94%A9%ED%95%98%EA%B8%B0/

에 자동으로 줄이는 함수가 있어서 이걸 이용해서 테스트 해봤다.


BitmapFactory.Options : BitmapFactory 가 사용하는 옵션클래스이다.
Options 객체를 생성하고 설정하고자 하는 옵션을 넣은후 BitmapFactory 의 함수 실행시 파라미터로 넘기면된다.
inSampleSize : decode 시 얼마나 줄일지 설정하는 옵션인데 1보다 작을때는 1이 된다.
1보다 큰값일 때 1/N 만큼 이미지를 줄여서 decoding 하게 된다. 보통 2의 배수로 설정한다.


import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.View;

public class BitMap extends View {
    public BitMap(Context context) {
        super(context);
    }

    protected void onDraw(Canvas canvas){
        canvas.drawColor(Color.CYAN);

        // Resource 폴더에 저장된 그림파일을 Bitmap 으로 만들어 리턴해준다
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.car2);
        // 이미지가 너무 크면 화면에서 잘려서 보임
        canvas.drawBitmap(bitmap,10,10,null);

        Bitmap resize = resize_decodeResource(getResources(), R.drawable.car2, 100, 100);
        canvas.drawBitmap(resize,10,900,null); // 비트맵 이미지를 캔버스에 출력하는 함수
    }

    public static Bitmap resize_decodeResource(Resources res, int resId,

                                                                               int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }
}


이미지 출력 결과


Bitmap resize = resize_decodeResource(getResources(), R.drawable.car2, 100, 100);

에서 width 와 height 지정된 크기로 이미지가 줄어드는게 아니라 원래 이미지 크기가 width 와 height 중에서 작은 것 기준으로 맞춰서 줄여진다.


그래서 높이 기준으로 줄여주는 걸로 수정을 했다.

protected void onDraw(Canvas canvas){
    canvas.drawColor(Color.CYAN);

    Bitmap resize = autoresize_decodeResource(getResources(), R.drawable.car2, 100);
    canvas.drawBitmap(resize,10,300,null); // 비트맵 이미지를 캔버스에 출력하는 함수
}

public static Bitmap autoresize_decodeResource(Resources res, int resId, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInAutoSize(options, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

public static int calculateInAutoSize(BitmapFactory.Options options, int reqHeight) {
    // 원본 이미지의 높이와 너비
    final int height = options.outHeight;
    final int width = options.outWidth;

    float ratio = width / height;
    int reqWidth = Math.round((float) ratio * width);

    int inSampleSize = 1;
    if (height > reqHeight) {
        final int halfHeight = height / 2;
        while ((halfHeight / inSampleSize) > reqHeight) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
} 


블로그 이미지

Link2Me

,