Last active
July 7, 2022 12:12
-
-
Save projectdelta6/3288c826af710f3c5bc77429beb6a6b4 to your computer and use it in GitHub Desktop.
Android kotlin Bitmap rotation correction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FYI
Log.d(this, "", e)
works because of FlexiLogger library