You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从相机拍摄所得的URI中打开Bitmap?

解决Xamarin Android中相机拍照后URI无法使用BitmapFactory.DecodeFile的问题

我太懂你这种卡壳的焦虑了!Xamarin Android的官方相机指南确实经常有缺漏和过时内容,好不容易走到图片解码这步,还碰到URI没法直接用BitmapFactory.DecodeFile的坎儿,试了一堆方案还是没搞定真的闹心。

针对你遇到的情况,这里有两个亲测有效的解决思路,你可以根据自己的场景选:

思路1:把URI转换成真实文件路径再解码

如果你一定要用BitmapFactory.DecodeFile,那得先把相机返回的content://类型URI转换成真实文件路径。这里要适配不同Android版本的URI规则,写个工具方法就能搞定:

public string GetRealPathFromUri(Context context, Android.Net.Uri uri)
{
    string path = null;
    // 处理MediaStore的content类型URI
    if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
    {
        string[] projection = { MediaStore.Images.Media.InterfaceConsts.Data };
        using (var cursor = context.ContentResolver.Query(uri, projection, null, null, null))
        {
            if (cursor != null && cursor.MoveToFirst())
            {
                int columnIndex = cursor.GetColumnIndexOrThrow(MediaStore.Images.Media.InterfaceConsts.Data);
                path = cursor.GetString(columnIndex);
            }
        }
    }
    // 处理file类型的URI
    else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
    {
        path = uri.Path;
    }
    return path;
}

拿到路径后就可以正常调用BitmapFactory.DecodeFile(path)了,但要注意Android 10及以上的Scoped Storage限制——如果用户拍摄的照片存在应用私有目录或MediaStore受保护区域,这种方法可能会有权限问题,这时候思路2会更稳妥。

思路2:直接通过URI获取输入流解码(推荐)

不用转路径,直接从URI获取输入流,用BitmapFactory.DecodeStream解码Bitmap,完全避开路径权限的坑,适配所有Android版本,还能顺便处理你要调整图片大小的需求:

public async Task<Bitmap> DecodeBitmapFromUri(Context context, Android.Net.Uri uri, int reqWidth, int reqHeight)
{
    // 先获取输入流,只读取图片尺寸避免OOM
    using (var inputStream = await context.ContentResolver.OpenInputStreamAsync(uri))
    {
        var options = new BitmapFactory.Options
        {
            InJustDecodeBounds = true
        };
        BitmapFactory.DecodeStream(inputStream, null, options);
        
        // 计算合适的缩放比例
        options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);
        options.InJustDecodeBounds = false;
        
        // 重新打开输入流(第一次解码后流指针会移动到末尾)
        using (var inputStream2 = await context.ContentResolver.OpenInputStreamAsync(uri))
        {
            return BitmapFactory.DecodeStream(inputStream2, null, options);
        }
    }
}

// 计算缩放比例,保证图片缩小到目标尺寸且不浪费内存
private int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
    int height = options.OutHeight;
    int width = options.OutWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth)
    {
        int halfHeight = height / 2;
        int halfWidth = width / 2;

        while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth)
        {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

额外踩坑提醒

  1. 权限要配全:在AndroidManifest.xml里添加相机和媒体读取权限,Android 13+记得用READ_MEDIA_IMAGES替代READ_EXTERNAL_STORAGE;
  2. 相机启动时要正确设置返回结果,确保拿到的URI是有效的;
  3. 用完Bitmap记得调用Recycle()释放内存,避免内存泄漏。

内容的提问来源于stack exchange,提问作者RhomburVernius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:01:52