Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion app/src/main/java/friendly/android/AvatarAdjuster.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package friendly.android
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
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
Expand All @@ -31,11 +33,25 @@ class AvatarAdjuster(
uri: Uri,
inputStream: InputStream,
): Pair<InputStream, Long> {
/* 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)

Expand All @@ -58,4 +74,34 @@ class AvatarAdjuster(
second = byteArray.size.toLong(),
)
}

private fun getRotationDegrees(uri: Uri): Int =
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,
)
}
}
Loading