기본 카메라를 불러와서 사진촬영 및 사진첩에 접근해서 사진을 불러오는걸 목표로 함
카메라는 권한접근을 요청하고 승인이 완료되었을 때 실행이 가능하므로 먼저 권한접근을 편리하게 구성하기 위한 라이브러리를 build.gradle 에 추가한다. - tedpermission
dependencies {
...
//tedpermission
implementation 'gun0912.ted:tedpermission:2.2.3'//권한 요청을 위한 팝업을 쉽게 구성하기 위해
}
권한접근 요청을 위한 manifests 설정
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="true"/>
사진촬영 및 사진첩에서 사진을 불러오기 예제 - class
class AddMemoryActivity : AppCompatActivity(),View.OnClickListener {
val REQUEST_IMAGE_CAPTURE = 1 //카메라 사진 촬영 요청 코드 *임의로 값 입력
lateinit var currentPhotoPath : String //문자열 형태의 사진 경로값 (초기값을 null로 시작하고 싶을 때 - lateinti var)
val REQUEST_IMAGE_PICK = 10
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_memory)
setPermission()
}
//테드 퍼미션 설정 (카메라 사용시 권한 설정 팝업을 쉽게 구현하기 위해 사용)
private fun setPermission() {
val permission = object : PermissionListener{
override fun onPermissionGranted() {//설정해 놓은 위험권한(카메라 접근 등)이 허용된 경우 이곳을 실행
Toast.makeText(this@AddMemoryActivity,"요청하신 권한이 허용되었습니다.",Toast.LENGTH_SHORT).show()
}
override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {//설정해 놓은 위험권한이 거부된 경우 이곳을 실행
Toast.makeText(this@AddMemoryActivity,"요청하신 권한이 거부되었습니다.",Toast.LENGTH_SHORT).show()
}
}
TedPermission.with(this)
.setPermissionListener(permission)
.setRationaleMessage("카메라 앱을 사용하시려면 권한을 허용해주세요.")
.setDeniedMessage("권한을 거부하셨습니다.앱을 사용하시려면 [앱 설정]-[권한] 항목에서 권한을 허용해주세요.")
.setPermissions(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA)
.check()
}
override fun onClick(v: View?) {
when(v!!.id){
R.id.btn_camera->{
takeCapture()
}
R.id.btn_photo->{
getPhotoFromMyGallary()
}
}
}
//사진첩에서 사진 불러오기
private fun getPhotoFromMyGallary() {
Intent(Intent.ACTION_PICK).apply{
type = "image/*"
startActivityForResult(this,REQUEST_IMAGE_PICK)
}
}
//기본 카메라 앱을 사용해서 사진 촬영
private fun takeCapture() {
//기본 카메라 앱 실행
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
takePictureIntent.resolveActivity(packageManager)?.also {
val photoFile : File? = try{
createImageFile()
}catch (e:Exception){
null
}
photoFile?.also {
val photoURI : Uri = FileProvider.getUriForFile(
this,
"com.gmail.moontae0317.memory.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
}
}
//이미지 파일 생성
private fun createImageFile(): File {
val timestamp : String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir : File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile("JPEG_${timestamp}_",".jpeg",storageDir).apply {
currentPhotoPath = absolutePath
}
}
//startActivityForResult를 통해서 기본 카메라 앱으로 부터 받아온 결과값
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
val bitmap : Bitmap
val file = File(currentPhotoPath)
if(Build.VERSION.SDK_INT < 28){//안드로이드 9.0 보다 버전이 낮을 경우
bitmap = MediaStore.Images.Media.getBitmap(contentResolver,Uri.fromFile(file))
img_photo.setImageBitmap(bitmap)
}else{//안드로이드 9.0 보다 버전이 높을 경우
val decode = ImageDecoder.createSource(
this.contentResolver,
Uri.fromFile(file)
)
bitmap = ImageDecoder.decodeBitmap(decode)
img_photo.setImageBitmap(bitmap)
}
savePhoto(bitmap)
}
if(requestCode == REQUEST_IMAGE_PICK && resultCode == Activity.RESULT_OK){
img_photo.setImageURI(data?.data)
}
}
//갤러리에 저장
private fun savePhoto(bitmap: Bitmap) {
//사진 폴더에 저장하기 위한 경로 선언
val folderPath = Environment.getExternalStorageDirectory().absolutePath + "/Pictures/"
val timestamp : String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val fileName = "${timestamp}.jpeg"
val folder = File(folderPath)
if(!folder.isDirectory){//해당 경로에 폴더가 존재하지
folder.mkdir() // make directory의 줄임말로 해당경로에 폴더 자동으로
}
//실제적인 저장 처리
val out = FileOutputStream(folderPath + fileName)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
Toast.makeText(this,"사진이 앨범에 저장되었습니다.",Toast.LENGTH_SHORT).show()
}
}
사진촬영 및 사진첩에서 사진을 불러오기 예제 - layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.AddMemoryActivity">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="120dp"
android:layout_marginLeft="120dp"
android:layout_marginTop="28dp"
android:text="메모리 추가할 수 있게 파는 뷰"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_camera"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="368dp"
android:onClick="onClick"
android:text="카메라촬영"
app:layout_constraintBottom_toTopOf="@+id/btn_photo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4"
app:layout_constraintVertical_bias="0.895" />
<Button
android:id="@+id/btn_photo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="앨범에서 선택"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/img_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/btn_camera"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4"
android:src="@drawable/ic_launcher_background" />
</androidx.constraintlayout.widget.ConstraintLayout>