Refactor image handling and decoding logic
- Introduced a maximum bitmap decode dimension to prevent excessive memory usage. - Enhanced base64 to bitmap conversion by extracting payload and applying EXIF orientation. - Improved error handling for image downloads and decoding processes. - Simplified media picker and chat input components to manage keyboard visibility more effectively. - Updated color selection grid to adaptively adjust based on available width. - Added safety checks for notifications and call actions in profile screens. - Optimized bitmap decoding in uriToBase64Image to handle large images more efficiently.
This commit is contained in:
@@ -11,7 +11,6 @@ import com.vanniktech.blurhash.BlurHash
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
|
||||
private const val TAG = "MediaUtils"
|
||||
|
||||
@@ -36,22 +35,34 @@ object MediaUtils {
|
||||
*/
|
||||
suspend fun uriToBase64Image(context: Context, uri: Uri): String? = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
|
||||
// Читаем EXIF ориентацию
|
||||
val orientation = getExifOrientation(context, uri)
|
||||
|
||||
// Открываем InputStream
|
||||
val inputStream: InputStream = context.contentResolver.openInputStream(uri)
|
||||
?: return@withContext null
|
||||
|
||||
// Декодируем изображение
|
||||
var bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream.close()
|
||||
|
||||
if (bitmap == null) {
|
||||
|
||||
val boundsOptions =
|
||||
BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
context.contentResolver.openInputStream(uri)?.use { inputStream ->
|
||||
BitmapFactory.decodeStream(inputStream, null, boundsOptions)
|
||||
} ?: return@withContext null
|
||||
|
||||
if (boundsOptions.outWidth <= 0 || boundsOptions.outHeight <= 0) {
|
||||
return@withContext null
|
||||
}
|
||||
|
||||
|
||||
val decodeOptions =
|
||||
BitmapFactory.Options().apply {
|
||||
inSampleSize =
|
||||
calculateInSampleSize(
|
||||
boundsOptions.outWidth,
|
||||
boundsOptions.outHeight,
|
||||
MAX_IMAGE_SIZE * 2
|
||||
)
|
||||
inPreferredConfig = Bitmap.Config.ARGB_8888
|
||||
}
|
||||
var bitmap =
|
||||
context.contentResolver.openInputStream(uri)?.use { inputStream ->
|
||||
BitmapFactory.decodeStream(inputStream, null, decodeOptions)
|
||||
} ?: return@withContext null
|
||||
|
||||
// Применяем EXIF ориентацию (поворот/отражение)
|
||||
bitmap = applyExifOrientation(bitmap, orientation)
|
||||
|
||||
@@ -74,6 +85,8 @@ object MediaUtils {
|
||||
base64
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
} catch (e: OutOfMemoryError) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +249,14 @@ object MediaUtils {
|
||||
|
||||
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
|
||||
}
|
||||
|
||||
private fun calculateInSampleSize(width: Int, height: Int, maxDimension: Int): Int {
|
||||
var sample = 1
|
||||
while ((width / (sample * 2)) >= maxDimension || (height / (sample * 2)) >= maxDimension) {
|
||||
sample *= 2
|
||||
}
|
||||
return sample.coerceAtLeast(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Конвертировать Bitmap в Base64 PNG
|
||||
|
||||
Reference in New Issue
Block a user