안드로이드 이미지뷰(ImageView)에 이미지 파일 표시하기. (Displaying an image file in ImageView)

2017. 7. 3. 15:54


1. ImageView의 src 속성과 setImageResource() 함수.

이전 글 [개발자 레시피 - 안드로이드 이미지뷰 기본 사용법]에서, ImageView에 png 또는 jpg 형식의 이미지를 표시하는 방법에 대해 살펴보았습니다. ImageView의 src 속성과, src 속성의 매핑 함수인 setImageResource() 함수를 사용하여 이미지를 표시하는 방법을 설명하였습니다.


그런데, ImageView의 src 속성을 사용하여 이미지를 표시하는 방법은, Drawable 리소스에 포함된 이미지만 화면에 표시할 수 있다는 단점이 있습니다. 인터넷을 통해 다운로드하거나, SD 카드와 같은 외부 저장소에 저장된 이미지 파일(png, jpg)을 표시하기 위해 src 속성을 사용할 수는 없다는 것이죠. 그 이유는 바로 ImageView의 src 속성과 setImageResource() 함수가 Drawable 리소스 ID을 사용하도록 되어 있기 때문입니다.

ImageView의 src 속성과 setImageResource() 함수


음, 그렇다면 Drawable 리소스에 포함된 이미지가 아닌, 인터넷을 통해 다운로드한 이미지 파일(png, jpg)을 ImageView에 표시하는 방법은 없는 걸까요? 아니오, 방법이 있습니다.


setImageResource() 함수를 사용하지 않고, setImageBitmap() 함수를 사용하면 됩니다.

1.1 setImageBitmap() 함수와 Bitmap 클래스

ImageView의 setImageBitmap() 함수는 ImageView의 내용(content)으로 Bitmap을 지정하는 함수입니다.

ImageView의 setImageBitmap() 함수


여기서 파라미터로 전달되는 변수의 타입은 Bitmap이라는 클래스인데요, Bitmap클래스는 압축되지 않은 이미지 전체 데이터를 저장 및 관리하는 클래스입니다. png 또는 jpg 형식의 이미지 파일은 원본 이미지를 압축(encoding)하여 저장한다는 것을 아실거라 생각합니다. 그리고 프로그램에서 파일을 압축 해제(decoding)한 다음, 원본 이미지의 압축되지 않은 전체 이미지 데이터를 가지고 있는 클래스가 바로 Bitmap클래스인 것이죠.


여기까지 내용을 정리하자면, 이미지 파일을 ImageView에 표시하기 위해서는, 압축된(encoded) 형식의 jpg 또는 png 파일을 읽어서 압축되지 않은(decoded) 데이터를 가지는 Bitmap으로 변환한 다음, 생성된 Bitmap 클래스 변수를 ImageView의 setImageBitmap() 함수에 전달하면 되는 것입니다.


그렇다면 이제, 압축된(encoding) 형식의 jpg 또는 png 파일을 읽어서 압축을 풀고(decoding) Bitmap 클래스로 변환하는 방법만 알면 되겠네요.


이미지 파일을 Bitmap으로 변환하는 기능을 제공하는 클래스는 BitmapFactory 클래스입니다.

1.2 BitmapFactory 클래스

BitmapFactory 클래스는 파일(file), 스트림(stream), 바이트-배열(byte-array) 등의 다양한 소스(source)로부터 이미지 데이터를 읽어들여 Bitmap객체를 생성하는 클래스입니다.

ImageFactory의 역할


"Factory"라는 단어가 "공장"을 의미한다는 것을 떠올려보면, "BitmapFactory"라는 이름이 "Bitmap"을 만드는 "Factory"라는 뜻이라는 것을 쉽게 알 수 있죠.


BitmapFactory 클래스에는 "decodeXxx()"로 이름지어진 많은 수의 static 함수가 정의되어 있는데, 어떤 소스(source)로부터 이미지 데이터를 읽어Bitmap을 생성할 것인지에 따라, 각각의 이름과 파라미터로 구분됩니다.


리턴 타입 메소드 이름 설명
Bitmap decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts) 바이트-배열 data의 offset 부터 length 만큼 opts에 따라 읽어들여 Bitmap 생성
Bitmap decodeByteArray(byte[] data, int offset, int length) 바이트-배열 data의 offset 부터 length 만큼 읽어들여 Bitmap 생성.
Bitmap decodeFile(String pathName, BitmapFactory.Options opts) pathName 경로의 파일을 opts에 따라 읽어들여 Bitmap 생성.
Bitmap decodeFile(String pathName) pathName 경로의 파일을 읽어들여 Bitmap 생성.
Bitmap decodeFileDescriptor(FileDescriptor fd) fd로부터 Bitmap 생성.
Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, BitmapFactory.Options opts) fd로부터 opts에 따라 padding이 들어간 Bitmap 생성.
Bitmap decodeResource(Resources res, int id) id의 리소스로부터 Bitmap 생성.
Bitmap decodeResource(Resources res, int id, BitmapFactory.Options opts) id의 리소스로부터 opts에 따라 Bitmap 생성.
Bitmap decodeResourceStream(Resources res, TypedValue value, InputStream is, Rect pad, BitmapFactory.Options opts) 입력 스트림 is로부터 opts에 따라 padding이 들어간 Bitmap 생성.
Bitmap decodeStream(InputStream is) 입력 스트림 is로부터 Bitmap 생성.
Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts) 입력 스트림 is로부터 opts에 따라 padding이 들어간 Bitmap 생성.

