본문 바로가기
APP/Kotlin

[2D Graphic - 2] Bitmap, 부분 이미지 확대 및 축소, 이미지 상하 반전/회전

by 하_랭 2021. 12. 5.

우선, Canvas vs Bitmap

Canvas : 2D graphic을 그리는 데 필요한 class

Bitmap: Canvas 클래스와 연결되어 있는 그림을 그리기 위한 공간 

 

Activity는 화면에 view를 보여줌. setContentView()의 형식 인자로 view가 필요.

저번엔 View를 상속받은 custom view 객체를 만들었지만, 이번엔 ImageView를 사용할 것(ImageView도 View의 일종!)

 

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val myBitmap = Bitmap.createBitmap( // 비트맵 생성
            800, 600, Bitmap.Config.ARGB_8888
        )
        val myCanvas = Canvas(myBitmap)
        myCanvas.drawColor(Color.argb(255, 0, 0, 255))

        val paint = Paint()
        paint.textSize = 100f
        paint.color = Color.argb(255, 255, 255, 255)
        myCanvas.drawText("Hello World!!", 100f, 100f, paint)

        paint.color = Color.argb(255, 100, 100, 100)
        myCanvas.drawCircle(400f, 300f, 150f, paint)
        val myImageView = ImageView(this)
        myImageView.setImageBitmap(myBitmap)
        setContentView(myImageView)
    }
}

 


img를 Bitmap으로 변환

 

그리고 그려줄 것. 이떄 다음 drawBitmap사용 

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

- bitmap, dst는 null 되면 안됨

- src : bitmap의 subset

- dst : 원래 이미지보다 더 크게/작게 출력 가능

 

우선 img를 drawable에 넣어주고, MyView 클래스에 다음과 같이 써줌.

 

class MyView(context: Context): View(context) {
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) return

        canvas.drawColor(Color.LTGRAY)

        // img객체를 bitmap 객체로 변환
        val b: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.harubang)
        canvas.drawBitmap(b, 0f, 0f, null) // paint객체 필요 없음
    }
}

 

MainActivity.kt에는 요렇고롬 

setContentView(MyView(this))

 

 

화면과 이미지 크기 출력하고 싶으면 다음 코드 추가 

 

val paint = Paint()
paint.textSize = 50f
var px = 500f
var py = 100f
// 화면에 대한 width, height
canvas.drawText(width.toString(), px, py, paint)
canvas.drawText(height.toString(), px + 150f, py, paint)

py += 100f
// 이미지에 대한 width, height
canvas.drawText(b.width.toString(), px, py, paint)
canvas.drawText(b.height.toString(), px + 150f, py, paint)

(화면에 따라서 이미지 크기가 실제랑 다를 수 있음)

 

결과


bitmap 이미지 일부 확대/축소

 

위와 연결되는 내용.

위에서 이미지를 가져와 bitmap으로 바꾼 뒤 draw해주었음.

이번엔 그 bitmap 이미지의 일부만 출력하는 방법에 대해 할 것.

class MyView(context: Context): View(context) {
    // img객체를 bitmap 객체로 변환
    private val b:Bitmap = BitmapFactory.decodeResource(resources, R.drawable.harubang)
    private val w:Int = b.width
    private val h:Int = b.height

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) return

        canvas.drawColor(Color.LTGRAY)

        canvas.drawBitmap(b, 0f, 0f, null) // paint객체 굳이 필요 없음

        /**
         * 사진 일부만 보이게
         */
        val src = Rect(40, 40, 140, 140) // 하르방 왼쪽 눈
        var pi = w + 50 // bitmap의 폭 + 50
        val dst = Rect(pi, 0, pi + w, h)
        canvas.drawBitmap(b, src, dst, null) // b의 src부분을 dst에 그린다.

        var pj = h + 50 // bitmap의 높이 + 50
        val dst2 = Rect(pi, pj, pi + w/2, pj + h/2)
        canvas.drawBitmap(b, src, dst2, null) // b의 src부분을 dst2에 그린다.
    }
}

결과


bitmap 공간 만든 후 출력

 

위에서는 별도의 bitmap공간을 만들지 않았음. 이러면 전체 공간에 할당 됨.

그래서! 이번에는 bitmap 공간을 만들어 준 뒤, 거기에 bitmap 이미지를 출력해보자.

 

 

ver1. onDraw 메소드에서 createBitmap 실행 : Layout이 화면에 나타난 다음 메모리에 저장된 bitmap 이미지 출력

