如何从Uri获取Bitmap?

问题描述 投票:0回答:25

如何从 Uri 获取 Bitmap 对象(如果我成功将其存储在

/data/data/MYFOLDER/myimage.png
file///data/data/MYFOLDER/myimage.png
)在我的应用程序中使用它?

有人知道如何实现这一目标吗?

android uri android-image android-bitmap
25个回答
649
投票

正确的做法是:

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

查看答案这里


126
投票

这是正确的方法,同时还要密切关注内存使用情况:

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(),因此您不会丢失任何功能。

参考资料:


66
投票

似乎

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
不读取


51
投票
try
{
    Bitmap bitmap = MediaStore.Images.Media.getBitmap(c.getContentResolver() , Uri.parse(paths));
}
catch (Exception e) 
{
    //handle exception
}

是的,路径必须采用这样的格式

file:///mnt/sdcard/filename.jpg


26
投票
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();
    }
}

25
投票

这是最简单的解决方案:

Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);

12
投票

您可以像这样从 uri 检索位图

Bitmap bitmap = null;
try {
    bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
} catch (IOException e) {
    e.printStackTrace();
}

12
投票
Uri imgUri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imgUri);

6
投票
Bitmap bitmap = null;
ContentResolver contentResolver = getContentResolver(); 
try {
    if(Build.VERSION.SDK_INT < 28) {
        bitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri);
    } else {
        ImageDecoder.Source source = ImageDecoder.createSource(contentResolver, imageUri);
        bitmap = ImageDecoder.decodeBitmap(source);
    }
} catch (Exception e) {
    e.printStackTrace();
}

5
投票
private fun setImage(view: ImageView, uri: Uri) {
        val stream = contentResolver.openInputStream(uri)
        val bitmap = BitmapFactory.decodeStream(stream)
        view.setImageBitmap(bitmap)
}

4
投票

通过使用 glide 库,您可以从

uri
,

获取位图

几乎在三星设备中图像旋转时,我们必须使用

exifinterface

检查旋转

但使用滑行无需检查旋转,图像始终正确接收。

在 kotlin 中你可以得到

bitmap
as

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'

3
投票

getBitmap
的插图现在已不再使用,我在 Kotlin 中使用以下方法

PICK_IMAGE_REQUEST ->
    data?.data?.let {
        val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(it))
        imageView.setImageBitmap(bitmap)
    }

3
投票
  InputStream imageStream = null;
    try {
        imageStream = getContext().getContentResolver().openInputStream(uri);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);

3
投票
ContentResolver cr = context.getContentResolver();
try (InputStream input = cr.openInputStream(url)) {
    Bitmap bitmap = BitmapFactory.decodeStream(input);
}

3
投票

我没有看到正确的答案,所以我将这个扩展放在这里

fun Context.getBitmap(uri: Uri): Bitmap =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) ImageDecoder.decodeBitmap(ImageDecoder.createSource(this.contentResolver, uri))
    else MediaStore.Images.Media.getBitmap(this.contentResolver, uri)

代码示例:

val bitmap = context.getBitmap(uri)

提示:您还可以更新 Activity/fragment 的扩展名,这样您就不必 根本需要写上下文。多一点合成糖)


2
投票

使用如下的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;
    }
}

2
投票

我尝试了很多方法。这对我来说非常有用。

如果您从图库中选择图片。您需要注意从

Uri
intent.clipdata
获取
intent.data
,因为其中一个在不同版本中可能为空。

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

2
投票
val bitmap = context.contentResolver.openInputStream(uri).use { data ->
        BitmapFactory.decodeStream(data)
    }

您需要使用

打开输入流

使用

因为操作完成后它会自动关闭流。


1
投票

你可以做这个结构:

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 转换为位图。 希望对你有帮助。


1
投票

(科特林) 因此,截至 2020 年 4 月 7 日,上述选项均无效,但以下是对我有用的选项:

  1. 如果你想将位图存储在 val 中并用它设置 imageView,请使用:

    val bitmap = BitmapFactory.decodeFile(currentPhotoPath).also { bitmap -> imageView.setImageBitmap(bitmap) }

  2. 如果您只想将位图设置为 imageView,请使用此:

    BitmapFactory.decodeFile(currentPhotoPath).also { bitmap -> imageView.setImageBitmap(bitmap) }


1
投票
* 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;
        }

0
投票

从移动图库获取图像 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();
      }


   }
}

0
投票

使用此处提供的解决方案时我遇到的一个反复出现的问题是:

找不到提供商信息 com.samsung.systemui.navillera.navilleraprovider

这将阻止您的位图被加载。

我尝试了这个,它有效!赞美神。

解释是提供的uri需要转换成文件路径

Bitmap b1 = MediaStore.Images.Media.getBitmap(this.getContentResolver(), Uri.fromFile(new File(uri1.toString())));

0
投票

使用InputStream从Uri中获取位图:

try {
   val inputStream = context.contentResolver.openInputStream(uri)
   val bitmap = BitmapFactory.decodeStream(inputStream)
} catch (e: Exception) {
    e.printStackTrace()
}

-1
投票

在 2022 年使用线圈库来实现此目的。

https://coil-kt.github.io/coil/compose/

用于喷气背包组成

            AsyncImage(
                model = uriOfImage,
                contentDescription = null,
            )
© www.soinside.com 2019 - 2024. All rights reserved.