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] (너무 기본적인걸 모르고 있었네요. ㅜ.ㅜ)
댓글 없음:
댓글 쓰기