class MyView(context: Context): View(context) {
    // img객체를 bitmap 객체로 변환
    private val b:Bitmap = BitmapFactory.decodeResource(resources, R.drawable.harubang)

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) return
        canvas.drawColor(Color.LTGRAY)

        /**
         * bitmap 공간 생성 뒤 bitmap 이미지 출력
         */
        val mbitmap = Bitmap.createBitmap(600, 600,
                    Bitmap.Config.ARGB_8888)
        // canvas 안에 별도의 비트맵을 만들어 줌. mCanvas는 mbitmap 안에서만 사용가능
        val mCanvas = Canvas(mbitmap)
        mCanvas.drawColor(Color.YELLOW)
        mCanvas.drawBitmap(b, 50f, 50f, null)
        canvas.drawBitmap(mbitmap, 50f, 50f, null)
    }
}

 

 

ver2. onSizeChanged 메소드에서 createBitmap 실행 : Layout 화면에 나타나기 전에 실행

(drawBitmap을 사용해 미리 메모리에 bitmap 이미지를 그림)

class MyView(context: Context): View(context) {
    // img객체를 bitmap 객체로 변환
    private val b:Bitmap = BitmapFactory.decodeResource(resources, R.drawable.harubang)
    private val mBitmap = Bitmap.createBitmap(600, 600,
        Bitmap.Config.ARGB_8888)

    /**
     * bitmap 공간 생성 뒤 bitmap 이미지 출력 ver.2 [onSizeChanged] 메소드 사용
     */
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) return
        canvas.drawColor(Color.LTGRAY)
        canvas.drawBitmap(mBitmap, 50f, 50f, null)
    }
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        val mCanvas = Canvas(mBitmap)
        mCanvas.drawColor(Color.YELLOW)
        mCanvas.drawBitmap(b, 20f, 20f, null)
    }
}

 


이미지 확대/축소

 

createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) : src 비트맵을 dstWidth, dstHeight 크기로 조정해줌 

확대할 때 filter를 true로 해주면 edges가 스무스 해짐.

 

class MyView(context: Context): View(context) {
    lateinit var myBitmap:Bitmap
    lateinit var myCanvas:Canvas


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        myBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        myCanvas = Canvas(myBitmap)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) return

        myCanvas.drawColor(Color.BLUE)
        drawEnlargedBitmap()
        canvas.drawBitmap(myBitmap, 0f, 0f, null)
    }

    private fun drawEnlargedBitmap() {
        var bobBitmap:Bitmap = BitmapFactory.decodeResource(resources, R.drawable.bob)
        myCanvas.drawBitmap(bobBitmap, 25f, 25f, null)

        // 300, 400 으로 bobBitmap 크기 조정
        bobBitmap = Bitmap.createScaledBitmap(bobBitmap, 300, 400, false)
        val w = bobBitmap.width
        myCanvas.drawBitmap(bobBitmap, w + 25f, 25f, null)
    }
}

결과

 

요건 줄인 코드 

bobBitmap = Bitmap.createScaledBitmap(bobBitmap, 50, 75, false)

결과

 

이미지 회전

 

이미지 상하 반전 - matrix(변환행렬)사용 

package com.example.graphicexample

import android.content.Context
import android.graphics.*
import android.view.View

class MyView(context: Context): View(context) {
    lateinit var myBitmap:Bitmap
    lateinit var myCanvas:Canvas


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        myBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        myCanvas = Canvas(myBitmap)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) return

        myCanvas.drawColor(Color.BLUE)
        drawMirrorBitmap()
        canvas.drawBitmap(myBitmap, 0f, 0f, null)
    }

    private fun drawMirrorBitmap() {
        var bobBitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.bob)
        myCanvas.drawBitmap(bobBitmap, 25f, 25f, null)

        val matrix = Matrix()
        matrix.preScale(1f, -1f) // y값 뒤집힘
        val w = bobBitmap.width
        val h = bobBitmap.height
        var bobBitmap2 = Bitmap.createBitmap(bobBitmap, 0, 0, w, h, matrix, false)

        myCanvas.drawBitmap(bobBitmap2, 25f, h + 50f, null)
        matrix.preRotate(-90f) // 반시계 방향으로 90도 회전
        var bobBitmap3 = Bitmap.createBitmap(bobBitmap, 0, 0, w, h, matrix, false)
        myCanvas.drawBitmap(bobBitmap3, 25f, 2*h + 50f, null)
    }
}

결과

 

 

 

 

댓글