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:
2026-02-20 02:45:00 +05:00
parent 5cf8b2866f
commit 88e2084f8b
26 changed files with 943 additions and 464 deletions

View File

@@ -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