Kotlin 카메라 & 갤러리 사진 처리하기2 + CROP (Old Camera1 Ver.)
안녕하세요 휴몬랩 쌩초보 개발자 호박입니다.
글 쓰기에 앞서 초보의 입장에서 직접 테스트해본 코드를 올리는거라 더 좋은 방법이 있을 수 도 있으며 코드는 정상적으로 작동을 해도 이 코드가 비효율적일 수도 있으니 이 점 유의해주세요~~ :)
(이런것까지 다 알면 더 이상 초보가 아니겠죠?ㅠㅠ)
이전 글 에는 카메라와 앨범을 따로 작업했었는데요, 따로 쓰는 경우도 있지만 만약 하나의 버튼으로 카메라와 갤러리를 둘 다 사용하고 싶다면 어찌해야할까요?! 네..합치면 됩니다.
그리고 추가적으로 CROP 기능까지 달아보고 끝내는걸로 하겠습니다 :)
제일 먼저 카메라와 갤러리를 함께 불러오는 것부터 해보겠습니다.
저는 카메라 여는 메소드에 갤러리를 추가해보았습니다.
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
if (takePictureIntent.resolveActivity(this.packageManager) != null) {
// 찍은 사진을 그림파일로 만들기
val photoFile: File? =
try {
createImageFile()
} catch (ex: IOException) {
Log.d("TAG", "그림파일 만드는도중 에러생김")
null
}
if (Build.VERSION.SDK_INT < 24) {
if(photoFile != null){
val photoURI = Uri.fromFile(photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) //제거해주세요
}
}
else{
// 그림파일을 성공적으로 만들었다면 startActivityForResult로 보내기
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this, "com.example.cameraonly.fileprovider", it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) //제거해주세요
}
}
< ---------------------------------------------------------------------------------------------->
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT
val chooserIntent = Intent.createChooser(intent, "골라주세요 제바알~~")
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(takePictureIntent))
startActivityForResult(chooserIntent, REQUEST_IMAGE_CAPTURE)
}
}
}
점선 아래쪽으로 갤러리열때 사용하던 메소드에서 startActivityForResult가 빠졌습니다.
그 이유는 카메라와 갤러리를 함께 사용하면서 requestCode가 2개일 필요까지 있을까요?
그래서 제일 마지막에 카메라와 함께 불러주게 되었습니다.
점선 위쪽의 startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) 을 안 지워준다면 카메라가 켜짐과 동시에 다이얼로그가 뜨게되니 꼭 지워주세요!! startActivityForResult는 맨 마지막에 한번만 불러줍시다!!
private fun openGalleryForImage() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT //추가됨
startActivityForResult(intent, REQUEST_GALLERY_TAKE) //빠졌음
}
그 다음으로 intent.action = Intent.ACTION_GET_CONTENT 를 사용하면?
아래 우측 이미지처럼 모든 갤럴리 폴더를 하나의 파일로 통합해서 보여지게 됩니다.
파일안에 갤러리, 클라우드, 포토, 스크린샷 등 다 있겠죠?
여기서 제일 중요한 코드는 바로 createChooser 입니다!
여러개의 Intent를 하나로 묶어줍니다.
바로 이 코드를 통해 카메라와 갤러리를 하나로 묶어줄 수 있는겁죠 :)
자 그럼 이제 onActivityResult로가서 또 하나로 묶어줘야겠죠?
// onActivityResult 로 이미지 설정
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode){
1 -> {
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
data?.data?.let { uri ->
image.setImageURI(uri)
}
val file = File(currentPhotoPath)
val selectedUri = Uri.fromFile(file)
try{
selectedUri?.let {
if (Build.VERSION.SDK_INT < 28) {
val bitmap = MediaStore.Images.Media
.getBitmap(contentResolver, selectedUri)
image.setImageBitmap(bitmap)
}
else{
val decode = ImageDecoder.createSource(this.contentResolver,
selectedUri)
val bitmap = ImageDecoder.decodeBitmap(decode)
image.setImageBitmap(bitmap)
}
}
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
}
}
}
아주 심플하게 원래의 코드에서 상단부분쪽에
data?.data?.let { uri -> image.setImageURI(uri) } 만 추가했습니다.
갤러리는 URI로 카메라 사진은 Bitmap으로 추가가 됩니다.
여기까지만해도 카메라와 갤러리를 둘 다 사용할 수 있게되었습니다~~
자 이제 마지막으로 CROP 기능을 한번 추가해볼까요?
CROP은 사진편집 기능으로 보통 사진 싸이즈를 조정할 때 많이 써보셨을꺼라 생각됩니다.
직접 구현할수도있지만 대부분 라이브러리를 사용해서 하던데.. 저도 라이브러리를 사용했지요 ㅠㅠ
제일먼저 build.gradle에 라이브러리를 추가하고 Sync 까지 해줍니다.
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
그런다음 카메라 또는 갤러리와 마찬가지로 CROP 메소드를 만들어줍니다.
private fun launchImageCrop(uri: Uri?){
CropImage.activity(uri).setGuidelines(CropImageView.Guidelines.ON)
.setCropShape(CropImageView.CropShape.RECTANGLE)
.start(this)
}
Manifest에 CropActivity를 추가해줍니다.
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat"/>
카메라 & 갤러리 열기 메소드에서 CROP이 가능하게끔 한 줄 추가해줍니다.
아래 코드의 3번째 줄의 intent.putExtra("crop", true) 를 꼭 추가해줍니다.
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
intent.putExtra("crop", true)
intent.action = Intent.ACTION_GET_CONTENT
마지막으로 onActivityResult에서 CROP 설정을 해줘야겠죠?
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode){
1 -> {
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
data?.data?.let { uri ->
launchImageCrop(uri)
}
// 카메라로부터 받은 데이터가 있을경우에만
val file = File(currentPhotoPath)
val selectedUri = Uri.fromFile(file)
try{
selectedUri?.let {
if (Build.VERSION.SDK_INT < 28) {
val bitmap = MediaStore.Images.Media
.getBitmap(contentResolver, selectedUri)
launchImageCrop(selectedUri)
}
else{
val decode = ImageDecoder.createSource(this.contentResolver,
selectedUri)
val bitmap = ImageDecoder.decodeBitmap(decode)
launchImageCrop(selectedUri)
}
}
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
}
CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE -> {
val result = CropImage.getActivityResult(data)
if(resultCode == Activity.RESULT_OK){
result.uri?.let {
image.setImageBitmap(result.bitmap)
image.setImageURI(result.uri)
}
}else if(resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE){
val error = result.error
Toast.makeText(this@MainActivity, error.message, Toast.LENGTH_SHORT).show()
}
}
}
}
상단에서 setImageURI 또는 setImageBitmap 부분을 launchImageCrop 으로 바꿔주었고
Crop에서는 Bitmap을 사용하지 못해서 URI 로 다 변경해서 바꿔주었습니다.
그리고나서 CROP_IMAGE_ACTIVTY_REQUEST_CODE를 다시 받아서 갤러리 또는 카메라 처리를 해주었습니다.
갤러리에서 사진을 가져와서 CROP해서 이미지뷰에 뿌려보았습니다~~짜잔!!