Android 问:从图库中获取图像并进行处理
Android Q: Get image from gallery and process it
我知道这似乎是一个非常基本的问题,但它是专门针对 Android 问的。
我只是想从图库中获取图片并压缩并发送到服务器。但是由于 Android Q 的 Scoped Storage,它比我想象的要难。我将首先解释我用代码做了什么:
首先我发出了选图的意向
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)
}
}
好的,现在的问题是如何以文件格式访问此图像,以便进一步 process/compress 它。
以下是我尝试过的事情:
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.
注意:我拥有所有必需的权限,所以这不是问题
Following things I've tried:
没有可靠的 getImagePathFromUri()
实现。
In this custom logic, I have a method to handle sampling and rotation of the image as follows:
您不需要在该函数中使用 File
。毕竟,你在该函数中的第一个语句 会从那个 File
中创建一个 Uri
。因此,将 File
参数替换为您拥有的 Uri
,并跳过 Uri.fromFile()
调用。
how can I use the image from external storage as a file in Android 10.
你不能。而且,如上所示,您不需要它来完成您正在做的事情。
如果您发现自己在某些情况下无法使用某个库或 API 绝对肯定 必须 File
:
- 像今天一样使用
contentResolver.openInputStream()
在内容上打开一个 InputStream
- 将
InputStream
中的字节复制到您可以 read/write 的文件中的某个 FileOutputStream
(例如,Context
上的 getCacheDir()
)
- 将您的副本用于需要
File
的库或 API
通过以下方式为要存储在 Android/data/package 名称中的数据创建一个目录:
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;
}
我知道这似乎是一个非常基本的问题,但它是专门针对 Android 问的。
我只是想从图库中获取图片并压缩并发送到服务器。但是由于 Android Q 的 Scoped Storage,它比我想象的要难。我将首先解释我用代码做了什么:
首先我发出了选图的意向
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)
}
}
好的,现在的问题是如何以文件格式访问此图像,以便进一步 process/compress 它。
以下是我尝试过的事情:
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.
注意:我拥有所有必需的权限,所以这不是问题
Following things I've tried:
没有可靠的 getImagePathFromUri()
实现。
In this custom logic, I have a method to handle sampling and rotation of the image as follows:
您不需要在该函数中使用 File
。毕竟,你在该函数中的第一个语句 会从那个 File
中创建一个 Uri
。因此,将 File
参数替换为您拥有的 Uri
,并跳过 Uri.fromFile()
调用。
how can I use the image from external storage as a file in Android 10.
你不能。而且,如上所示,您不需要它来完成您正在做的事情。
如果您发现自己在某些情况下无法使用某个库或 API 绝对肯定 必须 File
:
- 像今天一样使用
contentResolver.openInputStream()
在内容上打开一个InputStream
- 将
InputStream
中的字节复制到您可以 read/write 的文件中的某个FileOutputStream
(例如,Context
上的getCacheDir()
) - 将您的副本用于需要
File
的库或 API
通过以下方式为要存储在 Android/data/package 名称中的数据创建一个目录:
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;
}