사진을 촬영하면 png형식으로 내부저장소에 파일을 저장하는 코드를 짜보았다.
먼저 app에서 카메라 기능과 내부저장소를 쓰기 위한 권한을 Manifest.xml에 등록해주었다.
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera"
android:required="true" />
그리고 layout과 버튼 생성
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.TestActivity">
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="업로드"
android:layout_centerHorizontal="true"
/>
<ImageView
android:id="@+id/iv"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
/>
</RelativeLayout>
파일을 저장하는 방식이 API29 버젼 이상과 이하로 두가지 버젼이 있다.
//API29이상인 경우
fun saveImageOnAboveAndroidQ(bitmap: Bitmap,context: Context) {
val fileName = "test" + System.currentTimeMillis().toString() + ".png" // 파일이름 현재시간.png
/*
* ContentValues() 객체 생성.
* ContentValues는 ContentResolver가 처리할 수 있는 값을 저장해둘 목적으로 사용된다.
* */
val contentValues = ContentValues()
contentValues.apply {
put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/ImageSave") // 경로 설정
put(MediaStore.Images.Media.DISPLAY_NAME, fileName) // 파일이름을 put해준다.
put(MediaStore.Images.Media.MIME_TYPE, "image/png")
put(MediaStore.Images.Media.IS_PENDING, 1) // 현재 is_pending 상태임을 만들어준다.
// 다른 곳에서 이 데이터를 요구하면 무시하라는 의미로, 해당 저장소를 독점할 수 있다.
}
// 이미지를 저장할 uri를 미리 설정해놓는다.
val uri =
context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
try {
if (uri != null) {
val image = context.contentResolver.openFileDescriptor(uri, "w", null)
// write 모드로 file을 open한다.
if (image != null) {
val fos = FileOutputStream(image.fileDescriptor)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
//비트맵을 FileOutputStream를 통해 compress한다.
fos.close()
contentValues.clear()
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0) // 저장소 독점을 해제한다.
context.contentResolver.update(uri, contentValues, null, null)
}
}
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
}
//API29미만인 경우
fun saveImageOnUnderAndroidQ(bitmap: Bitmap,user_num : Int,context: Context) : File {
val fileName = "$user_num.png"
val externalStorage = Environment.getExternalStorageDirectory().absolutePath
val path = "$externalStorage/passport"
val dir = File(path)
if (dir.exists().not()) {
dir.mkdirs() // 폴더 없을경우 폴더 생성
}
try {
val fileItem = File("$path/$fileName")
fileItem.createNewFile()
//0KB 파일 생성.
val fos = FileOutputStream(fileItem) // 파일 아웃풋 스트림
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
//파일 아웃풋 스트림 객체를 통해서 Bitmap 압축.
fos.close() // 파일 아웃풋 스트림 객체 close
context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(fileItem)))
// 브로드캐스트 수신자에게 파일 미디어 스캔 액션 요청. 그리고 데이터로 추가된 파일에 Uri를 넘겨준다.
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
return dir
}
위의 클래스드를 이용한 전체 코드
class TestActivity : AppCompatActivity() {
lateinit var imageView: ImageView
lateinit var imageButton: Button
companion object {
private val TAG = TestActivity::class.java.simpleName
}
val user_num = intent.getIntExtra("user_num",0)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
imageView = findViewById(R.id.iv)
imageButton = findViewById(R.id.btn)
imageButton.setOnClickListener {
var intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
resultLauncher.launch(intent)
}
}
private var resultLauncher = registerForActivityResult(
StartActivityForResult()
) { result ->
val data = result.data
val img = data?.extras?.get("data") as Bitmap
var file : File
Log.d(TAG, data.toString())
imageView.setImageBitmap(img)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//Q 버전 이상일 경우. (안드로이드 10, API 29 이상일 경우)
saveImageOnAboveAndroidQ(img, context = baseContext)
} else {
// Q 버전 이하일 경우. 저장소 권한을 얻어온다.
val writePermission = ActivityCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
if (writePermission == PackageManager.PERMISSION_GRANTED) {
file = saveImageOnUnderAndroidQ(img, user_num = user_num,baseContext)
Log.d(TAG,file.name)
} else {
val requestExternalStorageCode = 1
val permissionStorage = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
ActivityCompat.requestPermissions(
this,
permissionStorage,
requestExternalStorageCode
)
}
}
}
}
camera로 촬영한 값을 받아오는 부분의 코드도 값을 받을 수 있는 방식이 바뀌었다.
기존에 startactivityforResert메서드를 사용해 @override onActivityResult로 값을 처리했지만, 이제는 deprecated되어서
registerForActivityResult안에 startActivityForResult를 담아서 실행시킨다.
private var resultLauncher = registerForActivityResult(
StartActivityForResult()
) { result ->
val data = result.data
val img = data?.extras?.get("data") as Bitmap
var file: File
Log.d(TAG, data.toString())
imageView.setImageBitmap(img)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//Q 버전 이상일 경우. (안드로이드 10, API 29 이상일 경우)
saveImageOnAboveAndroidQ(img, context = baseContext)
} else {
// Q 버전 이하일 경우. 저장소 권한을 얻어온다.
val writePermission = ActivityCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
if (writePermission == PackageManager.PERMISSION_GRANTED) {
file = saveImageOnUnderAndroidQ(img, user_num = user_num, baseContext)
Log.d(TAG, file.name)
} else {
val requestExternalStorageCode = 1
val permissionStorage = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
ActivityCompat.requestPermissions(
this,
permissionStorage,
requestExternalStorageCode
)
}
}
}
관련 메서드들이 deprecated 된 부분이 많아 고생을 했다...
'kotlin' 카테고리의 다른 글
qr코드 생성하기 (0) | 2022.08.22 |
---|---|
canvas (0) | 2022.02.24 |
앱 만들어보기 - 1 (0) | 2022.02.19 |
SharedPreferences (0) | 2022.02.16 |
handler (0) | 2022.02.10 |