달달한 스토리

728x90
반응형

오늘은 이미지 크롭 기능을 구현해 보려고 한다.

 

여러 크롭 라이브러리들이 있지만, 나는 이 라이브러리가 

 

제일 심플한 것 같아서 사용을 해보았다.

 

 

https://github.com/lyrebirdstudio/Croppy

 

lyrebirdstudio/Croppy

Image Cropping Library for Android. Contribute to lyrebirdstudio/Croppy development by creating an account on GitHub.

github.com

 

이런 식으로 크기 영역을 원하는 식으로 조정할 수 있다는 장점을 가지고 있다.

 

한번 손쉽게 구현해보자.

 

우선 종속성을 넣어주자.

 

위에 사이트에 나와있는 대로 종속성을 추가해준다.

 

나도 아직 초보라서 잘 모르겠지만, 이렇게 종속성을 추가하니

 

해당 라이브러리의 클래스들이 임포트 되지 않았다.

 

그래서 외부 라이브러리를 그대로 가져와 적용하는 방법을 선택했다.

 

우선 아래 두 라이브러리를 다운로드하여주자.

 

CroppyLibrary.zip
0.08MB

 

두 라이브러리를 하나로 압축하였다.

 

다운을 받고 압축을 풀어주면 두 폴더가 있을 것이다.

 

이 두 폴더를 원하는 프로젝트 폴더에 넣어주자.

 

이렇게 폴더에 넣어주고,

 

안드로이드 스튜디오를 실행해보자.

실행을 하게 되면 이렇게 프로젝트 내부에 두 개의 라이브러리가 들어가 있는 것을 볼 수 있다.

 

하지만,

 

여기서 바로 사용은 할 수 없다.

 

이 라이브러리 모듈들을 연결을 해줘야 사용할 수가 있다.

 

우선

 

 

settings.gradle로 들어가

 

':croppylib', ':aspectratiorecyclerviewlib'

 

이 두 라이브러리를 인클루드 해준다.

 

그러고 나서 프로젝트에 경로를 넣어준다.

이 라이브러리가 어디 있는지 경로를 나타내 주는 것이다.

 

그리고 build.gradle로 들어가서,

 

아까 적었던 경로에 라이브러리를 종속성에 이런 식으로 추가해준다.

 

복잡해 보이지만, 이렇게 하는 방법으로도 라이브러리를 사용 가능하다.

 

여기까지 오래 걸렸지만, Croppy라이브러리를 사용해보자.

 


사용법

 

아 그리고 참고로 뷰 바인딩과 데이터 바인딩을 사용하고 있다.

 

모르는 분들은 내 이전 "뷰 바인딩"을 참고하길 바란다.

 

우선 MainActivity이다.

 

class MainActivity : AppCompatActivity() {

    var mBinding: ActivityMainBinding? = null
    val binding get() = mBinding!!

    val TAG: String = "로그"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        Log.d(TAG, "MainActivity - onCreate() called")

        binding.buttonChoose.setOnClickListener {
            Log.d(TAG, "MainActivity - 버튼클릭 이미지 크롭 실행")
            startCroppy() // 이미지 크롭 실
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.d(TAG, "MainActivity - onActivityResult() called")

        if (requestCode == RC_CROP_IMAGE) {
            data?.data?.let {
                Log.v("TEST", it.toString())
                binding.imageViewCropped.setImageURI(it)
                Log.d(TAG, "MainActivity - 수정된 이미지 가져와서 이미지 뷰에 삽입 ")
            }
        }
    }

