Android Q: получить изображение из галереи и обработать его - PullRequest
2 голосов
/ 24 октября 2019

Я знаю, что это кажется очень простым вопросом, но он специально для Android Q.

Я просто хочу получить изображение из галереи, сжать его и отправить на сервер. Но из-за Scoped Storage Android Q это сложнее, чем я думал. Сначала я объясню, что я сделал с кодом:

Сначала я отправляю намерение выбрать изображение.

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)
}

Это работает нормально, и я могу получить изображениев методе onActivityResult

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)
    }
}

Хорошо, теперь вопрос, как я могу получить доступ к этому изображению в формате файла, чтобы я мог дополнительно обработать / сжать его.

Следующие вещи, которые я пробовал:

val mImagePath = getImagePathFromUri(activity!!, selectedImage)

Вот мой путь:

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

Я создал файл из него следующим образом:

val file = File(mImagePath)

И следующиймоя пользовательская логика для сжатия и загрузки изображения:

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

В этой пользовательской логике у меня есть метод обработки выборки и поворота изображения следующим образом:

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
}

Но когдаЯ пытаюсь открыть поток, используя context.contentResolver.openInputStream Я получаю следующую ошибку:

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

Я знаю, что получаю это, потому что в Android 10 мы не делаемиметь разрешение на прямой доступ к файлам из внешнего хранилища.

Итак, помогите мне разобраться в этомно как я могу использовать изображение из внешнего хранилища как файл в Android 10.

Примечание: у меня есть все необходимые разрешения, так что это не проблема

1 Ответ

1 голос
/ 24 октября 2019

Следующие вещи, которые я пробовал:

Нет никакой надежной реализации getImagePathFromUri().

В этой пользовательской логике у меня есть методдля обработки выборки и поворота изображения следующим образом:

Вам не нужен File в этой функции. В конце концов, ваш самый первый оператор в этой функции идет и создает Uri из этого File. Итак, замените параметр File на имеющийся у вас Uri и пропустите вызов Uri.fromFile().

, как я могу использовать изображение из внешнего хранилища в качестве файла в Android 10.

Вы не можете. И, как показано выше, вам это не нужно для того, что вы делаете.

Если вы окажетесь в какой-то ситуации, когда вы застряли, используя какую-то библиотеку или API, которые абсолютно положительно должны иметьa File:

  • Откройте InputStream для содержимого, используя contentResolver.openInputStream(), как вы делаете сегодня
  • Скопируйте байты из этого InputStream в некоторые FileOutputStream для файла, который вы можете читать / записывать (например, getCacheDir() для Context)
  • Используйте свою копию с библиотекой или API, для которых требуется File
...