content-uri 받아왔음content-uri 는 파일을 읽을 수 있는 uri로, UI에 이미지를 보여주는 것은 가능함. 그러나 서버 전송을 위한 이미지 File 자체를 얻을 수 없음. 대신 이미지 권한을 요구하지 않고 갤러리 접근이 가능한 장점이 있음.uri 기반 File 객체를 생성해 서버로 전송함uri 기반 생성된 File 객체는 앱의 캐시 메모리에 저장됨 (context.cachedDir)File 객체를 생성하기 전, ImageDecoder 사용해 uri에 bitmap으로 접근 > 원본 이미지 크기를 알아낼 수 있음
val source = ImageDecoder.createSource(context.contentResolver, uri)
val bitmap = ImageDecoder.decodeBitmap(source) { decoder, **info**, _ ->
// 디코더 설정
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
decoder.isMutableRequired = true
...
}
info에 크기 정보가 담겨 있음!
원본 이미지 크기를 기반으로 자체적으로 정한 한도 내의 크기가 될 수 있도록 계산해 target 설정
val source = ImageDecoder.createSource(context.contentResolver, uri)
val bitmap = ImageDecoder.decodeBitmap(source) { decoder, info, _ ->
// 디코더 설정
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
decoder.isMutableRequired = true
// 리사이징 크기 설정
**val targetSize = calculateTargetSize(info.size.width, info.size.height)
decoder.setTargetSize(targetSize.width, targetSize.height)**
}
...
private fun calculateTargetSize(
width: Int,
height: Int,
): Size {
if (width <= MAX_WIDTH && height <= MAX_HEIGHT) return Size(width, height)
val ratio = max(width.toFloat() / MAX_WIDTH, height.toFloat() / MAX_HEIGHT)
return Size((width / ratio).toInt(), (height / ratio).toInt())
}
companion object {
private const val MAX_WIDTH = 1024
private const val MAX_HEIGHT = 1024
private const val QUALITY = 80
}
상수 한도를 1024로 설정하고 (1024*1024 최대로 채워도 1MB 이하)
calculateTargetSize 원본 이미지 크기와 MAX 계산해, 원본 이미지의 비율 유지하며 한도 내 크기가 되도록 목표 사이즈 계산
decoder.setTargetSize 설정한 크기로 이미지 압축할 수 있도록 디코더에 targetSize 옵션 넣어줌
리사이징된 이미지로 File 객체 생성
// bitmap을 리사이징(압축)한 jpeg byteArray 생성
val compressedImage = ByteArrayOutputStream().use { stream ->
bitmap.compress(Bitmap.CompressFormat.JPEG, QUALITY, stream)
bitmap.recycle()
stream.toByteArray()
}
// 임시 파일 객체 생성
val tempFile = File(
dir,
"${UUID.randomUUID()}.$IMAGE_EXTENSION",
)
// 파일 객채에 리사이징 byteArray 덮어씌워 최종 이미지 파일 생성
tempFile.outputStream().use { stream ->
stream.write(compressedImage)
}
return tempFile
이미지 파일은 JPEG로 생성하며, quality 값은 80 고정
서버 업로드 완료된다면 더 이상 파일 객체는 필요하지 않음. 따라서 삭제 로직 제공
fun clearDirectory() {
val directory = getDirectory()
directory.listFiles()?.forEach { it.delete() }
}
FileLocalDataSource 추가
위 설명한 이미지 최적화 로직은 FileLocalDataSource 가 제공합니다.