Convert Jetpack Compose Image into BitMap Image for Sharing Purpose

3.5k Views Asked by At

I am looking for help on how to share image binary content from my PhotoApp to external Social Media apps.

I load the image from an API using Coil and display the image in a composable.

@Composable
fun PhotoDetailsScreen( photo: AstroPhoto ... ) {
         
           val context = LocalContext.current
        
            val imgUri = photo.url.toUri()
                    .buildUpon()
                    .scheme("https")
                    .build()
        
    Column ( ...
                //Image
                Image(
                        painter = rememberImagePainter(
                                data = imgUri,
                                builder = {
                                    crossfade(true)
                                    placeholder(R.drawable.loading_animation)
                                }
                        ) ... 
                //Assist Chip
                  AssistChip(onClick = { shareAstroPhoto("", context) }

Clicking on the AssistChip calls the below shareAstroPhoto() fxn that takes the uri pointing to the image file to fire an ACTION_SEND Intent

 fun shareAstroPhoto(uri:String, context: Context){
        
        val intent = Intent().apply {
    
            action = Intent.ACTION_SEND
            putExtra(Intent.EXTRA_STREAM, uri)
            type = "image/jpg"
        }
        context.startActivity(Intent.createChooser(intent, null))
    }

I intend to get a Bitmap out of my composable, save the Bitmap in my own ContentProvider or MediaStore (I know how these 2 work) and then pass the uri of the saved BitMap to Intent.EXTRA_STREAM.

Have browsed through similar cases and videos but all I find is working with XML code.

Therefore my query is how to convert Jetpack Compose Image from a composable into a Bitmap to enable sharing the file with other external apps through Android Sharesheet.

2

There are 2 best solutions below

1
FishHawk On BEST ANSWER

I'm not sure if I understand your question. If you just want to share the image, then:

Util function:

fun Context.shareImage(title: String, image: Drawable, filename: String) {
    val file = try {
        val outputFile = File(cacheDir, "$filename.png")
        val outPutStream = FileOutputStream(outputFile)
        image.toBitmap().compress(CompressFormat.PNG, 100, outPutStream)
        outPutStream.flush()
        outPutStream.close()
        outputFile
    } catch (e: Throwable) {
        return toast(e)
    }
    val uri = file.toUriCompat(this)
    val shareIntent = Intent().apply {
        action = Intent.ACTION_SEND
        type = "image/png"
        putExtra(Intent.EXTRA_STREAM, uri)
    }
    startActivity(Intent.createChooser(shareIntent, title))
}

Share image with (Coil 2.0):

val painter = rememberAsyncImagePainter(
    ImageRequest.Builder(LocalContext.current)
        .data(url)
        .build()
)
Button(
    onClick={
        val state = painter.state as? AsyncImagePainter.State.Success
        val drawable = state?.result.drawable
        context.shareImage(
            "Share image via",
             drawable,
            "filename"
        )
    }
)

Updated

Those are small helper functions, but if you want them:

fun File.toUriCompat(context: Context): Uri {
    return FileProvider.getUriForFile(context, context.packageName + ".provider", this)
}
fun Context.toast(throwable: Throwable) =
    throwable.message?.let { toast(it) }
        ?: toast(R.string.unknown_error)
fun Context.toast(message: String) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
0
Jahid Hasan On

You can get drawable using painter in jetpack compose, then use that Drawble to share..

@Composable
fun photoItem(
    photoUrl: String,
    modifier: Modifier = Modifier,
    contentScale: ContentScale = ContentScale.Fit
): Drawable? {
    val painter = rememberAsyncImagePainter(
        Builder(LocalContext.current)
            .placeholder(drawable.placeholder)
            .data(photoUrl)
            .build()
    )
    Image(
        contentScale = contentScale,
        painter = painter,
        contentDescription = null,
        modifier = modifier,
    )
    val state = painter.state as? AsyncImagePainter.State.Success
    return state?.result?.drawable
}

then cast the Drawable to BitmapDrawable