How to get the absolute path of the image file?

1.4k Views Asked by At

I am creating a drawing app and have added a save image functionality which will store my bitmap in the Pictures folder of external storage using MediaStore. Now I want to add a functionality of sharing image and for that absolute path of the saved image is needed. I am confused how to get the absolute path of the image.

P.S.- I have used the code of Philipp Lackner for saving image in external storage.

    private fun saveImage(mbitmap:Bitmap?):Boolean/*String*/{ // to run code in Background Thread
      
        val displayName = "Drawing" + System.currentTimeMillis() / 1000

        val imageCollection = sdkVersion29andUp {
            MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
        } ?: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        val contentValues = ContentValues().apply {
            put(MediaStore.Images.Media.DISPLAY_NAME, "$displayName.jpeg")
            put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
            put(MediaStore.Images.Media.WIDTH, mbitmap!!.width)
            put(MediaStore.Images.Media.HEIGHT, mbitmap!!.height)
        }

        return try{
            contentResolver.insert(imageCollection,contentValues)?.also { uri ->
                contentResolver.openOutputStream(uri).use { outputstream->
                    if(!mbitmap!!.compress(Bitmap.CompressFormat.JPEG,95,outputstream))
                        throw IOException("Couldn't save Bitmap")
                }
            }?: throw IOException("Couldn't create MediaStore entry")
            true
        }catch (e:IOException){
            e.printStackTrace()
            false
        }  

Below is the code for Share Image functionality.Here savedImagePath is the global variable for storing the absolute path of the saved Image.

 private fun shareImage(){
    MediaScannerConnection.scanFile(this,arrayOf(savedImagePath!!),null){
        path,uri-> val sharedIntent=Intent()
        sharedIntent.action=Intent.ACTION_SEND
        sharedIntent.putExtra(Intent.EXTRA_STREAM,uri)
        sharedIntent.setType("image/jpeg")

        startActivity(
            Intent.createChooser(sharedIntent,"Share")
        )

    }
}
1

There are 1 best solutions below

0
Raz Leshem On

You can get a file path from a content uri using this:

/**
 * Parses out the real local file path from the file content URI
 */
fun getUriRealPath(context: Context, uri: Uri): String? {
    var filePath: String? = ""
    if (isContentUri(uri)) {
        filePath = if (isGooglePhotoDoc(uri.authority)) {
            uri.lastPathSegment
        } else {
            getFileRealPath(context.contentResolver, uri, null)
        }
    } else if (isFileUri(uri)) {
        filePath = uri.path
    } else if (DocumentsContract.isDocumentUri(context, uri)) {
        // Get uri related document id
        val documentId = DocumentsContract.getDocumentId(uri)
        // Get uri authority
        val uriAuthority = uri.authority
        if (isMediaDoc(uriAuthority)) {
            val idArr = documentId.split(":".toRegex()).toTypedArray()
            if (idArr.size == 2) {
                // First item is document type
                val docType = idArr[0]
                // Second item is document real id
                val realDocId = idArr[1]
                // Get content uri by document type
                var mediaContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                when (docType) {
                    "image" -> {
                        mediaContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    }
                    "video" -> {
                        mediaContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    }
                }
                // Get where clause with real document id.
                val whereClause = MediaStore.Images.Media._ID + " = " + realDocId
                filePath = getFileRealPath(
                    context.contentResolver,
                    mediaContentUri,
                    whereClause
                )
            }
        } else if (isDownloadDoc(uriAuthority)) {
            // Build download uri.
            val downloadUri = Uri.parse("content://downloads/public_downloads")
            // Append download document id at uri end.
            val downloadUriAppendId =
                ContentUris.withAppendedId(downloadUri, java.lang.Long.valueOf(documentId))
            filePath = getFileRealPath(
                context.contentResolver,
                downloadUriAppendId,
                null
            )
        } else if (isExternalStoreDoc(uriAuthority)) {
            val idArr = documentId.split(":".toRegex()).toTypedArray()
            if (idArr.size == 2) {
                val type = idArr[0]
                val realDocId = idArr[1]
                if ("primary".equals(type, ignoreCase = true)) {
                    filePath = Environment.getExternalStorageDirectory()
                        .toString() + "/" + realDocId
                }
            }
        }
    }
    return filePath
}

/**
 * Checks whether this uri is a content uri or not.
 * Content uri like content://media/external/images/media/1302716
 */
private fun isContentUri(uri: Uri): Boolean {
    var isContentUri = false
    val uriSchema = uri.scheme
    if ("content".equals(uriSchema, ignoreCase = true)) {
        isContentUri = true
    }
    return isContentUri
}

/**
 * Check whether this uri is a file uri or not.
 * File uri like file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg
 */
private fun isFileUri(uri: Uri): Boolean {
    var isFileUri = false
    val uriSchema = uri.scheme
    if ("file".equals(uriSchema, ignoreCase = true)) {
        isFileUri = true
    }
    return isFileUri
}

/**
 * Checks whether this document is provided by ExternalStorageProvider.
 * @return true if the file is saved in external storage, false otherwise
 */
private fun isExternalStoreDoc(uriAuthority: String?): Boolean {
    return "com.android.externalstorage.documents" == uriAuthority
}

/**
 * Checks whether this document is provided by DownloadsProvider.
 * @return true if this file is a download file, false otherwise
 */
private fun isDownloadDoc(uriAuthority: String?): Boolean {
    return "com.android.providers.downloads.documents" == uriAuthority
}

/**
 * Checks if MediaProvider provided this document
 * @return true if this image is created in android media app, false otherwise
 */
private fun isMediaDoc(uriAuthority: String?): Boolean {
    return "com.android.providers.media.documents" == uriAuthority
}

/**
 * Checks whether google photos provided this document, if true means this image is created in google photos app
 */
private fun isGooglePhotoDoc(uriAuthority: String?): Boolean {
    return "com.google.android.apps.photos.content" == uriAuthority
}

/**
 * Return uri represented document file real local path
 */
private fun getFileRealPath(
    contentResolver: ContentResolver,
    uri: Uri,
    whereClause: String?
): String {
    var filePath = ""
    // Query the uri with condition
    val cursor = contentResolver.query(uri, null, whereClause, null, null)
    if (cursor != null) { // if cursor is not null
        if (cursor.moveToFirst()) {
            // Get columns name by uri type.
            var columnName = MediaStore.Images.Media.DATA
            when (uri) {
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI -> {
                    columnName = MediaStore.Images.Media.DATA
                }
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI -> {
                    columnName = MediaStore.Video.Media.DATA
                }
            }
            // Get column index.
            val filePathColumnIndex = cursor.getColumnIndex(columnName)
            // Get column value which is the uri related file local path.
            filePath = cursor.getString(filePathColumnIndex)
        }
        cursor.close()
    }
    return filePath
}

If you want a shorter version you can use only: getFileRealPath() and that will give you the uri file path in case the uri is a content uri which is the case in the code you provided.

P.S: the DATA column may be shown as deprecated, but it is still available to read from.