camera intent로 카메라를 구현하는 경우, 화질이 매우 낮다.
(촬영하고 난 썸네일 이미지를 그대로 사용해서 그렇다고 함)
그래서 촬영한 이미지를 저장하고, 그 저장한 이미지를 불러오는 식으로 카메라의 화질을 높일 수 있다.
또한, 촬영한 이미지가 회전돼서 출력되는 현상도 있는데,
이미지를 돌아간 만큼 다시 회전시켜주는 기능도 같이 구현할 것이다.
이 사진을 서버에 업로드하는 경우, 찍힌 파일 그대로 업로드하면 용량이 너무 커서
multipart로 업로드할때 시간이 너무 오래걸리는데 (5초정도 걸린거같다.)
사진을 압축해서 보내는 것도 추가했다.
AndroidManifest.xml
1
2
3
4
5
6
7
8
9
|
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.food_classification.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
|
cs |
파일 공유 방식으로 이미지를 로드할 것이기 때문에 FileProvider를 사용한다.
file_paths는 xml폴더 안에 새로 만들어서 작성한다.
xml/file_paths.xml
1
2
3
4
5
6
|
<?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/com.example.food_classification/files/Pictures" />
</paths>
|
cs |
저장할 파일의 경로를 설정해준다.
MainActivity.kt
저번에 했던 코드를 수정해서 진행한다.
1
2
3
4
5
6
7
8
9
10
11
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 카메라 실행 부분
if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
dispatchTakePictureIntent()
//val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
//startActivityForResult(cameraIntent, 1)
} else {
Log.d("test", "권한 설정 요청")
ActivityCompat.requestPermissions(this@MainActivity, arrayOf<String?>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
}
}
|
cs |
dispatchTakePictureIntent()가 새로 생겼는데,
이 메서드에서 사진을 찍고 저장하는 기능을 구현한다.
dispatchTakePictureIntent()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(packageManager) != null) {
// Create the File where the photo should go
var photoFile: File? = null
try {
photoFile = createImageFile()
}
catch (ex: IOException) { // 파일을 만드는데 오류가 발생한 경우
}
// Continue only if the File was successfully created
if (photoFile != null) {
val photoURI: Uri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider",
photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
}
}
}
|
cs |
코드는 Android developers에서 참고했다.
이제 onActivityResult에서 찍힌 파일을 bitmap으로 불러온 뒤에,
사진을 회전시키고 압축하는 기능을 구현한다.
onActivityResult
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
//findViewById(R.id.result_image).setImageURI(photoUri);
try {
when (requestCode) {
REQUEST_TAKE_PHOTO -> {
if (resultCode === Activity.RESULT_OK) {
val file = File(mCurrentPhotoPath)
myBitmap = MediaStore.Images.Media
.getBitmap(contentResolver, Uri.fromFile(file))
if (myBitmap != null) {
val exif = mCurrentPhotoPath?.let { ExifInterface(it) }
val exifOrientation: Int = exif!!.getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val exifDegree = exifOrientationToDegrees(exifOrientation)
myBitmap = rotate(myBitmap, exifDegree)
}
else {
Log.d("myBitmap null", "null")
}
}
}
}
} catch (error: Exception) {
error.printStackTrace()
}
}
|
cs |
exifOrientationToDegrees는 ExifInterface라는 사진의 정보를 담고 있는 객체를 통해 사진의 정보를 받아와
사진에 대한 각도가 얼마인지 반환하는 함수이다.
rotate 함수가 사진을 회전하고, 압축하는 함수이다.
exifOrientationToDegrees
1
2
3
4
5
6
7
8
9
10
|
fun exifOrientationToDegrees(exifOrientation: Int): Int {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270
}
return 0
}
|
cs |
ExifInterface를 사용한다.
rotate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
fun rotate(bitmap: Bitmap?, degrees: Int): Bitmap? { // 이미지 회전 및 이미지 사이즈 압축
var bitmap = bitmap
if (degrees != 0 && bitmap != null) {
val m = Matrix()
m.setRotate(degrees.toFloat(), bitmap.width.toFloat() / 2,
bitmap.height.toFloat() / 2)
try {
val converted = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.width, bitmap.height, m, true)
if (bitmap != converted) {
bitmap.recycle()
bitmap = converted
val options = BitmapFactory.Options()
options.inSampleSize = 4
bitmap = Bitmap.createScaledBitmap(bitmap, 1280, 1280, true) // 이미지 사이즈 줄이기
}
} catch (ex: OutOfMemoryError) {
// 메모리가 부족하여 회전을 시키지 못할 경우 그냥 원본을 반환합니다.
}
}
return bitmap
}
|
cs |
끝.
이제 해당 bitmap을 사용해 imageView에 출력해도 되고,
bitmap으로 이미지의 uri를 찾아 서버로 보낼 수도 있다.
'개발 > 안드로이드' 카테고리의 다른 글
[Kotlin] 안드로이드 RecyclerView 누른 item만 색깔 바뀌게 하기 (0) | 2020.10.22 |
---|---|
[Kotlin] 안드로이드 다른 class에서 UI 그리기 (0) | 2020.10.16 |
[Kotlin] 안드로이드 bitmap으로부터 uri가져온 뒤, filepath 찾기 (3) | 2020.10.14 |
[Kotlin] 안드로이드 카메라 구현 예제 (0) | 2020.10.14 |
[Java] 안드로이드 OkHttp3를 사용한 서버로 파일 업로드하기 (4) | 2020.09.07 |