[Kotlin] 이미지 크롭

Hand·2022년 10월 4일
0

Android

목록 보기
15/17

💡 이미지 크롭하는 방법은 쉽게 찾을 수 있습니다. 하지만, 크롭을 위한 새로운 뷰를 띄우고 거기서 크롭을 해서 받은 데이터를 activityForResult()에서 받아서 처리하는 방법만 찾을 수 있어 이 글을 작성합니다.

제가 원하는 이미지크롭 방법은 인스타그램을 생각하시면 됩니다. 같은 뷰 내에서 이미지를 자르고, 이를 처리하여 다른 Activity로 전송하는 그러한 방법을 생각하였습니다.

로직

  1. 새로운 글 작성 페이지
  2. 사진 추가 버튼 클릭
  3. 앨범 페이지
  4. 앨범 페이지 내에서 이미지 선택
  5. 앨범 페이지 내에서 선택한 이미지 자르기
  6. 저장을 누르면 새로운 글 작성 페이지에서 자른 이미지 보여주기

여기서 가장 어렵다고 생각한 부분은 앨범 페이지 내에서 선택한 이미지 자르기 였습니다.

페이지 내에서 선택한 이미지 자르기

저는 일단 많은 라이브러리 중에서 CropMe라는 라이브러리를 사용할 예정입니다.
CropMe
이 라이브러리가 레이아웃으로 사용가능하며, 딱 제가 생각한 이미지 크롭 방법이라 생각하여 사용했습니다.

테스트를 위해서 인스타와 거의 동일하게 구현을 해보았습니다.

activity_album.xml

반은 스마트폰 내부의 이미지들을 보여주고, 반은 Croplayout을 보여주고, 버튼 2개를 두었습니다.
왼쪽 위는 저장, 오른쪽 위는 자르기라고 생각하시면 됩니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <com.takusemba.cropme.CropLayout
        android:id="@+id/cl_CropImage"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:cropme_background_alpha="100%"
        app:cropme_frame_height_percent="100%"
        app:cropme_frame_width_percent="100%"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintBottom_toTopOf="@id/rv_SelectedImages"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginBottom="5dp"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/btn_Add"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"/>

    <Button
        android:id="@+id/btn_End"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_SelectedImages"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="vertical"
        android:paddingStart="10dp"
        android:layout_marginTop="5dp"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cl_CropImage"
        app:spanCount="3"
        tools:listitem="@layout/layout_album_image" />

</androidx.constraintlayout.widget.ConstraintLayout>

Activity

이미지들을 가져와서 보여주는 것은 전 포스트에서 했습니다.
갤러리 열지 않고 이미지 가져오기

이미지를 CropLayout에 보여준다.

val cropLayout = binding.clCropImage

//Uri
cropLayout.setUri(image)
//Bitmap
cropLayout.setBitmap(image)

Uri를 통해서 보여주냐, Bitmap을 통해서 보여주냐 2가지 방법이 있습니다.

이벤트가 발생했을 때, 이미지를 잘라준다.

저는 맘편하게 버튼 클릭 이벤트가 발생했을 때, 이미지를 잘라주겠습니다.

add.setOnClickListener {
	cropLayout.crop()
}

이렇게 하면 이미지를 자를 수 있습니다.

잘린 이미지를 받아와서 처리
cropLayout의 Listener를 이용해줍니다.

cropLayout.addOnCropListener(object : OnCropListener {
	// 성공했을 때,
	override fun onSuccess(bitmap: Bitmap) {
		checkedImages[position] = bitmap
		images[position].flag = true

		adapter.notifyDataSetChanged()
	}
	// 실패했을 때,
	override fun onFailure(e: Exception) {
		Log.e("Failure", "$e")
	}
})

저 같은 경우 여러 장을 처리해서 넘겨야 하는 기능을 구현해야 했습니다.
그래서 checkedImages라는 LinkedHashMap<Int, Bitmap>()을 구현한 뒤
여기에 순번과, 이미지들을 저장해주었습니다.

잘린 이미지는 모두 Bitmap으로 밖에 되지 않는 것 같습니다.


이렇게 고양이를 약간 좌측으로 하고 자르기 버튼을 눌러봤습니다.
미리보기 이미지에서 정상적으로 좌측으로 잘린 고양이가 보이는 것을 확인할 수 있습니다.

이미지를 자르는 포스트는 여기까지입니다!

다음 발생한 문제점

Bitmap은 생각보다 크기가 큽니다.
이를 intent를 통해 옮겨주려고 하면 당연하게도 에러가 발생할 것 입니다.

저는 그래서 Bitmap을 String으로 바꾼 뒤, 보내고
받은 String을 Bitmap으로 바꿔줘서 처리해주었습니다.

다음 포스트에서 작성할게요~!

profile
화이팅!

0개의 댓글