본문 바로가기
Android

카메라 촬영 후 이미지뷰로 나타내기

by kldaji 2021. 7. 7.

1. Permission 추가

// AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" android:required="true"/>

 

2. Provider 추가

- 촬영한 사진의 원본 형태를 유지하기 위해 추가한다.

- $package는 사용자의 패키지를 입력한다. 

// AndroidManifest.xml
<application
        ...
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="$package.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"></meta-data>
        </provider>
        ...
</application>

 

3. xml 추가

// file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path = "Android/data/$package/files/Pictures"/>
</paths>

 

4. layout

- TouchImageView에 대한 설명은 (https://kldaji.tistory.com/3) 해당 링크를 참조하자.

- TouchImage 말고 ImageView를 사용해도 무방하다.

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

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

        <com.ortiz.touchview.TouchImageView
            android:id="@+id/touch_iv"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/camera_btn"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

5. Gradle 추가

// build.gradle (Module: $ProjectName)
dependencies {
    ...
    implementation 'gun0912.ted:tedpermission:2.2.3'
}

 

6. 함수 추가

// $fragmentName.kt
class $fragmentName : Fragment() {
    private val REQUEST_IMAGE_CAPTURE = 2	// any number
    lateinit var currentPhotoPath : String	// photo path
    private lateinit var uri: Uri	// uri

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        // binding
        val binding: FragmentNewClientBinding = DataBindingUtil.inflate(
                inflater, R.layout.fragment_new_client, container, false
        )

        // 버튼 클릭
        binding.cameraBtn.setOnClickListener {
            // 권한 설정
            settingPermission()
            
            // 카메라
            startCapture()
        }

        // Touch Image View 클릭
        binding.touchIv.setOnClickListener(View.OnClickListener {
            // uri 보내기
            sendImage(it)
        })

        return binding.root
    }

    // Request Code 확인
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode == Activity.RESULT_OK){
            if(requestCode == REQUEST_IMAGE_CAPTURE){
                // 카메라 Request
             
                val file = File(currentPhotoPath)
                
                if (Build.VERSION.SDK_INT < 28) {
                    val bitmap = MediaStore.Images.Media
                        .getBitmap(requireActivity().contentResolver, Uri.fromFile(file))
                        
                    touch_iv.setImageBitmap(bitmap)
                }
                else{
                    val decode = ImageDecoder.createSource(requireActivity().contentResolver,
                        Uri.fromFile(file))
                        
                    val bitmap = ImageDecoder.decodeBitmap(decode)
                    
                    // bitmap -> uri
                    uri = getImageUri(requireContext(), bitmap)
                    
                    // 이미지 설정
                    touch_iv.setImageBitmap(bitmap)
                }
            }
        }
    }

    // uri 보내기
    private fun sendImage(view: View){
        val intent = Intent(requireContext(), FullImageActivity::class.java).apply {
            putExtra("ImageUri", uri.toString())
        }
        startActivity(intent)
    }
    
    // bitmap -> uri
    private fun getImageUri(context: Context, inImage: Bitmap): Uri {
        val bytes = ByteArrayOutputStream()
        inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
        val path = MediaStore.Images.Media.insertImage(context.contentResolver, inImage, "Title", null)
        return Uri.parse(path)
    }

    // 권한 설정
    private fun settingPermission(){
        var permission = object : PermissionListener {
            override fun onPermissionGranted() {
                Toast.makeText(requireActivity(), "권한 허가", Toast.LENGTH_SHORT).show()
            }

            override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
                Toast.makeText(requireActivity(), "권한 거부", Toast.LENGTH_SHORT).show()
                ActivityCompat.finishAffinity(requireActivity()) // 권한 거부시 앱 종료
            }
        }

        TedPermission.with(requireContext())
            .setPermissionListener(permission)
            .setRationaleMessage("카메라 사진 권한 필요")
            .setDeniedMessage("카메라 권한 요청 거부")
            .setPermissions(
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                android.Manifest.permission.READ_EXTERNAL_STORAGE,
                android.Manifest.permission.CAMERA)
            .check()
    }

    // 카메라 Intent
    private fun startCapture(){
        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
            takePictureIntent.resolveActivity(requireActivity().packageManager)?.also {
                val photoFile: File? = try{
                    createImageFile()
                }catch(ex:IOException){
                    null
                }
                photoFile?.also{
                    val photoURI : Uri = FileProvider.getUriForFile(
                        requireContext(),
                        "com.kldaji.loanclientlist.fileprovider",
                        it
                    )
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
                }
            }
        }
    }

    // 새로운 이미지 파일 생성
    @Throws(IOException::class)
    private fun createImageFile() : File {
        val timeStamp : String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val storageDir : File? = requireActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        return File.createTempFile(
            "JPEG_${timeStamp}_",
            ".jpg",
            storageDir
        ).apply{
            currentPhotoPath = absolutePath
        }
    }
}

 

※ 촬영한 사진은 갤러리에 자동으로 저장된다.