본문 바로가기
카테고리 없음

Kotlin 카메라 & 갤러리 사진 처리하기2 + CROP (Old Camera1 Ver.)

by 알 수 없는 사용자 2020. 6. 12.

안녕하세요 휴몬랩 쌩초보 개발자 호박입니다.
글 쓰기에 앞서 초보의 입장에서 직접 테스트해본 코드를 올리는거라 더 좋은 방법이 있을 수 도 있으며 코드는 정상적으로 작동을 해도 이 코드가 비효율적일 수도 있으니 이 점 유의해주세요~~ :)
(이런것까지 다 알면 더 이상 초보가 아니겠죠?ㅠㅠ)

 

이전 글 에는 카메라와 앨범을 따로 작업했었는데요, 따로 쓰는 경우도 있지만 만약 하나의 버튼으로 카메라와 갤러리를 둘 다 사용하고 싶다면 어찌해야할까요?! 네..합치면 됩니다.
그리고 추가적으로 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해서 이미지뷰에 뿌려보았습니다~~짜잔!!

댓글