제임스딘딘의
Tech & Life

개발자의 기록 노트/Android

[안드로이드] 안드로이드의 이미지 Canvas, Bitmap, Drawable 개요

제임스-딘딘 2011. 6. 16. 16:45

안드로이드의 이미지 Canvas, Bitmap, Drawable 개요




안드로이드에서는 이미지를 다루기 위한 몇가지 클래스가 존재한다.

Canvas, Bitmap, Drawable이 그것이다.

각각의 이미지 관련 클래스들에 대해 전반적인 사항을 알아보고자 한다.



Drawable, 앱의 resource 디렉토리에 저장되어 있는 이미지 다루기

기본적으로 resource에 저장되어 있는 이미지의 경우에는 "Drawable" type의 객체로써 해당 이미지를 다룰 수 있다.
"Drawable" type을 화면에 그리는 예제 코드는 아래와 같다.
 
Drawable drawable = getResources().getDrawable(id);
drawable.setBounds(0,0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());  // drawable을 그리려는 영역을 지정
 
onDraw(canvas canvas) {
    drawable.draw(canvas);
}
setBounds 메소드로 설정한 영역에 따라, 자동으로 이미지가 scaling이 된다. 

만약 원본 이미지 사이즈가 100 x 50 이라고 가정을 하고, setBounds 메소드에 parameter를 (0,0, 200, 100)이라고 설정하면?

가로 세로가 2배로 확대되어서 그려지는 식이다.


Bitmap을 다루기

임의의 bitmap을 생성하고 bitmap에 원하는 내용을 그리는 방법을 살펴보자.

다음과 같이 임의의 bitmap을 생성할 수 있다.


Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);

 

세번째 parameter인 Config.ARGB_8888 외에도 몇가지 설정 가능한 값들이 존재한다. 


  • ALPHA_8 : 각 픽셀은 단일 반투평(알파) 채널로 저장된다.
  • ARGB_4444 : API level 13부터 더이상 유지보수 하지 않는 값. 이미지의 품질이 좋지 않기 때문이라고 한다. 이것을 사용하지 말고 ARGB_8888을 사용할 것이 권장된다. 
  • ARGB_8888 : 각 픽셀은 4bytes로 저장된다. 
  • HARDWARE : 비트맵이 그래픽 메모리에 저장되는 경우. 특수 설정값.
  • RGBA_F16 : 각 픽셀은 8bytes로 저장된다.
  • RGB_565 : 각 픽셀은 2 바이트로 저장되고 RGB 채널만 인코딩 된다. 빨간색은 5비트 정밀도 (32 개의 가능한 값)로 저장됨, 녹색은 6비트 정밀도 (64 개의 가능한 값)로 저장되며 파란색은 빨간색과 마찮가지로 5비트의 정밀도로 저장된다. 그래서 RGB_565 임.


원하는 걸로 생성하면 되는데, ARGB_8888로 생성할 경우 투명값을 지정할 수가 있는 반면, RGB_565로 생성하면 불투명한 이미지만 가능하다. 알파 채널을 제외하므로 메모리를 절약할 수 있는 장점이 있다.

이렇게 만들어진 bitmap에 직접 그림을 그리거나 다른 이미지를 그리려고 하면 아래와 같이 새로운 canvas를 만들어야 한다.

 

Canvas canvas = new Canvas();
canvas.setBitmap(bitmap);

 이렇게 하면, 향후에 canvas에 그리는 모든 작업은 bitmap에 반영이 된다.



Bitmap과 Drawable간의 변환

 안드로이드에서는 bitmap을 직접 다루기보단 대부분 Drawable이라는 wrapping된 형태로 이미지를 처리하기 때문에, Bitmap의 경우 종종 Drawable로 변환해야 하는 경우가 있다. 이런 경우를 위해서 BitmapDrawable이라는 클래스가 존재하는데, 아래 예제와 같은 방식으로 변환이 가능하다.

 

Drawable drawable = (Drawable)(new BitmapDrawable(bitmap));


BitmapDrawable은 Drawable로 type casting이 가능한 점을 기억하면 된다.

 

canvas 처리

 width X height 크기의 drawable 오브젝트가 있다고 가정하고, setBounds를 이용하여 임의의 좌표 (x, y)에 원래의 크기로 출력하려 한다면 아래와 같은 방법으로 가능하다.


obj.setBounds(x, y, x + width, y + height);
obj.draw(canvas);

 

그런데 사실, 이 방식은 귀찮은 점이 있다.

항상 width, height를 지정해 주어야 한다는 것인데, 이 때문에 코드가 상당히 길어져 보기 좋지 않다.

getIntrinsicWidth()/Height()로 항상 구하던지 별도의 변수에 값을 유지해야한다.

 

이를 피하려면 위 방법보다는 아래와 같이 canvas의 좌표이동 변환식을 이용하는게 깔끔하다.

 


obj.setBounds(0, 0, width, height); // 가로 세로 크기값은 drawable을 생성하는 최초 한번만 지정하면 됨

canvas.save(); // 현재 변환식을 저장함
canvas.translate(x, y) // 좌표이동과 관련된 변환식 적용함

obj.draw(canvas); // drawable을 그림

canvas.restore(); // 원래 변환식으로 복구함


canvas.translate(x, y) 를 지정할 경우 출력할 이미지를 (x, y)만큼 이동시켜서 그려준다. (좌표이동 행렬식이라고 생각하면 됨)