From 4d3259704803bffd8b7e33ee64aed60943d4aa80 Mon Sep 17 00:00:00 2001 From: Viktor Varenik Date: Wed, 10 Jun 2026 22:59:59 +0300 Subject: [PATCH 1/2] fix(edit): rotated avatars after adjuster --- .../java/friendly/android/AvatarAdjuster.kt | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/friendly/android/AvatarAdjuster.kt b/app/src/main/java/friendly/android/AvatarAdjuster.kt index 5ef863b..1143f24 100644 --- a/app/src/main/java/friendly/android/AvatarAdjuster.kt +++ b/app/src/main/java/friendly/android/AvatarAdjuster.kt @@ -3,6 +3,8 @@ package friendly.android import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.graphics.Matrix +import androidx.exifinterface.media.ExifInterface import android.net.Uri import androidx.core.graphics.scale import java.io.ByteArrayInputStream @@ -31,11 +33,19 @@ class AvatarAdjuster( uri: Uri, inputStream: InputStream, ): Pair { + /* Extract EXIF metadata to fix orientation issues. + * Some device cameras save images rotated sideways alongside an EXIF orientation flag + * rather than encoding the physical pixel array right-side up. + */ + val rotationDegrees = getRotationDegrees(uri) + val bitmap = BitmapFactory.decodeStream(inputStream) ?: error("Failed to decode image") + val rotatedBitmap = rotateBitmapIfNeeded(bitmap, rotationDegrees) + val croppedDimension = minOf(bitmap.width, bitmap.height) val croppedBitmap = Bitmap - .createBitmap(bitmap, 0, 0, croppedDimension, croppedDimension) + .createBitmap(rotatedBitmap, 0, 0, croppedDimension, croppedDimension) val scaledBitmap = croppedBitmap .scale(NewAvatarDimension, NewAvatarDimension) @@ -58,4 +68,22 @@ class AvatarAdjuster( second = byteArray.size.toLong(), ) } + + private fun getRotationDegrees(uri: Uri): Int { + return contentResolver.openInputStream(uri)?.use { stream -> + val exif = ExifInterface(stream) + when (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) { + ExifInterface.ORIENTATION_ROTATE_90 -> 90 + ExifInterface.ORIENTATION_ROTATE_180 -> 180 + ExifInterface.ORIENTATION_ROTATE_270 -> 270 + else -> 0 + } + } ?: 0 + } + + private fun rotateBitmapIfNeeded(bitmap: Bitmap, degrees: Int): Bitmap { + if (degrees == 0) return bitmap + val matrix = Matrix().apply { postRotate(degrees.toFloat()) } + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) + } } From fb69ff61397622a14299b9ece549cfda732ee81c Mon Sep 17 00:00:00 2001 From: demndevel Date: Wed, 10 Jun 2026 23:32:46 +0300 Subject: [PATCH 2/2] lint: fix formatting issues --- .../java/friendly/android/AvatarAdjuster.kt | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/friendly/android/AvatarAdjuster.kt b/app/src/main/java/friendly/android/AvatarAdjuster.kt index 1143f24..8187615 100644 --- a/app/src/main/java/friendly/android/AvatarAdjuster.kt +++ b/app/src/main/java/friendly/android/AvatarAdjuster.kt @@ -4,9 +4,9 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Matrix -import androidx.exifinterface.media.ExifInterface import android.net.Uri import androidx.core.graphics.scale +import androidx.exifinterface.media.ExifInterface import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream @@ -45,7 +45,13 @@ class AvatarAdjuster( val croppedDimension = minOf(bitmap.width, bitmap.height) val croppedBitmap = Bitmap - .createBitmap(rotatedBitmap, 0, 0, croppedDimension, croppedDimension) + .createBitmap( + rotatedBitmap, + 0, + 0, + croppedDimension, + croppedDimension, + ) val scaledBitmap = croppedBitmap .scale(NewAvatarDimension, NewAvatarDimension) @@ -69,21 +75,33 @@ class AvatarAdjuster( ) } - private fun getRotationDegrees(uri: Uri): Int { - return contentResolver.openInputStream(uri)?.use { stream -> + private fun getRotationDegrees(uri: Uri): Int = + contentResolver.openInputStream(uri)?.use { stream -> val exif = ExifInterface(stream) - when (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) { + when ( + exif.getAttributeInt( + ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL, + ) + ) { ExifInterface.ORIENTATION_ROTATE_90 -> 90 ExifInterface.ORIENTATION_ROTATE_180 -> 180 ExifInterface.ORIENTATION_ROTATE_270 -> 270 else -> 0 } } ?: 0 - } private fun rotateBitmapIfNeeded(bitmap: Bitmap, degrees: Int): Bitmap { if (degrees == 0) return bitmap val matrix = Matrix().apply { postRotate(degrees.toFloat()) } - return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) + return Bitmap.createBitmap( + bitmap, + 0, + 0, + bitmap.width, + bitmap.height, + matrix, + true, + ) } }