1.3 이미지 표시하는 코드

앞에서 살펴 본 BitmapFactory의 decodeXxx() 함수와 ImageView의 setImageBitmap() 함수를 사용하여 이미지 파일을 이미지뷰에 표시하는 코드는 아래와 같습니다.

    Bitmap bm = BitmapFactory.decodeStream("image.png") ;

    ImageView imageView = (ImageView) findViewById(R.id.image1) ;
    imageView.setImageBitmap(bm) ;

2. 파일로부터 이미지를 읽어 이미지뷰(ImageView)에 표시하기.

그럼 지금부터 예제 앱 작성을 통해, 파일에 저장된 이미지를 읽어 이미지뷰에 표시하는 방법에 대해 살펴보도록 하겠습니다. 작성할 예제는 하나의 이미지뷰만을 가지는 단순한 화면으로 구성되며, 이미지뷰에 표시할 이미지 파일은 안드로이드 애셋(Asset)을 통해 앱에서 읽을 수 있도록 만들겠습니다. (안드로이드 애셋(Asset)에 대한 자세한 내용은 [안드로이드 애셋(Asset) 사용하기.])를 통해 확인할 수 있습니다.

2.1 MainActivity의 레이아웃 작성.

앞서 언급한대로, MainActivity는 하나의 이미지뷰만을 가집니다.

[STEP-1] "activity_main.xml" - MainActivity의 Layout 구성.
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/image1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

2.2 애셋(Asset) 폴더 추가.

안드로이드에서 애셋(Asset)을 사용하기 위해서는, 애셋(Asset) 폴더를 추가해야 합니다. [안드로이드 애셋(Asset) 사용하기.]에서 설명했듯이, New - Folder - Assets Folder 메뉴를 통해 애셋 폴더를 추가할 수 있습니다.

[STEP-2] 애셋(Asset) 폴더 추가. (src/main/assets)

ImageView 파일 예제 애셋 폴더에 이미지 파일 추가


2.3 애셋(Asset) 폴더에 이미지 파일 추가하기.

위에서 만든 애셋(Asset) 폴더에 이미지 파일을 추가합니다. 이는 이미지 파일을 Drawable 리소스 폴더에 추가하는 방법과 동일합니다. 즉, 탐색기에서 이미지파일을 복사(Ctrl + C)한 다음, 애셋(Asset) 폴더(src/main/assets)에 붙여넣으면(Ctrl + V) 됩니다.

[STEP-3] 애셋(Asset) 폴더에 이미지 파일 추가.

ImageView 파일 예제 애셋 폴더에 이미지 파일 추가


2.4 애셋(Asset) 폴더에서 이미지 파일을 열어 이미지뷰에 표시하기.

마지막으로, AssetManager 클래스를 사용하여 애셋(Asset) 폴더에 저장된 파일을 여는 코드를 작성해야 합니다. 그리고 이미지 파일을 Bitmap으로 변환한 다음, 이미지뷰에 표시하는 것이죠.


예제에서 이미지 파일을 변환할 때는 BitmapFactory 클래스의 decodeStream(InputStream is) 함수를 사용합니다. 이는 AssetManager의 open() 함수가 InputStream 타입을 리턴하기 때문에, BitmapFactory에서 바로 사용 가능하기 때문입니다.


하지만 만약 로컬 저장소에 저장된 파일을 읽어야 한다면, 파일의 경로는 지정하는 decodeFile(String pathName) 함수를 사용하면 됩니다. 그리고 마찬가지로 메모리 버퍼에 저장된 내용을 Bitmap으로 변환하려면 decodeByteArray(byte[] data, int offset, int length) 함수를 사용하면 됩니다. 즉, 현재 사용 중인 입력 소스에 맞는 함수를 골라서 사용하면 되는 것이죠.

[STEP-4] MainActivity.java - AssetManager를 통해 이미지 파일 열기.
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
        // ... 코드 계속

        // 애셋매니저 
        AssetManager am = getResources().getAssets() ;
        InputStream is = null ;

        try {
            // 애셋 폴더에 저장된 field.png 열기.
            is = am.open("field.png") ;

            // 입력스트림 is를 통해 field.png 을 Bitmap 객체로 변환.
            Bitmap bm = BitmapFactory.decodeStream(is) ;

            // 만들어진 Bitmap 객체를 이미지뷰에 표시.
            ImageView imageView = (ImageView) findViewById(R.id.image1) ;
            imageView.setImageBitmap(bm) ;

            is.close() ;
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (is != null) {
            try {
                is.close() ;
            } catch (Exception e) {
                e.printStackTrace() ;
            }
        }

    }
}

3. 예제 실행 화면

예제를 작성하고 실행하면, 아래 그림과 같이 이미지 파일이 이미지뷰에 그려지는 것을 확인할 수 있습니다.

ImageView 파일 예제 실행 화면


4. 참고.

.END.


ANDROID 프로그래밍/IMAGEVIEW