如何从 Uri 获取位图?
Posted
技术标签:
【中文标题】如何从 Uri 获取位图?【英文标题】:How to get Bitmap from an Uri? 【发布时间】:2011-04-22 06:06:07 【问题描述】:如何从 Uri 中获取 Bitmap 对象(如果我成功将其存储在
/data/data/MYFOLDER/myimage.png
或 file///data/data/MYFOLDER/myimage.png
) 在我的应用程序中使用它?
有没有人知道如何做到这一点?
【问题讨论】:
【参考方案1】:这是正确的做法:
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK)
Uri imageUri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
如果您需要加载非常大的图像,以下代码会将其加载到图块中(避免大量内存分配):
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(myStream, false);
Bitmap region = decoder.decodeRegion(new Rect(10, 10, 50, 50), null);
查看答案here
【讨论】:
此代码不处理更大的图像(基本上任何壁纸尺寸)。 getBitmap() 调用 decodeStream() 失败并出现来自***.com/questions/2220949/handling-large-bitmaps 的 OOM 错误。还有什么建议吗? MediaStore.Images.Thumbnails.getThumbnail() 显然不接受 contentURI。 在这里查看答案:***.com/questions/4753013/… @MarkIngram 这适用于任何本地图像还是仅适用于相机图像? @MarkIngram 如果我们无法访问 data.getData() 怎么办,我的意思是如果我只是从图库中打开一些图像并且我都知道它的路径,我怎样才能获得 uri 和位图? MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);现已弃用【参考方案2】:这是正确的做法,同时还要注意内存使用情况:
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK)
Uri imageUri = data.getData();
Bitmap bitmap = getThumbnail(imageUri);
public static Bitmap getThumbnail(Uri uri) throws FileNotFoundException, IOException
InputStream input = this.getContentResolver().openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
onlyBoundsOptions.inJustDecodeBounds = true;
onlyBoundsOptions.inDither=true;//optional
onlyBoundsOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional
BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
input.close();
if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1))
return null;
int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;
double ratio = (originalSize > THUMBNAIL_SIZE) ? (originalSize / THUMBNAIL_SIZE) : 1.0;
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
bitmapOptions.inDither = true; //optional
bitmapOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//
input = this.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
input.close();
return bitmap;
private static int getPowerOfTwoForSampleRatio(double ratio)
int k = Integer.highestOneBit((int)Math.floor(ratio));
if(k==0) return 1;
else return k;
Mark Ingram 帖子中的 getBitmap() 调用也调用了 decodeStream(),因此您不会丢失任何功能。
参考资料:
android: Get thumbnail of image on SD card, given Uri of original image
Handling large Bitmaps
【讨论】:
这对我很有帮助,尽管我认为值得一提的是 this 关键字不能在静态上下文中使用。我将它作为参数传递给 getThumbnail 方法,它就像一个魅力。 谁能告诉我应该给THUMBNAILSIZE什么值 关闭再重新打开 InputStream 实际上是必要的,因为第一次 BitmapFactory.decodeStream(...) 调用将流的读取位置设置到末尾,因此该方法的第二次调用不起作用不再重新打开流! THUMBNAILSIZE ,顾名思义是要显示为缩略图的图像的大小,即。缩略图显示尺寸 不需要自己计算比率为 2 的幂,因为解码器本身会将样本大小四舍五入到最接近的 2 的幂。因此可以跳过方法调用getPowerOfTwoForSampleRatio()
。见:developer.android.com/reference/android/graphics/…【参考方案3】:
try
Bitmap bitmap = MediaStore.Images.Media.getBitmap(c.getContentResolver() , Uri.parse(paths));
catch (Exception e)
//handle exception
是的,路径必须是这样的格式
file:///mnt/sdcard/filename.jpg
【讨论】:
@Dhananjay 谢谢,您的提示节省了我的时间,它可以从 Content Provider 加载缩略图位图。 另外,Uri.parse()必须包含URI格式,如:Uri.parse("file:///mnt/sdcard/filename .jpg"),否则我们会得到 java.io.FileNotFoundException: No content provider. 一些社论会很好,但这是对大多数情况下有效的 OP 问题的一个很好的简洁答案。这是一个很好的答案,可以在页面上提取出直接回答 OP 问题的其他答案。 @AndroidNewBee c 是上下文对象。 在我的情况下无法正常工作导致异常原因:java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法'java.lang.String android.net.Uri.getScheme()' 【参考方案4】:似乎MediaStore.Images.Media.getBitmap
在API 29
中已被弃用。推荐的方法是使用ImageDecoder.createSource
,它是在API 28
中添加的。
以下是获取位图的方法:
val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
ImageDecoder.decodeBitmap(ImageDecoder.createSource(requireContext().contentResolver, imageUri))
else
MediaStore.Images.Media.getBitmap(requireContext().contentResolver, imageUri)
重要提示:ImageDecoder.decodeBitmap
读取 EXIF 方向,Media.getBitmap
不读取
【讨论】:
文档清楚地写着“这个方法应该在工作线程中完成,而不是在主线程中完成!”【参考方案5】:private void uriToBitmap(Uri selectedFileUri)
try
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(selectedFileUri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
catch (IOException e)
e.printStackTrace();
【讨论】:
它适用于所有 sdk .. 谢谢。这是Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
的替代方式
MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri) 已弃用【参考方案6】:
这是最简单的解决方案:
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
【讨论】:
【参考方案7】:你可以像这样从 uri 中检索位图
Bitmap bitmap = null;
try
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
catch (IOException e)
e.printStackTrace();
【讨论】:
【参考方案8】:Uri imgUri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imgUri);
【讨论】:
您能否详细说明此代码的工作原理以及它如何回答问题?【参考方案9】: InputStream imageStream = null;
try
imageStream = getContext().getContentResolver().openInputStream(uri);
catch (FileNotFoundException e)
e.printStackTrace();
final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
【讨论】:
【参考方案10】:private fun setImage(view: ImageView, uri: Uri)
val stream = contentResolver.openInputStream(uri)
val bitmap = BitmapFactory.decodeStream(stream)
view.setImageBitmap(bitmap)
【讨论】:
【参考方案11】:使用 startActivityForResult 方法,如下所示
startActivityForResult(new Intent(Intent.ACTION_PICK).setType("image/*"), PICK_IMAGE);
你可以得到这样的结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode != RESULT_OK)
return;
switch (requestCode)
case PICK_IMAGE:
Uri imageUri = data.getData();
try
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
catch (IOException e)
e.printStackTrace();
break;
【讨论】:
【参考方案12】:getBitmap
的插图现在已被贬低,我在 Kotlin 中使用以下方法
PICK_IMAGE_REQUEST ->
data?.data?.let
val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(it))
imageView.setImageBitmap(bitmap)
【讨论】:
【参考方案13】:我尝试了很多方法。这对我来说很完美。
如果您从图库中选择图片。您需要注意从intent.clipdata
或intent.data
获取Uri
,因为其中一个在不同版本中可能为空。
private fun onChoosePicture(data: Intent?):Bitmap
data?.let
var fileUri:Uri? = null
data.clipData?.let clip->
if(clip.itemCount>0)
fileUri = clip.getItemAt(0).uri
it.data?.let uri->
fileUri = uri
return MediaStore.Images.Media.getBitmap(this.contentResolver, fileUri )
【讨论】:
【参考方案14】:你可以这样做:
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent)
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch(requestCode)
case 0:
if(resultCode == RESULT_OK)
Uri selectedImage = imageReturnedIntent.getData();
Bundle extras = imageReturnedIntent.getExtras();
bitmap = extras.getParcelable("data");
break;
通过这种方式,您可以轻松地将 uri 转换为位图。 希望能帮到你。
【讨论】:
这不适用于 android nougat 7.1.1 版本。这个 extras.getParcelable("data");正在返回 null【参考方案15】:(科特林) 因此,截至 2020 年 4 月 7 日,上述选项均无效,但以下是对我有效的方法:
如果要将位图存储在 val 中并使用它设置 imageView,请使用:
val bitmap = BitmapFactory.decodeFile(currentPhotoPath).also bitmap -> imageView.setImageBitmap(bitmap)
如果你只想设置位图和imageView,使用这个:
BitmapFactory.decodeFile(currentPhotoPath).also bitmap -> imageView.setImageBitmap(bitmap)
【讨论】:
【参考方案16】:* For getting bitmap from uri. Work for me perfectly.
public static Bitmap decodeUriToBitmap(Context mContext, Uri sendUri)
Bitmap getBitmap = null;
try
InputStream image_stream;
try
image_stream = mContext.getContentResolver().openInputStream(sendUri);
getBitmap = BitmapFactory.decodeStream(image_stream);
catch (FileNotFoundException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
return getBitmap;
【讨论】:
【参考方案17】:通过使用 glide 库,您可以从uri
获取位图,
几乎在三星设备中图像旋转时我们必须使用exifinterface
检查旋转
但使用 glide 不需要检查旋转,图像总是正确接收。
在 kotlin 中你可以得到bitmap
CoroutineScope(Dispatchers.IO).launch
var bitmap = Glide.with(context).asBitmap().load(imageUri).submit().get()//this is synchronous approach
我正在使用这个依赖项
api 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
【讨论】:
【参考方案18】:从手机图库中获取图片 uri 的完整方法。
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null)
Uri filePath = data.getData();
try //Getting the Bitmap from Gallery
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), filePath);
rbitmap = getResizedBitmap(bitmap, 250);//Setting the Bitmap to ImageView
serImage = getStringImage(rbitmap);
imageViewUserImage.setImageBitmap(rbitmap);
catch (IOException e)
e.printStackTrace();
【讨论】:
【参考方案19】:ContentResolver cr = context.getContentResolver();
try (InputStream input = cr.openInputStream(url))
Bitmap bitmap = BitmapFactory.decodeStream(input);
【讨论】:
考虑稍微解释一下你的答案。尤其是 cr (contentResolver) 部分。以上是关于如何从 Uri 获取位图?的主要内容,如果未能解决你的问题,请参考以下文章
如何从MediaStore.Images.Media.getBitmap(contentResolver,uri)获取Bitmap?