Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Q: Get image from gallery and process it

I know it seems like a very basic question, but it's specifically for Android Q.

I just want to get an image from Gallery and compress it and send to the server. But because of the Android Q's Scoped Storage, it's harder than I thought. I'll first explain what I did with code:

First I send out the intent to pick the image.

fun openGallery(fragment: Fragment){
    val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
    intent.type = "*/*"
    val mimeTypes = arrayOf("image/*")
    intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
    fragment.startActivityForResult(intent, REQUEST_IMAGE_PICK)
}

It works fine, and I'm able to get the image in the onActivityResult method

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

    if (requestCode == REQUEST_IMAGE_PICK && resultCode == Activity.RESULT_OK && null != data) {
        val selectedImage = data.data

        val source = ImageDecoder.createSource(activity!!.contentResolver, selectedImage)
        val bitmap = ImageDecoder.decodeBitmap(source)
        mBinding.circularProfileImage.setImageBitmap(bitmap)
    }
}

Okay now the question is how can I access this image in File format, so I can further process/compress it.

Following things I've tried:

val mImagePath = getImagePathFromUri(activity!!, selectedImage)

This is the path I've got:

/storage/emulated/0/DCIM/Camera/IMG_20191022_152437.jpg

I created a file from it, in the following way:

val file = File(mImagePath)

And Following is my custom logic to compress and upload image:

val mNewFile = MediaCompressor.compressCapturedImage(activity!!, file, "ProfilePictures")
uploadProfile(mNewFile)

In this custom logic, I have a method to handle sampling and rotation of the image as follows:

fun handleSamplingAndRotationBitmap(context: Context, selectedImage: File, reqWidth: Int, reqHeight: Int): Bitmap {

    val mUri = Uri.fromFile(selectedImage)

    // First decode with inJustDecodeBounds=true to check dimensions
    val options = BitmapFactory.Options()
    options.inJustDecodeBounds = true
    var imageStream = context.contentResolver.openInputStream(mUri)
    BitmapFactory.decodeStream(imageStream, null, options)
    imageStream!!.close()

    // Calculate inSampleSize
    options.inSampleSize =
        calculateInSampleSize(options, reqWidth, reqHeight)

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false
    imageStream = context.contentResolver.openInputStream(mUri)

    var img = BitmapFactory.decodeStream(imageStream, null, options)

    img = rotateImageIfRequired(context, img!!, mUri)
    return img
}

But when I'm trying to open the stream using context.contentResolver.openInputStream I get the following error:

java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20191022_152437.jpg: open failed: EACCES (Permission denied)

I know I'm getting this because in Android 10 we don't have the permission to directly access files from external storage.

So, please help me figure this out, how can I use the image from external storage as a file in Android 10.

Note: I've all the required permissions, so that's not the issue

like image 353
Parag Pawar Avatar asked Oct 24 '19 10:10

Parag Pawar


People also ask

What is image processing in Android?

Android allows you to manipulate images by adding different kinds of effects on the images. You can easily apply image processing techniques to add certain kinds of effects on images. The effects could be brightness,darkness, grayscale conversion e.t.c. Android provides Bitmap class to handle images.

What is the code to open phone gallery?

What is the code to open phone gallery? To open gallery: (This should be in your activity class.) public OnClickListener btnChoosePhotoPressed = new OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(Intent. ACTION_PICK, android.

How do I get a list of images in a specific folder on Android?

You can use below code to get all images from specific folder. 1) First you need to define File object to get the storage and appened the name of the folder you want to read. File folder = new File(Environment. getExternalStorageDirectory().


1 Answers

Following things I've tried:

There is no possible reliable getImagePathFromUri() implementation.

In this custom logic, I have a method to handle sampling and rotation of the image as follows:

You do not need a File in that function. After all, your very first statement in that function goes and creates a Uri from that File. So, replace the File parameter with the Uri that you have, and skip the Uri.fromFile() call.

how can I use the image from external storage as a file in Android 10.

You can't. And, as demonstrated above, you do not need it for what you are doing.

If you find yourself in some situation where you are stuck using some library or API that absolutely positively must have a File:

  • Open an InputStream on the content, using contentResolver.openInputStream(), as you are doing today
  • Copy the bytes from that InputStream to some FileOutputStream on a file that you can read/write (e.g., getCacheDir() on Context)
  • Use your copy with the library or API that requires a File
like image 161
CommonsWare Avatar answered Oct 21 '22 05:10

CommonsWare