2026/03/19

오늘의 이야기

오늘은 이미지 자르기 (cropper)에 대한 이야기를 적어 보겠습니다. 해당 라이브러리의 출처는 다음과 같습니다. 


https://github.com/CanHub/Android-Image-Cropper



 


GitHub - CanHub/Android-Image-Cropper: Image Cropping Library for Android, optimised for Camera / Gallery.


Image Cropping Library for Android, optimised for Camera / Gallery. - GitHub - CanHub/Android-Image-Cropper: Image Cropping Library for Android, optimised for Camera / Gallery.


github.com




2021년쯤에 이 방법을  java 코드에 연결해 보았던 기억이 있으나 그때 사용 되었던 github는 이제 더 이상 관리가 되지 않고 있었고 그걸 fork 해 계속 유지하고 있는 코드를 발견하게 되었습니다. 


 


카메라 또는 갤러리에서 가져오는 이미지는 전체가 필요할 수 도 있지만,  문자 인식 등에 활용 하기 위해서는 필요한 부분만을 가져와야 하는 경우 등이 있습니다. 


 


이 떄 유용하게 활용될 수 있습니다.   


 


이미지 자르기 (cropper 기능)을 활용하는 방법은 먼저 gradle 파일에 다음과 같이 기술합니다. 


// image cropper
implementation("com.vanniktech:android-image-cropper:4.5.0")

현재는 4.5.0 이 마지막 버전입니다. 이 글을 보시는 시점에는 다시 확인해 보시는 것이 좋을 듯합니다. 


 


이제 코드 구현을 해 보겠습니다.  먼저 callback 을 구현합니다.  호출된 이후에 결과가 돌아오면 그걸 현재는 viewModel에 있는 변수에 저장해 볼 예정입니다.


private val customCropImage = registerForActivityResult(CropImageContract()) {
if (it !is CropImage.CancelledResult) {
dataViewModel.textRecognitionUri.value = it.uriContent
Log.e("", "cropImage = ${it.uriContent}")
}
}

 


이 응답을 받기 위해서 아래와 같이 호출을 시도합니다. 


 


private fun startCameraWithoutUri(includeCamera: Boolean, includeGallery: Boolean) {
customCropImage.launch(
CropImageContractOptions(
uri = null,
cropImageOptions = CropImageOptions(
imageSourceIncludeCamera = includeCamera,
imageSourceIncludeGallery = includeGallery,
),
),
)
}

첫 번째 인수는 카메라 선택 가능 여부, 두 번째는 갤러리 선택 가능 여부입니다.  저는 두 개다 true로 실행을 했습니다. 


 


선택하기 화면



 


이렇게 activity가 실행이 되게 되는 이때 꼭 해야 할 것은 다음과 같이 manifest.xml 파일에 해당 activite을 추가해 주어야 합니다. 


 


<activity
android:name="com.canhub.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />

또한 갤러리와 카메라  선택 하는 문구가 영문으로 표출되는 것이 기본 값인데, 그걸 한글로 표시 되게 하기 위해서 


values / strings.xml 에 다음과 같이 추가했습니다. 


 


 


<string name="ic_rotate_left_24">반시계 회전</string>
<string name="ic_rotate_right_24">회전</string>
<string name="crop_image_menu_crop">자르기</string>
<string name="ic_flip_24">반전</string>
<string name="ic_flip_24_horizontally">좌우반전</string>
<string name="ic_flip_24_vertically">상하반전</string>
<string name="pick_image_chooser_title">이미지 선택</string>
<string name="pick_image_camera">카메라로 촬영하기</string>
<string name="pick_image_gallery">저장된 이미지 읽어오기</string>

이런 문구들이 들어가므로 해서 화면에 한글로 표시가 진행됩니다. 


 


이제 실행하고 그 결과를 보겠습니다.


이미지 선택 전 후 모습



 


당초에는 전체 촬영된 이미지가 보였으나,   안내선을 이용하여 조정한 후 화면 상단의 자르기 버튼을 선택하면 오른쪽의 그림과 같이 선택된 부분만 이미지로 전달을 받아 보여 줄 수 있었습니다. 


 


위에서 선택된 결과를 viewModel에 있는 변수에 받았으니 그걸 그대로 Image에 넣어주는 것으로 그 코드를 정리가 되었습니다.  그 부분은 다음과 같습니다. 


dataViewModel.textRecognitionUri.value?.let {
val source = ImageDecoder
.createSource(context.contentResolver, it)
bitmapPic.value = ImageDecoder.decodeBitmap(source)
bitmapPic.value?.let { btm ->
val quality = 20
val baos = ByteArrayOutputStream()
btm.compress(
Bitmap.CompressFormat.WEBP_LOSSLESS,
quality,
baos
)
val b: ByteArray = baos.toByteArray()
productImage = Base64.encodeToString(b, Base64.DEFAULT)

Image(
bitmap = btm.asImageBitmap(),
contentDescription = "profile",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.clip(shape = RoundedCornerShape(16.dp))
.width(screenWidth * .8f)
.height(300.dp)
)
}
}

uri로 받아온 응답을 활용해서 이미지로 변환해 바로 보여주는 방식으로 말입니다.  Quality는 20으로 조정을 하기는 했으나, 그렇게 차이가 나는 것을 느낄 수 없었습니다. 


 


이제 이미지 자르기는 그렇게 어렵지 않게 구현을 해 볼 수 있을 것 같습니다.


 





댓글 없음:

댓글 쓰기

오늘의 이야기

https://github.com/hi-manshu/Kalendar   GitHub - hi-manshu/Kalendar: Kalendar is a powerful and customizable calendar library for Android ap...