    private fun startCroppy() {
        val uri = Uri.Builder()
            .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
            .authority(resources.getResourcePackageName(R.drawable.bb)) //권한을 인코딩하고 설정한다.
            .appendPath(resources.getResourceTypeName(R.drawable.bb)) //주어진 세그먼트를 인코딩하고 경로에 추가한다.
            .appendPath(resources.getResourceEntryName(R.drawable.bb))
            .build()

        //외부에 저장하고 URI를 반환합니다.
        val externalCropRequest = CropRequest.Auto(
            sourceUri = uri,
            requestCode = RC_CROP_IMAGE
        )

        //캐시에 저장하고 URI를 반환합니다.
        val cacheCropRequest = CropRequest.Auto(
            sourceUri = uri,
            requestCode = RC_CROP_IMAGE,
            storageType = StorageType.CACHE
        )

        // 지정된 대상 URI에 저장합니다.
        val destinationUri =
            FileCreator
                .createFile(FileOperationRequest.createRandom(), application.applicationContext)
                .toUri()

        val manualCropRequest = CropRequest.Manual(
            sourceUri = uri,
            destinationUri = destinationUri,
            requestCode = RC_CROP_IMAGE
        )



        //실질적으로는 이것을 사용
        //비율종류
        val excludeAspectRatiosCropRequest = CropRequest.Manual(
            sourceUri = uri,
            destinationUri = destinationUri,
            requestCode = RC_CROP_IMAGE,
            //색 설정
            croppyTheme = CroppyTheme(R.color.white),

            //제외했으면 하는 비율 종류 넣기
            excludedAspectRatios = arrayListOf( //비율종류
                AspectRatio.ASPECT_1_2,
                AspectRatio.ASPECT_3_2,
                AspectRatio.ASPECT_3_4,
                AspectRatio.ASPECT_4_3,
                AspectRatio.ASPECT_5_4,
                AspectRatio.ASPECT_A_4,
                AspectRatio.ASPECT_A_5,
                AspectRatio.ASPECT_FACE_COVER,
                AspectRatio.ASPECT_FACE_POST,
                AspectRatio.ASPECT_FREE,
                AspectRatio.ASPECT_INS_1_1,
                AspectRatio.ASPECT_INS_4_5,
                AspectRatio.ASPECT_INS_STORY,
                AspectRatio.ASPECT_PIN_POST,
                AspectRatio.ASPECT_TWIT_HEADER,
                AspectRatio.ASPECT_TWIT_POST,
                AspectRatio.ASPECT_YOU_COVER
            )
        )

        val themeCropRequest = CropRequest.Manual(
            sourceUri = uri,
            destinationUri = destinationUri,
            requestCode = RC_CROP_IMAGE,
            croppyTheme = CroppyTheme(R.color.blue) //색 설정
        )

        Croppy.start(this, excludeAspectRatiosCropRequest)
    }

    companion object {
        private const val RC_CROP_IMAGE = 102

    }
}

우선은 버튼을 클릭할 때 startCroppy가 실행이 되도록 했다.

 

 val uri = Uri.Builder()
            .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
            .authority(resources.getResourcePackageName(R.drawable.bb)) //권한을 인코딩하고 설정한다.
            .appendPath(resources.getResourceTypeName(R.drawable.bb)) //주어진 세그먼트를 인코딩하고 경로에 추가한다.
            .appendPath(resources.getResourceEntryName(R.drawable.bb))
            .build()

 

그러면 이 부분에서 미리 넣어둔 사진을 Crop기능을 구현할 수 있는

 

Croppy가 빌드가 된다.

 

// 지정된 대상 URI에 저장합니다.
        val destinationUri =
            FileCreator
                .createFile(FileOperationRequest.createRandom(), application.applicationContext)
                .toUri()

여기서 지정된 대상 Uri를 저장하는 역할을 해준다.

 

그리고

 

