0

Hi I am beginner in Android Development, I am trying to learn Jetpack Compose but I'm facing one problem which I can't resolve. I have this code for opening gallery and selecting image

@Composable
fun LoadImage(
    bitmap: MutableState<Bitmap?>
) {
    var imageUri by remember {
        mutableStateOf<Uri?>(null)
    }
    val context = LocalContext.current

    val launcher = rememberLauncherForActivityResult(
        contract =
        ActivityResultContracts.GetContent()
    ) { uri: Uri? ->
        imageUri = uri
    }

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
            .fillMaxWidth()
            .padding(6.dp)
    ) {
        Button(onClick = {
            launcher.launch("image/*")
        }) {
            Text(text = "Izaberi sliku")
        }
    }
    Log.d("DEBUG", "IMAGE URI $imageUri")
    imageUri?.let {
        if (Build.VERSION.SDK_INT < 28) {
            bitmap.value = MediaStore.Images
                .Media.getBitmap(context.contentResolver, it)

        } else {
            val source = ImageDecoder
                .createSource(context.contentResolver, it)
            bitmap.value = ImageDecoder.decodeBitmap(source)
        }
    }
}

I call it from this component:

@Composable
fun ShowImage(
    member: Member,
    snackScope: CoroutineScope,
    snackHostState: SnackbarHostState,
) {
    val bitmap = remember {
        mutableStateOf<Bitmap?>(null)
    }

    if (bitmap.value != null) {
        Image(
            painter = rememberAsyncImagePainter(bitmap.value),
            contentDescription = null,
            modifier = Modifier.size(400.dp)
        )
    }

    Row(
        modifier = Modifier
            .padding(12.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        LoadImage(bitmap = bitmap)
    }
    ...

What happens: it works perfectly in Pixel 2 API 28 Emulator, but when I run it in LG K22 (Android 10) it does not show the image when it is picked from Gallery. Acrually, if I select image from e.g. /Pictures/Viber folder it is shown, but if I select from any other folder (e.g. Download, DCIM) it does not show, it is just white space, also when I upload that image to Firebase Storage it is all black. Can someone explain what happens and what am I doing wrong? Actually I tried uploading same image which I found in Images/Viber folder from Download directory (copied it, then loaded from application) and it loads. The only difference that I see is that image which loads correctly is about 200KB but image which is not loading correctly is about 3MB. Is there any way to load and show image from gallery in Jetpack Compose? I googled a lot but haven't found any solution except this one.

vm381
  • 119
  • 1
  • 1
  • 5
  • Not a direct answer to the question, but: Storing the URI to a file WON'T work for long, see: https://stackoverflow.com/questions/63478041/android-storing-and-reusing-obtained-uris and https://commonsware.com/blog/2020/08/08/uri-access-lifetime-still-shorter-than-you-might-think.html – JustSightseeing Jun 10 '23 at 17:57

2 Answers2

1

if understood your question correctly you just want to open the gallery select an image then either display it to the screen or upload it to firestore.

if that is the case then why did you have to do all of that you could just use the asyncImage from Coil library to display you image asynchronosly:

var imageUri by remember {
            mutableStateOf<Uri?>(null)
        }    
        val launcher = rememberLauncherForActivityResult(
            contract =
            ActivityResultContracts.GetContent()
        ) { uri: Uri? ->
            imageUri = uri
        }
    AsyncImage(
     model = imageUri,
     contentDescription = null,
     modifier = Modifier
                .padding(4.dp)
                .fillMaxHeight().width(100.dp)
                .clip(RoundedCornerShape(12.dp)),
     contentScale = ContentScale.Crop,
    )
Button(onClick = {
            launcher.launch("image/*")
        }) {
            Text(text = "select image")
        }

and now you can just use the Uri to upload the image to firebase storage.

Ayman Ait
  • 391
  • 2
  • 9
0

@JustSightseeing comment lead me to find a way to fix this. I changed code for selecting image and for converting it to Bitmap as follows:

@Composable
fun LoadImage(
    bitmap: MutableState<Bitmap?>
) {
    val context = LocalContext.current

    var bytes by remember {
        mutableStateOf<ByteArray?>(null)
    }

    val launcher = rememberLauncherForActivityResult(
        contract =
        ActivityResultContracts.GetContent()
    ) { result ->
        val item = context.contentResolver.openInputStream(result!!)
        bytes = item?.readBytes()
        item?.close()
    }

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
            .fillMaxWidth()
            .padding(6.dp)
    ) {
        Button(onClick = {
            launcher.launch("image/*")
        }) {
            Text(text = "Izaberi sliku")
        }
    }

    bytes?.let {
        val bos = ByteArrayOutputStream()
        val bmp = BitmapFactory.decodeByteArray(it, 0, it.size).compress(Bitmap.CompressFormat.JPEG, 50, bos)
        bitmap.value = BitmapFactory.decodeByteArray(bos.toByteArray(), 0, bos.toByteArray().size)
    }


}

Thanks.

vm381
  • 119
  • 1
  • 1
  • 5