안드로이드

[Android/Kotlin] 카메라로 사진 찍고 이미지뷰에 넣기 (2)

mingmaeng 2020. 4. 22. 13:18

진짜 오랜만에 글을 포스팅하는 것 같다. 최근 토익 공부하느라 블로그에 신경을 많이 못 썼는데, 열심히 포스팅하다가

시간이 흘러 다시 포스팅을 하고 있으니 블로그 초창기 글을 쓸 때랑 기분이 비슷하다. ㅎㅎㅎ

지난번에 안드로이드 기본 카메라를 이용하여 사진을 찍고 그 사진을 이미지 뷰에 넣는 작업을 했다.

그러나 내가 찍었던 사진이 원치 않는 회전된 상태로 들어가 버렸다. (90도로 돌아간 상태로 화면에 나온다던지...)

오늘은 찍은 사진이 회전되지 않으면서 원래의 모양 그대로 들어가는 법을 알아보겠다.

 


이전에 실습했던 코드를 수정 및 추가하는 포스팅이기에 이전 글을 보지 못했던 분들이라면 아래 링크를 통해 확인하길 바란다.

 

[Android/Kotlin] 카메라로 사진 찍고 이미지뷰에 넣기

잠시 이전 코드를 수정합시다.

이전 카메라 포스팅을 보면 이러한 코드가 있었다.

 

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
           val file = File(currentPhotoPath)
            if (Build.VERSION.SDK_INT < 28) {
            val bitmap = MediaStore.Images.Media
                .getBitmap(contentResolver, Uri.fromFile(file))
            img_picture.setImageBitmap(bitmap)
            }
            else{
                val decode = ImageDecoder.createSource(this.contentResolver,
                    Uri.fromFile(file))
                val bitmap = ImageDecoder.decodeBitmap(decode)
                img_picture.setImageBitmap(bitmap)
            }
        }
    }

 

onActivityResult()에서 getBitmap()이 Deprecated 돼서 sdk 28 버전을 기준으로 이미지 뷰에 표시하는 방법을 나눈 코드였다.

그때 당시 이렇게 해도 Deprecated 되는 건 여전했었다. 여러 가지를 찾아보던 끝에 방법을 찾았다.

현재 코드보다 더 간단하고 짧은 코드로 깔끔하게 정리 수정하였다.

 

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
            val bitmap = BitmapFactory.decodeFile(currentPhotoPath)
            img_picture.setImageBitmap(bitmap)
        }
    
    }

 

BitmapFactory를 이용해서 이미지 뷰에 넣는 방법이다. 정말 깔끔해지지 않았는가?

 

멋대로 돌아가버리는 사진을 다 잡아 보자.

지난 코드에서 걸리적거리는 부분을 수정완료 했으니, 이제 제멋대로 돌아가버리는 사진을 수정해보자.

먼저 이미지가 몇 도 회전했는지를 알아본 후 그에 맞춰 사진을 원래 방향으로 돌리는 형식이다.

이미지가 몇 도 회전했는지를 알아보는 함수 1개와 사진을 원래 방향으로 돌리는 함수 1개 총 2개의 함수를 만들어보자.

 

먼저 이미지가 몇 도 회전했는지를 알아보는 함수다.

 

MainActivity.kt

    private fun exifOrientationToDegress(exifOrientation: Int): Int {
        when(exifOrientation){
            ExifInterface.ORIENTATION_ROTATE_90 -> return 90
            
            ExifInterface.ORIENTATION_ROTATE_180 -> return 180
            
            ExifInterface.ORIENTATION_ROTATE_270 -> return 270
            
            else -> return 0


        }
    }

 

ExifInterface()를 이용해서 사진이 90도, 180도, 270도 돌아갔는지를 파악하는 함수다. switch문을 이용해서 내가 찍은 사진이 얼마나 회전되었는지에 따라 Int값을 리턴해준다. "else -> return 0"은 사진이 찍힌 그 상태로 온전히 있을 경우다.

 

private fun rotate(bitmap: Bitmap, degree: Int) : Bitmap {
        Log.d("rotate","init rotate")
        val matrix = Matrix()
        matrix.postRotate(degree.toFloat())
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix,true)
    }

 

실제 사진을 원래대로 회전시켜주는 함수다. Matrix 기능을 이용해서 사진을 원래대로 돌려주는 역할을 한다.

여기서 매개변수는 다음과 같은 역할을 한다.

 

bimap : 내가 촬영했던 사진을 Bitmap 형식으로 가지고 있는 변수

degree : exifOrientationToDegress() 함수에서 리턴된 값

 

이 두개의 함수를 만들고 나면 앞서 수정했던 onActivityResult() 함수에 추가적으로 코드를 변경하고 추가해주면 완성이다.

 

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
            val bitmap = BitmapFactory.decodeFile(currentPhotoPath)
            lateinit var exif : ExifInterface

            try{
                exif = ExifInterface(currentPhotoPath)
                var exifOrientation = 0
                var exifDegree = 0

                if (exif != null) {
                    exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                        ExifInterface.ORIENTATION_NORMAL)
                    exifDegree = exifOrientationToDegress(exifOrientation)
                }

                img_picture.setImageBitmap(rotate(bitmap, exifDegree))
            }catch (e : IOException){
                e.printStackTrace()
            }

        }
    }

 

ExifInterface 객체의 exif를 하나 만들어 준다. ExifInterface란 이미지가 가지고 있는 정보들의 집합 클래스다.

사진의 가로 세로 길이, 회전 값들을 담고 있기 때문에 이를 이용해 이미지의 회전값을 파악하고 변경할 수 있게 된다.

try-catch 문을 이용하여 촬영한 이미지의 정보를 받아 exifOrientationToDegress()함수를 이용해 회전된 값을 추출하고, rotate() 함수를 이용해서 원래의 방향으로 회전시켜 준다.

 

실습 화면

사진에 찍힌 다른 사람들은 그림판으로 샤샤샥

 

버튼을 누르면 저번에 실습했던 것 처럼 카메라가 켜지면서 사진을 찍을 수 있게 된다.

 

 

확인 버튼을 누르면 이전 실습 프로젝트와는 다르게 제대로 된 방향으로 사진이 온전히 화면에 나오는 걸 확인할 수 있다.

 


어떻게 보면 어렵고 어떻게 보면 쉬운 그런 카메라 기능이다. 앱에서 그렇게 많이 쓰이진 않지만, 그래도 살면서 한 번 정도는 사용할 것이고, 안 쓴다는 보장은 없으니 재미 삼아서 공부해 보면 좋다.

모든 기능들이 그렇지만 작동 원리를 이해하고, 실습을 진행하면 쉽게 이해 할 수 있기 때문에 동작 원리부터 천천히

파악하고 실습에 임하길 바란다.

 

아래는 기존 카메라 예제를 실습했던 프로젝트에 이번에 포스팅한 실습버전을 추가해 놓은 코드다. 잘 모르겠으면 확인해보면서 천천히 따라 해 보길 바란다.

 

https://github.com/kangmin1012/AndroidExcercise/tree/UseCamera

 

kangmin1012/AndroidExcercise

Contribute to kangmin1012/AndroidExcercise development by creating an account on GitHub.

github.com