[Kotlin] Inner Class

Inner Class는 어떤 클래스(A라고 하자)의 내부에 정의되는데.. 이 Inner Class는 바로 객체화 될수 없고, 먼저 A 클래스를 객체화한 뒤 객체화된 것을 통해 생성된다.

아래는 코틀린의 문법 중 Inner Class에 대한 예제이다.

open class Base {
    open val c: String = "Dip2K"
    open fun f() = println("Programmer, ${c}")
}

class Derived: Base() {
    override  val c: String = "Super ${super.c}"
    override fun f() = println("Developer, ${c}")

    inner class InnerClass {
        constructor() {
            println("InnerClass's constructor")
        }

        fun f() = println("InnerClass's fun: f")
        fun t() {
            f()
            Derived().f()
            super@Derived.f()
        }
    }
}

fun main() {
    val c = Derived()
    val i = c.InnerClass()

    i.t()
}

Inner Class를 기준으로 바깓 클래스 및 그 바깓 클래스의 부모 클래스에 대한 프로퍼티와 함수에 대한 접근에 대한 문법을 나타내고 있다. 실행결과는 다음과 같다.

InnerClass's constructor
InnerClass's fun: f
Developer, Super Dip2K
Programmer, Super Dip2K

카메라로 찍은 이미지 올바른 방향으로 회전시켜 보여주기

안드로이드의 폰에서 찍은 사진은 내부적으로 카메라의 회전 정보가 담겨 있습니다. 폰으로 찍은 사진을 화면에 표시할때 이 화전 정보를 반영하여 촬영된 이미지를 표시해야 자연스럽습니다. 아래의 코드는 이미지 파일에 대한 회전 정보를 얻는 코드입니다.

val imageFilePath = "...... . jpg"
val ei = ExifInterface(imageFilePath)
val orientation: Int = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
val angle = when(orientation) {
    ExifInterface.ORIENTATION_ROTATE_90 -> 90f
    ExifInterface.ORIENTATION_ROTATE_180 -> 180f
    ExifInterface.ORIENTATION_ROTATE_270 -> 270f
    else -> 0f
}

위의 코드를 통해 이미지의 회전 각도르 얻어올 수 있고, 이를 토대로 이미지를 실제로 회전시키는 코드는 다음과 같습니다.

private fun resizeBitmap(src: Bitmap, size: Float, angle: Float): Bitmap {
    val width = src.width
    val height = src.height

    var newWidth = 0f
    var newHeight = 0f

    if(width > height) {
        newWidth = size
        newHeight = height.toFloat() * (newWidth / width.toFloat())
    } else {
        newHeight = size
        newWidth = width.toFloat() * (newHeight / height.toFloat())
    }

    val scaleWidth = newWidth.toFloat() / width
    val scaleHeight = newHeight.toFloat() / height

    val matrix = Matrix()

    matrix.postRotate(angle);
    matrix.postScale(scaleWidth, scaleHeight)

    val resizedBitmap = Bitmap.createBitmap(src, 0, 0, width, height, matrix, true)
    return resizedBitmap
}

위의 함수는 카메라로 찍은 이미지를 회전시켜 주는 것뿐만 아니라 이미지의 크기를 화면에 표시하기에 적당한 크기를 인자로 받아 줄여줍니다. 실제 사용하는 코드는 다음과 같습니다.

val imageFilePath = "...... . jpg"
val file = File(imageFilePath)

val angle = ...

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    val source = ImageDecoder.createSource(contentResolver, Uri.fromFile(file))
    ImageDecoder.decodeBitmap(source)?.let {
        imageView.setImageBitmap(resizeBitmap(it, 900f, 0f))
    }
} else {
    MediaStore.Images.Media.getBitmap(contentResolver, Uri.fromFile(file))?.let {
        imageView.setImageBitmap(resizeBitmap(it, 900f, 0f))
    }
}