Skip to content

Instantly share code, notes, and snippets.

@projectdelta6
Last active July 7, 2022 12:12
Show Gist options
  • Save projectdelta6/3288c826af710f3c5bc77429beb6a6b4 to your computer and use it in GitHub Desktop.
Save projectdelta6/3288c826af710f3c5bc77429beb6a6b4 to your computer and use it in GitHub Desktop.
Android kotlin Bitmap rotation correction
//package ...
import android.content.ContentResolver
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.graphics.Matrix
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.WorkerThread
import androidx.exifinterface.media.ExifInterface
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException
object BitmapUtil {
/**
* Reads a [Bitmap] form the given [path] and attempts to read the [ExifInterface] data and
* rotate the Bitmap as necessary to display correctly.
*
* @param path The path to the Image file
*/
@Throws(IOException::class)
suspend fun fixRotation(path: String): Bitmap {
return withContext(Dispatchers.IO) {
val bitmap = BitmapFactory.decodeFile(path)
fixRotation(bitmap, path)
}
}
@WorkerThread
private fun fixRotation(bitmap: Bitmap, filePath: String): Bitmap {
try {
val exifInterface = ExifInterface(filePath)
val exifOrientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL)
val rotateBy = when(exifOrientation) {
ExifInterface.ORIENTATION_ROTATE_270 -> 270F
ExifInterface.ORIENTATION_ROTATE_180 -> 180F
ExifInterface.ORIENTATION_ROTATE_90 -> 90F
//ExifInterface.ORIENTATION_NORMAL -> 0F
else -> 0F
}
if(rotateBy != 0F) {
val matrix = Matrix()
matrix.postRotate(rotateBy)
return try {
Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
} catch(e: OutOfMemoryError) {
Log.d(this, "Ran out of memory trying to rotate photo Bitmap", e)
bitmap
}
}
} catch(e: IOException) {
Log.d(this, "Unable to get image exif orientation", e)
}
return bitmap
}
/*--- Alternative using ContentResolver. works with both 'content://' and 'file://' URIs ---*/
/**
* Reads a [Bitmap] form the given [imageUri] and attempts to read the [ExifInterface] data and
* rotate the Bitmap as necessary to display correctly.
*
* @param context to get the ContentResolver.
* @param imageUri The path to the Image file.
*/
@Throws(IOException::class)
suspend fun fixRotation(context: Context, imageUri: Uri): Bitmap {
return withContext(Dispatchers.IO) {
val bitmap = loadBitmap(context.contentResolver, imageUri)
fixRotation(context.contentResolver, bitmap, imageUri)
}
}
private fun loadBitmap(contentResolver: ContentResolver, imageUri: Uri): Bitmap {
return if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
val source = ImageDecoder.createSource(contentResolver, imageUri)
ImageDecoder.decodeBitmap(source)
} else {
MediaStore.Images.Media.getBitmap(contentResolver, imageUri)
}
}
@WorkerThread
private fun fixRotation(contentResolver: ContentResolver, bitmap: Bitmap, imageUri: Uri): Bitmap {
try {
contentResolver.openInputStream(imageUri)?.let { inputStream ->
val exifInterface = ExifInterface(inputStream)
val exifOrientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL)
Log.v(this, "exifOrientation=$exifOrientation")
val rotateBy = when(exifOrientation) {
ExifInterface.ORIENTATION_ROTATE_270 -> 270F
ExifInterface.ORIENTATION_ROTATE_180 -> 180F
ExifInterface.ORIENTATION_ROTATE_90 -> 90F
//ExifInterface.ORIENTATION_NORMAL -> 0F
else -> 0F
}
if(rotateBy != 0F) {
Log.v(this, "Rotating by $rotateBy")
val matrix = Matrix()
matrix.postRotate(rotateBy)
return try {
Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
} catch(e: OutOfMemoryError) {
Log.d(this, "Ran out of memory trying to rotate photo Bitmap", e)
bitmap
}
} else Log.v(this, "Not rotating")
}
} catch(e: IOException) {
Log.d(this, "Unable to get image exif orientation", e)
}
return bitmap
}
}
@projectdelta6
Copy link
Author

FYI Log.d(this, "", e) works because of FlexiLogger library

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment