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
}
}
}
※ 촬영한 사진은 갤러리에 자동으로 저장된다.
'Android' 카테고리의 다른 글
Navigation Up Button (0) | 2021.07.08 |
---|---|
Back Button Click Listener (0) | 2021.07.08 |
카메라 앨범으로부터 사진 가져오기 (0) | 2021.07.06 |
[Open Source] 이미지 줌 인/아웃 - TouchImageView (0) | 2021.07.06 |
[Open Source] 이미지 줌 인/아웃 - PhotoView (0) | 2021.07.05 |