androidbitmapuriexifmediastore

Android ImagePicker/MediaStore returns rotated image


I know this question has been asked many times but there is no best-case answer to be found.

MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri)

I am retrieving the bitmap from this code, it returns a rotated bitmap. Also, the Uri which I am passing is in the form of content://com.android.providers.media.documents/document/image%3A3553763

I can't use ExifInterface because it requires a real path from uri but the URI which I have can't be converted to a real path. I already tried a few answers which some of which work up to some extent and return but they fail if I pick an image from the MIUI gallery or the System storage app.


Solution

  • I have found a workaround that solved the problem at last. So the thing is to actually create a temporary file in the cacheDir or anywhere else. After that, we can easily get the real path of this image file and can perform Exif to rotate the image.

    You may wonder why doing it the hard way when the ExifInterface supports inputStream?

    That's because ExifInterface was always returning me 0 for orientation even though the image needed rotation.

    So here is the code which helped me achieve the solution.

    fun getFilePathFromUri(context: Context, uri: Uri, uniqueName: Boolean): String =
        if (uri.path?.contains("file://") == true) {
            uri.path!!
        } else {
            getFileFromContentUri(context, uri, uniqueName).path
        }
    
    private fun getFileFromContentUri(context: Context, contentUri: Uri, uniqueName: Boolean): File {
        // Preparing Temp file name
        val fileExtension = getFileExtension(context, contentUri) ?: ""
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", getDefault()).format(Date())
        val fileName = ("temp_file_" + if (uniqueName) timeStamp else "") + ".$fileExtension"
        // Creating Temp file
        val tempFile = File(context.cacheDir, fileName)
        tempFile.createNewFile()
        // Initialize streams
        var oStream: FileOutputStream? = null
        var inputStream: InputStream? = null
    
        try {
            oStream = FileOutputStream(tempFile)
            inputStream = context.contentResolver.openInputStream(contentUri)
    
            inputStream?.let { copy(inputStream, oStream) }
            oStream.flush()
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            // Close streams
            inputStream?.close()
            oStream?.close()
        }
    
        return tempFile
    }
    
    private fun getFileExtension(context: Context, uri: Uri): String? =
        if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
            MimeTypeMap.getSingleton().getExtensionFromMimeType(context.contentResolver.getType(uri))
        } else {
            uri.path?.let { MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(File(it)).toString()) }
        }
    
    @Throws(IOException::class)
    private fun copy(source: InputStream, target: OutputStream) {
        val buf = ByteArray(8192)
        var length: Int
        while (source.read(buf).also { length = it } > 0) {
            target.write(buf, 0, length)
        }
    }
    

    After that, I just called the method getFilePathFromUri into my ExifProcessingMethod (for rotating/flipping bitmap) if needed!

    var bmp = SendCapturedImageActivity.retrieveBitmapFromFile(
                File(GetFilePathFromUri().getFilePathFromUri(applicationContext, uri, false))
            )
    

    Now this above bitmap is absolutely correct in orientation. I hope this help anyone who has this issue <3