如何从Uri获取位图?


209

如何从Uri获取Bitmap对象(如果我成功将其存储在 /data/data/MYFOLDER/myimage.png或中file///data/data/MYFOLDER/myimage.png)以在应用程序中使用它?

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


30
您应该在此信息上更新您接受的答案,因为比我的答案更好。
维达尔·韦斯特内斯

1
第二个答案是正确的,则第三个答案是更完整。
IgniteCoders

@VidarVestnes为什么不删除它?
卡洛斯·洛佩斯·玛丽(CarlosLópezMarí)

Answers:


-35

。。 重要说明:请参阅下面@Mark Ingram和@pjv的答案以获得更好的解决方案。 。。

您可以尝试以下方法:

public Bitmap loadBitmap(String url)
{
    Bitmap bm = null;
    InputStream is = null;
    BufferedInputStream bis = null;
    try 
    {
        URLConnection conn = new URL(url).openConnection();
        conn.connect();
        is = conn.getInputStream();
        bis = new BufferedInputStream(is, 8192);
        bm = BitmapFactory.decodeStream(bis);
    }
    catch (Exception e) 
    {
        e.printStackTrace();
    }
    finally {
        if (bis != null) 
        {
            try 
            {
                bis.close();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }
        if (is != null) 
        {
            try 
            {
                is.close();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }
    }
    return bm;
}

但是请记住,只能从线程(而不是GUI -thread)内调用此方法。我是AsyncTask。


2
如何将URI转换为url,例如使用yourUri.toURL()?
维达尔·韦斯特尼斯

7
@VidarVestnes好友,如何在Url上转换文件路径?
dharam 2013年

7
我不明白这是如何选择的答案
Nick Cardoso 2014年

11
我同意,这个答案不应被认为是最好的。可能因为它是第一个答案而被选择。它是一个老职位。无论如何,下面的答案会提供更好的解决方案。
维达尔·韦斯特尼斯

8
@VidarVestnes只是删除您的答案
winklerrr

564

这是正确的方法:

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

这里查看答案


3
这段代码不会处理更大的图像(基本上是任何墙纸尺寸)。getBitmap()从stackoverflow.com/questions/2220949/handling-large-bitmaps调用带有OOM错误的失败的stream 。还有其他建议吗?MediaStore.Images.Thumbnails.getThumbnail()显然没有采用contentURI。
pjv 2011年


@MarkIngram这适用于任何本地图像还是仅适用于相机图像?
Narendra Singh

@MarkIngram如果我们无法访问data.getData(),我的意思是,如果我只是简单地从图库中打开一些图像,而我都知道它的路径,那我如何获得uri和位图?
Umair

@Umair,您应该提出一个新问题,而不要在答案注释中提出。顺便说一句:在这里看看developer.android.com/reference/android/net/Uri.html
winklerrr

111

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

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()调用也调用了encodeStream(),因此您不会失去任何功能。

参考文献:


1
这确实对我有所帮助,尽管我认为值得一提的是,不能在静态上下文中使用this关键字。我将它作为参数传递给getThumbnail方法,它的工作原理就像一个魅力。
MacKinley Smith Smith 2013年

8
谁能告诉我我应该给THUMBNAILSIZE带来什么价值
2014年

2
关闭并重新打开InputStream实际上是必要的,因为第一个BitmapFactory.decodeStream(...)调用将流的读取位置设置为末尾,因此,如果不重新打开流,该方法的第二个调用将不再起作用!
DominicM,2015年

3
请说出THUMBNAILSIZE的值
Mightian

3
不必自己将比率计算为2的幂,因为解码器本身会将样本大小舍入为最接近的2的幂。因此,getPowerOfTwoForSampleRatio()可以跳过方法调用。参见:developer.android.com/reference/android/graphics/…–
winklerrr

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

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

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


1
感谢伊泰,这很简单,如果u有路你刚刚要通过这条道路,并得到位图..这是为我工作,希望到u也试试这个..
DJP

2
@Dhananjay谢谢,您的提示节省了我的一天,它可以从Content Provider加载缩略图位图。
Nezneika

2
此外,Uri.parse()必须包含URI格式,就像:Uri.parse(“ file:///mnt/sdcard/filename.jpg”),否则,我们将得到java.io.FileNotFoundException:无内容提供者
Nezneika

进行一些编辑可能会很好,但这是对大多数情况下有效的OP问题的一个简洁明了的答案。这是在页面上提供的一个很好的答案,目的是提炼出直接回答OP问题的其他答案。
umassthrower 2014年

1
@AndroidNewBee c是上下文对象。
DjP'Sep


16
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();
    }
}

3
它适用于所有SDK。它的另一种方式Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
Jigar帕特尔

所有SDK满意的最真实答案
Noaman Akram,

13

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

11

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

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


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

我尝试了很多方法。这项工作非常适合我。

如果从库中选择pictrue。您需要当心Uri来自intent.clipdataintent.data,因为其中之一在不同版本中可能为null。

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

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
这在android nougat 7.1.1版本中不起作用。这个extras.getParcelable(“ data”); 返回空值
Developer_vaibhav

1

getBitmap现在描述了它的插图,我在Kotlin中使用以下方法

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

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

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


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


   }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.