Android Q: получить изображение из галереи и обработать его
Я знаю, что это очень простой вопрос, но он специально для 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.
Примечание: у меня есть все необходимые разрешения, так что проблема не в этом.
2 ответа
Следующие вещи, которые я пробовал:
Нет возможного надежного getImagePathFromUri()
реализация.
В этой настраиваемой логике у меня есть метод обработки выборки и поворота изображения следующим образом:
Вам не нужен File
в этой функции. В конце концов, ваш самый первый оператор в этой функции создаетUri
От этого File
. Итак, заменитеFile
параметр с Uri
что у вас есть, и пропустите Uri.fromFile()
вызов.
как я могу использовать изображение из внешнего хранилища как файл в Android 10.
Вы не можете. И, как показано выше, вам это не нужно для того, что вы делаете.
Если вы оказались в ситуации, когда застряли в использовании какой-либо библиотеки или API, которые абсолютно точно должны иметьFile
:
- Откройте
InputStream
по содержанию, используяcontentResolver.openInputStream()
, как вы делаете сегодня - Скопируйте байты из этого
InputStream
некоторымFileOutputStream
в файле, который вы можете читать / писать (например,getCacheDir()
наContext
) - Используйте свою копию с библиотекой или API, для которых требуется
File
Создайте каталог для данных, которые будут храниться в Android/data/имя пакета:
private void createDir() {
String timeStamp = utils.currentTimeStamp();
File storageDir = getExternalFilesDir(null);
File image;
try {
image = File.createTempFile(timeStamp, ".png", storageDir);
Log.i("SANJAY ", "createDir: " + image.getPath());
} catch (IOException e) {
e.printStackTrace();
Log.i("SANJAY ", "createDir: " + e.getMessage());
}
}
теперь вызовите намерение галереи:
intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, 100);
В onActivityResult():
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == 100) {
Uri mediaUri = data.getData();
//display the image
try {
InputStream inputStream = getBaseContext().getContentResolver().openInputStream(mediaUri);
Bitmap bm = BitmapFactory.decodeStream(inputStream);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] byteArray = stream.toByteArray();
bind.photo.setImageBitmap(bm);
//Log.i("SANJAY ", "onActivityResult: " + saveBitMap(this, bm));
uri = Uri.fromFile(saveBitMap(this, bm));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
получить Uri из файла, используя этот метод:
private File saveBitMap(Context context, Bitmap Final_bitmap) {
File pictureFileDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getApplicationContext().getPackageName()
+ "/"/*Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), ""*/);
if (!pictureFileDir.exists()) {
boolean isDirectoryCreated = pictureFileDir.mkdirs();
if (!isDirectoryCreated)
Log.i("SANJAY ", "Can't create directory to save the image");
return null;
}
String filename = pictureFileDir.getPath() + File.separator + System.currentTimeMillis() + ".jpg";
File pictureFile = new File(filename);
try {
pictureFile.createNewFile();
FileOutputStream oStream = new FileOutputStream(pictureFile);
Final_bitmap.compress(Bitmap.CompressFormat.PNG, 18, oStream);
oStream.flush();
oStream.close();
Log.i("SANJAY ", "saveBitMap :: Save Image Successfully..");
} catch (IOException e) {
e.printStackTrace();
Log.i("SANJAY", "There was an issue saving the image.");
Log.i("SANJAY", "Error :: " + e.getLocalizedMessage());
}
return pictureFile;
}