1

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.

Tonnie
  • 4,865
  • 3
  • 34
  • 50
  • 1
    If you want to get screenshot of a Composable you can check [this thread](https://stackoverflow.com/questions/63861095/jetpack-compose-take-screenshot-of-composable-function). You need take into consideration on Oreo and obove you need to use PixelCopy Also i made a library that screenshots Comosables, you can check it here https://github.com/SmartToolFactory/Compose-Screenshot – Thracian Jul 06 '22 at 17:55
  • 1
    This article might help you: https://medium.com/@vipulthawre/how-to-share-composable-as-bitmap-e207c2f299d4 – nglauber Jul 06 '22 at 19:06
  • 1
    @nglauber you need to consider devices with Oreo and above which is not mentioned in that article. If you don't you will get exception in this link. https://stackoverflow.com/questions/58314397/java-lang-illegalstateexception-software-rendering-doesnt-support-hardware-bit – Thracian Jul 06 '22 at 19:18
  • 1
    https://github.com/PatilShreyas/Capturable and https://github.com/KaustubhPatange/kapture are two other implementations of "capture a composable to a bitmap". – CommonsWare Jul 06 '22 at 19:56

2 Answers2

2

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()
}
FishHawk
  • 414
  • 4
  • 11
  • This exactly what I am trying to accomplish. Do you mind posting content for the `toUriCompat(this)` and `toast(e)' functions for my reference. Thanks Man – Tonnie Jul 08 '22 at 05:54
0

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

Jahid Hasan
  • 439
  • 1
  • 4
  • 4