[컴][안드로이드] 이미지 축소하기 - BitmapFacotry.decode*()

이미지 크기 줄이기, 이미지 리사이징, image resizing, 이미지 확대, 축소

bitmap loading 을 할 때 너무 큰 사이즈의 이미지를 load 하는 것은 메모리를 너무 잡아먹게 된다. 이것과 관련된 android api 문서가 있다.
문서에 있는 소스는 아래에 있다. 이 포스트에서는 간략한 설명을 하려 한다. 자세한 설명은 원문을 참조하면 될 듯 하다.

Scaled Down

options.inJustDecodeBounds

이 옵션을 true 로 하고 나서 decode*() 를 호출하면, bitmap 의 bound 만 알려준다고 한다.

options.inSampleSize

inSampleSize 를 2로 하면 1/2 배가 되고, 4 를 하면 1/4 가 된다. 예를 들면 10x10 이라면 inSampleSize 가 2 인 경우에 5x5 가 되는 것이다.
이 inSampleSize 는 2 의 배수로 하면 decode*() 에서 연산이 빨라진다고 한다. 하지만 caching 등을 할 때는 여전히 caching 공간을 절약하는 알맞은 inSampleSize 값을 계산해서 넣는 것이 낫다고 한다.

BitmapFactory.decode* 함수

결국 원하는 size 로 변경 해 주는 핵심 함수는
BitmapFactory.decodeResource()
가 된다. 이 BitmapFactory.decode* 의 함수는
  • ByteArray
  • Resource
  • ResourceStream
  • File
  • FileDescriptor
  • Stream
등이 가능하다. 문서를 보고 자신에게 알맞은 것을 선택하면 된다.



public static Bitmap decodeSampledBitmapFromResource(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) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}


참고

그런데 web 에서 받아온 image 를 바로 resizing 하고 싶어서 아래와 같은 코드를 사용했다. 그런데 실패 했다.

 HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();

 InputStream is = new BufferedInputStream(conn.getInputStream(), BUFFER_SIZE);

 // First decode with inJustDecodeBounds=true to check dimensions
 final BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = true;
 BitmapFactory.decodeStream(is, null, options);

 
 // Calculate inSampleSize
 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
 
 // Decode bitmap with inSampleSize set
 options.inJustDecodeBounds = false;
 Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
 

아래 같은 error 가 발생했는데, 결과적으로 bitmap 이 null 로 왔다.
SkImageDecoder::Factory returned null
이유는  inputStream 은 한 번 사용하면(read) 다시 읽지 못한다고 한다.[ref. 2] (너무 기본적인걸 모르고 있었네요. ㅜ.ㅜ)


Reference

  1. http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap
  2. http://stackoverflow.com/questions/2503628/bitmapfactory-decodestream-returning-null-when-options-are-set

댓글 없음:

댓글 쓰기