如何将 Bitmap 转换为 Uri?

45

我正在尝试使用Android的SHARE INTENT分享图片到Facebook、twitter等社交媒体平台。

我找到了发送图像到Share Intent的代码,但这段代码需要位图的URI:fullSizeImageUri

以下是完整的代码:

private void startShareMediaActivity(Bitmap image) {
    boolean isVideo=false;
    String mimeType="bmp";
    Uri fullSizeImageUri=null;
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_SEND);
    intent.setType(mimeType);
    intent.putExtra(Intent.EXTRA_STREAM, fullSizeImageUri);
    try {
        startActivity(Intent.createChooser(intent, (isVideo ? "video" : "image")));
    } catch (android.content.ActivityNotFoundException ex) { }
}

如何将Bitmap转换为Uri?

8个回答

94

这是 Colin 的博客,他建议了一个简单的方法来将位图转换为 Uri。点击这里

public Uri getImageUri(Context inContext, Bitmap inImage) {
  ByteArrayOutputStream bytes = new ByteArrayOutputStream();
  inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
  String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
  return Uri.parse(path);
}

15
请注意,这将创建一张图片,并保存在用户的相册中。 - ocross
6
如果路径为空,Uri.parse(path)会使应用程序崩溃。 - Roni Castro
3
不要忘记获取WRITE_EXTERNAL_STORAGE权限,否则insertImage方法可能会返回null。参考:https://stackoverflow.com/a/35283353/3341089 - oguzhan
2
在Android Oreo中无法工作, String path = Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null); path将会得到null。 - Ashutosh Srivastava
1
该方法已被废弃 - Abraham Mathew
显示剩余4条评论

22
String FILENAME = "image.png";
String PATH = "/mnt/sdcard/"+ FILENAME;
File f = new File(PATH);
Uri yourUri = Uri.fromFile(f);

2
解析函数始终需要一个字符串作为参数,而不是文件。下次请仔细阅读函数的详细信息或进行测试。 - Aurelian Cotuna
14
我们能否在不保存位图的情况下获取Uri? - Prasad
在 Android Studio 2022 Bumblebee 中工作 - reza rahmad
@rezarahmad 亲爱的Sheldon,这个问题在10年前已经回答过了。 - KK_07k11A0585
@KK_07k11A0585 是的,这个仍然有效直到2023年以及更多未来的年份。 - reza rahmad

5
我找到的最新解决方案是这个。它是用Kotlin编写的,你可以将其转换为Java。
    // Get uri of images from camera function
private fun getImageUri(inContext: Context?, inImage: Bitmap): Uri {

    val tempFile = File.createTempFile("temprentpk", ".png")
    val bytes = ByteArrayOutputStream()
    inImage.compress(Bitmap.CompressFormat.PNG, 100, bytes)
    val bitmapData = bytes.toByteArray()

    val fileOutPut = FileOutputStream(tempFile)
    fileOutPut.write(bitmapData)
    fileOutPut.flush()
    fileOutPut.close()
    return Uri.fromFile(tempFile)
}

4
上述解决方案使用媒体存储,并将图像存储在用户的主要图像文件夹中,使其可通过画廊/照片查看器查看。该解决方案将其存储为应用程序数据中的临时文件。在此示例中,inImage是一个位图,title是图像文件的名称字符串。
    File tempDir= Environment.getExternalStorageDirectory();
    tempDir=new File(tempDir.getAbsolutePath()+"/.temp/");
    tempDir.mkdir();
    File tempFile = File.createTempFile(title, ".jpg", tempDir);
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    byte[] bitmapData = bytes.toByteArray();

    //write the bytes in file
    FileOutputStream fos = new FileOutputStream(tempFile);
    fos.write(bitmapData);
    fos.flush();
    fos.close();
    return Uri.fromFile(tempFile);

临时文件有多临时? 文件何时被删除?我能在快速连续的几张图片中使用相同的文件名吗? - Joel Broström
你可以使用一个只供你的应用程序使用的目录,而不是tempDir=new File(tempDir.getAbsolutePath()+"/.temp/");,并将图像留在那里。 - DragonFire
@Joel 如果您正在使用循环,请将文件名命名为“file”+i,并在成功处理(例如API响应)后清除此文件夹->这将需要手动完成。 - DragonFire

2
val context = LocalContext.current
val uri = context.saveImage(bitmap) // here you will receive the Uri


private fun Context.saveImage(bitmap: Bitmap): Uri? {
    var uri: Uri? = null
    try {
        val fileName = System.nanoTime().toString() + ".png"
        val values = ContentValues().apply {
            put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
            put(MediaStore.Images.Media.MIME_TYPE, "image/png")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/")
                put(MediaStore.MediaColumns.IS_PENDING, 1)
            } else {
                val directory =
                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
                val file = File(directory, fileName)
                put(MediaStore.MediaColumns.DATA, file.absolutePath)
            }
        }

        uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        uri?.let {
            contentResolver.openOutputStream(it).use { output ->
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, output)
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                values.apply {
                    clear()
                    put(MediaStore.Audio.Media.IS_PENDING, 0)
                }
                contentResolver.update(uri, values, null, null)
            }
        }
        return uri
    }catch (e: java.lang.Exception) {
        if (uri != null) {
            // Don't leave an orphan entry in the MediaStore
            contentResolver.delete(uri, null, null)
        }
        throw e
    }
}

1

传递位图和压缩格式(如PNG、JPG等),以及图像质量百分比。

public Uri getImageUri(Bitmap src, Bitmap.CompressFormat format, int quality) {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    src.compress(format, quality, os);

    String path = MediaStore.Images.Media.insertImage(getContentResolver(), src, "title", null);
    return Uri.parse(path);
}

路径可能为空,因此您的代码在Uri.parse(path)上会崩溃。 - Roni Castro
检查路径是否为空。在传入Uri后执行此操作。 - Pankaj Talaviya
@PankajTalaviya,即使我们提供PNG格式进行压缩,该方法仍将图像保存为.jpg格式。 - Pankaj Mundra
@PankajMundra 增加或减少压缩图像的质量百分比。 - Pankaj Talaviya
那么,根据您的看法,将图像保存为.png格式的适当百分比应该是多少呢?因为如果保存为jpeg格式,图像的背景会变成黑色。 - Pankaj Mundra

0
String picName = "pic.jpg";
        String PATH = Environment.getExternalStorageDirectory().getPath()+ picName;
        File f = new File(PATH);
        Uri yourUri = Uri.fromFile(f);

0

你不能将位图文件转换为URI。在这里阅读更多关于URI的信息。

URI是统一资源标识符。但是你可以将位图放置在绝对或相对URI中,像这样:

Absolute: http://android.com/yourImage.bmp
Relative: yourImage.bmp 

那么我怎样才能满足我的需求呢?这是不可能的吗? - NullPointerException
我想你需要重新思考看待这个问题的方式...查看Facebook和Twitter的API,看看如何实现图像分享。 - Aurelian Cotuna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接