Android/Error

[Android] trying to draw too large Bitmap 해결하기 - Bitmap Resize

점냥 2020. 2. 7. 19:42
반응형

 

RuntimeException : try to draw too large ( 바이트 수 ) Bitmap

위 명시되어 있는 Exception은 메모리 캐싱 등의 부가 기능을 제공해 주는 이미지 라이브러리 없이 직접 메모리 용량이 큰  이미지View에 로딩 했을 때, 나타나는 문제입니다. 

우리가 사용할 수 있는 application의 메모리는 제한되어 있기 때문에 Bitmap Resize를 적용해주는 것이 좋습니다.

 

 

Bitmap 크기 가져오기

 

BitmapFactory class는 Bitmap을 생성하기 위해 여러 가지 Decode Method를 제공합니다.

decodeByteArray(), decodeFile(),decodeResource(), etc

위 함수를 사용하게 되면 Bitmap의 고유의 크기를 메모리에 할당하게 되면서 Error를 발생시킬 수 있습니다.

때문에 BitmapFactory.Options 사용해야 합니다.

 

val options = BitmapFactory.Options().apply {
    inJustDecodeBounds = true
}
BitmapFactory.decodeResource(resources, R.id.myimage, options)
val imageHeight: Int = options.outHeight
val imageWidth: Int = options.outWidth
val imageType: String = options.outMimeType

BitmapFactory.Options의 속성 중 inJustDecodeBoundstrue를 준 다음, decode Method를 호출하면 Method 반환값인 Bitmap은 null을 반환하지만, options 변수에 해당 Bitmap의 가로 세로 크기와 Type이 저장됩니다.

적용하고자 하는 Image의 크기만 먼저 가져와 application UI에 알맞은 크기를 계산한 뒤 다시 decode를 하는 것입니다.

 

 

저해상도 이미지

 

적용하고자 하는 이미지의 크기를 알아왔으니, application UI 크기에 맞게 크기를 줄이면 됩니다.

 

fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
    // Raw height and width of image
    val (height: Int, width: Int) = options.run { outHeight to outWidth }
    var inSampleSize = 1

    if (height > reqHeight || width > reqWidth) {

        val halfHeight: Int = height / 2
        val halfWidth: Int = 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
}

 

BitmapFactory.Options의 속성 중 inSampleSize 속성 값을 구하는 함수입니다.  원하는 가로 , 세로 크기가 함수 인자 reqWidth , reqHeight에 들어오고 미리 구한 Bitmap의 크기가 options.run { outHeight to outWidth }에 있습니다. 

미리 로드한 Bitmap의 크기가 reqWidth, reqHeight 보다 작을 때까지 알맞은 SampleSize의 값을 구하고 반환하는 함수입니다.

 

 

fun decodeSampledBitmapFromResource(
        res: Resources,
        resId: Int,
        reqWidth: Int,
        reqHeight: Int
): Bitmap {
    // First decode with inJustDecodeBounds=true to check dimensions
    return BitmapFactory.Options().run {
        inJustDecodeBounds = true
        BitmapFactory.decodeResource(res, resId, this)

        // Calculate inSampleSize
        inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)

        // Decode bitmap with inSampleSize set
        inJustDecodeBounds = false

        BitmapFactory.decodeResource(res, resId, this)
    }
}

반환된 inSampleSize 값으로 이제 UI에 알맞은 Size인 Bitmap를 실제로 로딩하기 위해, inJustDecodeBounds = false 설정해준 뒤

Decode 합니다.

 

imageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100))
 

 

 

참고

 

https://developer.android.com/topic/performance/graphics/load-bitmap#java

 

 

반응형