Bitmap from View | Android Studio | Compose
How to get and save the screenshot of a specific part of the Screen?
In this tutorial, we will learn how to get the Bitmap from any UI View and Save it to Storage/Gallery. For Example, we have a LinearLayout containing some child views such as ImageView(s), TextView(s), and maybe some more UI Views. On clicking a button we will save that LinearLayout as an image in storage/gallery. So by learning this technique you can save any UI View or Layout as an image in Storage/Gallery.
Code:
MaintActivity.kt
package com.technifysoft.myapplication import android.content.ContentValues import android.content.Context import android.graphics.Bitmap import android.graphics.Rect import android.net.Uri import android.os.Bundle import android.os.Environment import android.provider.MediaStore import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.view.drawToBitmap import com.technifysoft.myapplication.ui.theme.MyApplicationTheme import kotlin.math.roundToInt /** * MainActivityCompose is the main activity of the application, responsible for setting up the UI. */ class MainActivityCompose : ComponentActivity() { /** * Called when the activity is first created. This is where you should do all of your normal static set up: * create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's * previously frozen state, if there was one. */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyApplicationTheme { Scaffold( modifier = Modifier.fillMaxSize(), ) { innerPadding -> ReceiptScreen(innerPadding) } } } } } @Composable fun ReceiptScreen(innerPadding: PaddingValues) { val context = LocalContext.current val rootView = LocalView.current var receiptRect by remember { mutableStateOf<Rect?>(null) } Column( modifier = Modifier .fillMaxSize() .padding(10.dp), verticalArrangement = Arrangement.SpaceBetween ) { // Title Text( text = "Bitmap From Any View/Layout", style = MaterialTheme.typography.bodyLarge, color = Color.Black, modifier = Modifier .fillMaxWidth() .padding(top = 20.dp), ) // Info layout (This will be saved as image) Column( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) .padding(10.dp) .onGloballyPositioned { coordinates -> val position = coordinates.localToWindow(Offset.Zero) val size = coordinates.size receiptRect = Rect( position.x.roundToInt(), position.y.roundToInt(), (position.x + size.width).roundToInt(), (position.y + size.height).roundToInt() ) }, horizontalAlignment = Alignment.CenterHorizontally ) { Image( modifier = Modifier.size(150.dp), painter = painterResource(id = R.drawable.atifpervaiz), contentDescription = "Logo", ) Spacer(Modifier.height(20.dp)) InfoText("Company: Technify Soft") InfoText("Website: https://technifysoft.com/") InfoText("YouTube: youtube.com/@AtifSayings") InfoText("LinkedIn: linkedin.com/in/AtifSayings") InfoText("Facebook: facebook.com/AtifSayings") InfoText("Twitter: twitter.com/AtifSayings") InfoText("Instagram: instagram.com/AtifSayings/") InfoText("Github: github.com/AtifSayings") InfoText("Stack Overflow: stackoverflow.com/users/7981077/atifsayings") } // Save button: Click to save Button( onClick = { val bitmap = rootView.drawToBitmap() val rect = receiptRect if (rect != null) { val cropped = Bitmap.createBitmap( bitmap, rect.left.coerceAtLeast(0), rect.top.coerceAtLeast(0), rect.width().coerceAtMost(bitmap.width - rect.left), rect.height().coerceAtMost(bitmap.height - rect.top) ) saveBitmapToMediaStore( context, cropped, "receipt_${System.currentTimeMillis()}.png" ) { uri -> // You can show Toast or Snackbar here Toast.makeText(context, "Saved", Toast.LENGTH_SHORT).show() } } }, modifier = Modifier .fillMaxWidth() .height(60.dp) ) { Text("Save") } } } @Composable fun InfoText(text: String) { Text( text = text, color = Color.Black, modifier = Modifier .fillMaxWidth() .padding(top = 5.dp) ) } fun saveBitmapToMediaStore( context: Context, bitmap: Bitmap, displayName: String, mimeType: String = "image/png", onComplete: (Uri?) -> Unit ) { val values = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, displayName) put(MediaStore.Images.Media.MIME_TYPE, mimeType) put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Receipts") put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) if (uri == null) { onComplete(null) return } resolver.openOutputStream(uri)?.use { out -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, out) } values.clear() values.put(MediaStore.Images.Media.IS_PENDING, 0) resolver.update(uri, values, null, null) onComplete(uri) } /** * GreetingPreview is a composable function for previewing the MainUI in Android Studio. * It is annotated with @Preview to enable live preview. * */ @Preview(showBackground = true) @Composable fun GreetingPreview() { MyApplicationTheme { ReceiptScreen(PaddingValues()) } }
Comments
Post a Comment