//실질적으로는 이것을 사용
        //비율종류
        val excludeAspectRatiosCropRequest = CropRequest.Manual(
            sourceUri = uri,
            destinationUri = destinationUri,
            requestCode = RC_CROP_IMAGE,
            //색 설정
            croppyTheme = CroppyTheme(R.color.white),

            //제외했으면 하는 비율 종류 넣기
            excludedAspectRatios = arrayListOf( //비율종류
                AspectRatio.ASPECT_1_2,
                AspectRatio.ASPECT_3_2,
                AspectRatio.ASPECT_3_4,
                AspectRatio.ASPECT_4_3,
                AspectRatio.ASPECT_5_4,
                AspectRatio.ASPECT_A_4,
                AspectRatio.ASPECT_A_5,
                AspectRatio.ASPECT_FACE_COVER,
                AspectRatio.ASPECT_FACE_POST,
                AspectRatio.ASPECT_FREE,
                AspectRatio.ASPECT_INS_1_1,
                AspectRatio.ASPECT_INS_4_5,
                AspectRatio.ASPECT_INS_STORY,
                AspectRatio.ASPECT_PIN_POST,
                AspectRatio.ASPECT_TWIT_HEADER,
                AspectRatio.ASPECT_TWIT_POST,
                AspectRatio.ASPECT_YOU_COVER
            )

이곳에서 색과 요청 코드, 그리고 크롭에서 제공되는

 

비율 중에서 어떤 것은 제거하고 싶으면,

 

여기서 제거하고 싶은 사이즈를 추가해주면 되는 것이다.

 

나는 16:9와 9:16 사이즈를 제외하고는 전부 제외시켰다.

Croppy.start(this, excludeAspectRatiosCropRequest)

그러고 해당 리퀘스트를 실행하고자. Croppy.start함수를 호출해준다.

 

그리고 나서 크롭 기능을 완료하는 버튼을 누르게 되면

 

onActivityResult 함수로, 수정된 uri가 넘어오게 된다.

 

companion object {
        private const val RC_CROP_IMAGE = 102

    }

요청 코드를 지정해주고,

 

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.d(TAG, "MainActivity - onActivityResult() called")

        if (requestCode == RC_CROP_IMAGE) {
            data?.data?.let {
                Log.v("TEST", it.toString())
                binding.imageViewCropped.setImageURI(it)
                Log.d(TAG, "MainActivity - 수정된 이미지 가져와서 이미지 뷰에 삽입 ")
            }
        }
    }

넘어온 uri를 이미지 뷰에다가 삽입을 해준다.

 

아래는 activity_main.xml이다.

 

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        android:background="#212121">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/imageViewCropped"
            android:layout_width="match_parent"
            android:layout_marginTop="24dp"
            android:layout_centerInParent="true"
            android:layout_height="match_parent"
            android:layout_above="@+id/buttonChoose"/>

        <com.google.android.material.button.MaterialButton
            android:id="@+id/buttonChoose"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_margin="24dp"
            android:text="Start Cropping" />

    </RelativeLayout>
</layout>

 

그렇다면 해당 결과물이 어떻게 나오는지 확인해보자.

 

 

이런 식으로 내가 제외했던 비율들을 제외하고

 

16:9와 9:16 비율만이 나온 것을 볼 수 있다.

 

확인 버튼을 누르면 내가 자른 사진만큼만

 

이미지 뷰에 삽입되는 것을 볼 수 있다.

 

그런데 여기서 한 가지 아쉬운 점은

 

저 비율들이 가운데로 위치했으면 좋을 것 같고,

 

처음 크롭 기능이 빌드되었을 때,

 

9:16으로 처음 설정이 안 되어있던 게 나는 아쉬웠다.

 

그러면 어떻게 수정하면 좋을까?

 

방법은

 

라이브러리 내부 코드를 수정하면 되는 것이다.

 

 

라이브러리도 결국 사람이 만든 것이기 때문에

 

내가 직접 건들고,

 

수정이 가능하다.

 

하지만 유의해야 할 점이 있다.

 

지금 우리가 한 것처럼 외부 라이브러리를 이런 식으로 가져오게 되면,

 

수정이 가능하게 되지만,

 

만약 단순히 종속성으로만 라이브러리를 가져오게 되면,

 

수정이 불가능하다.

 

이 불가능한 수정 방법은 내가 추후에 설명하고자 한다.

 

우선 우리는 내가 이 블로그에 파일을 올려 직접 가져왔기 때문에,

 

수정이 가능한 상태이다.

 

 

 

나는 이 리사이클 러뷰 부분을 가운데로 볼 수 있게 수정하고,

 

처음 비율을 정해줄 때 0.3초 뒤에 9:16 비율로 변할 수 있게

 

스레드로 콜백을 구현하였다.

 

결과는 아래와 같다.

 

 

 

이런 식으로 원하는 구현을 맞췄다.

 

이런 식으로 Croppy라이브러리를 사용하면 되겠다.

 

다음 글은 위에서 말한 거와 같이

 

라이브러리를 수정할 수 없을 때, 어떻게 하면 수정할 수 있는지..

 

그 방법은 모듈이라고 하고 그 모듈을 어떻게 활용하여

 

라이브러리를 수정할 수 있는지 포스팅을 할 예정이다.

 

끝.!

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading