根据这篇Android开发人员最佳实践博客,存储共享媒体文件
(我就是这样)应该使用MediaStore API。
在文档中挖掘,我找不到相关的函数。
这是我在科特林的审判:
val bitmap = getImageBitmap() // I have a bitmap from a function or callback or whatever
val name = "example.png" // I have a name
val picturesDirectory = getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
// Make sure the directory "Android/data/com.mypackage.etc/files/Pictures" exists
if (!picturesDirectory.exists()) {
picturesDirectory.mkdirs()
}
try {
val out = FileOutputStream(File(picturesDirectory, name))
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
out.flush()
out.close()
} catch(e: Exception) {
// handle the error
}
提前感谢!
编辑
多亏了PerracoLabs
val name = "Myimage"
val relativeLocation = Environment.DIRECTORY_PICTURES + File.pathSeparator + "AppName"
val contentValues = ContentValues().apply {
put(MediaStore.Images.ImageColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
// without this part causes "Failed to create new MediaStore record" exception to be invoked (uri is null below)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Images.ImageColumns.RELATIVE_PATH, relativeLocation)
}
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var stream: OutputStream? = null
var uri: Uri? = null
try {
uri = contentResolver.insert(contentUri, contentValues)
if (uri == null)
{
throw IOException("Failed to create new MediaStore record.")
}
stream = contentResolver.openOutputStream(uri)
if (stream == null)
{
throw IOException("Failed to get output stream.")
}
if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream))
{
throw IOException("Failed to save bitmap.")
}
Snackbar.make(mCoordinator, R.string.image_saved_success, Snackbar.LENGTH_INDEFINITE).setAction("Open") {
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_VIEW
intent.data = contentUri
startActivity(Intent.createChooser(intent, "Select Gallery App"))
}.show()
} catch(e: IOException) {
if (uri != null)
{
contentResolver.delete(uri, null, null)
}
throw IOException(e)
}
finally {
stream?.close()
}
图像总是得到一个由数字组成的名称,如下所示:
1563468625314.jpg
这就给我们带来了第二个问题:
更改为:
uri = contentResolver.insert(contentUri, contentValues)
if (uri == null)
{
throw IOException("Failed to create new MediaStore record.")
}
val cursor = contentResolver.query(uri, null, null, null, null)
DatabaseUtils.dumpCursor(cursor)
cursor!!.close()
stream = contentResolver.openOutputStream(uri)
这是原木
I/System.out: >>>>> Dumping cursor android.content.ContentResolver$CursorWrapperInner@76da9d1
I/System.out: 0 {
I/System.out: _id=25417
I/System.out: _data=/storage/emulated/0/Pictures/1563640732667.jpg
I/System.out: _size=null
I/System.out: _display_name=Myimage
I/System.out: mime_type=image/png
I/System.out: title=1563640732667
I/System.out: date_added=1563640732
I/System.out: is_hdr=null
I/System.out: date_modified=null
I/System.out: description=null
I/System.out: picasa_id=null
I/System.out: isprivate=null
I/System.out: latitude=null
I/System.out: longitude=null
I/System.out: datetaken=null
I/System.out: orientation=null
I/System.out: mini_thumb_magic=null
I/System.out: bucket_id=-1617409521
I/System.out: bucket_display_name=Pictures
I/System.out: width=null
I/System.out: height=null
I/System.out: is_hw_privacy=null
I/System.out: hw_voice_offset=null
I/System.out: is_hw_favorite=null
I/System.out: hw_image_refocus=null
I/System.out: album_sort_index=null
I/System.out: bucket_display_name_alias=null
I/System.out: is_hw_burst=0
I/System.out: hw_rectify_offset=null
I/System.out: special_file_type=0
I/System.out: special_file_offset=null
I/System.out: cam_perception=null
I/System.out: cam_exif_flag=null
I/System.out: }
I/System.out: <<<<<
我注意到标题
与名称匹配,所以我尝试添加:
I/System.out: >>>>> Dumping cursor android.content.ContentResolver$CursorWrapperInner@51021a5
I/System.out: 0 {
I/System.out: _id=25418
I/System.out: _data=/storage/emulated/0/Pictures/1563640934803.jpg
I/System.out: _size=null
I/System.out: _display_name=Myimage
I/System.out: mime_type=image/png
I/System.out: title=Myimage
I/System.out: date_added=1563640934
I/System.out: is_hdr=null
I/System.out: date_modified=null
I/System.out: description=null
I/System.out: picasa_id=null
I/System.out: isprivate=null
I/System.out: latitude=null
I/System.out: longitude=null
I/System.out: datetaken=null
I/System.out: orientation=null
I/System.out: mini_thumb_magic=null
I/System.out: bucket_id=-1617409521
I/System.out: bucket_display_name=Pictures
I/System.out: width=null
I/System.out: height=null
I/System.out: is_hw_privacy=null
I/System.out: hw_voice_offset=null
I/System.out: is_hw_favorite=null
I/System.out: hw_image_refocus=null
I/System.out: album_sort_index=null
I/System.out: bucket_display_name_alias=null
I/System.out: is_hw_burst=0
I/System.out: hw_rectify_offset=null
I/System.out: special_file_type=0
I/System.out: special_file_offset=null
I/System.out: cam_perception=null
I/System.out: cam_exif_flag=null
I/System.out: }
I/System.out: <<<<<
尝试下一种方法。如果文件夹不存在,Android Q(及以上版本)已经负责创建这些文件夹。该示例是硬编码的,以输出到DCIM文件夹中。如果您需要一个子文件夹,然后追加子文件夹名称如下:
final String relativeLocation = Environment.DIRECTORY_DCIM + File.separator + “YourSubforderName”;
考虑压缩格式应该与mime-type参数相关。例如,对于JPEG压缩格式,MIME类型应该是“image/JPEG”,依此类推。您可能还希望将压缩质量作为参数传递,在本例中,压缩质量被硬编码为95。
Java:
@NonNull
public Uri saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap,
@NonNull final Bitmap.CompressFormat format,
@NonNull final String mimeType,
@NonNull final String displayName) throws IOException {
final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
final ContentResolver resolver = context.getContentResolver();
Uri uri = null;
try {
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, values);
if (uri == null)
throw new IOException("Failed to create new MediaStore record.");
try (final OutputStream stream = resolver.openOutputStream(uri)) {
if (stream == null)
throw new IOException("Failed to open output stream.");
if (!bitmap.compress(format, 95, stream))
throw new IOException("Failed to save bitmap.");
}
return uri;
}
catch (IOException e) {
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
throw e;
}
}
@Throws(IOException::class)
fun saveBitmap(
context: Context, bitmap: Bitmap, format: Bitmap.CompressFormat,
mimeType: String, displayName: String
): Uri {
val values = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
}
val resolver = context.contentResolver
var uri: Uri? = null
try {
uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
?: throw IOException("Failed to create new MediaStore record.")
resolver.openOutputStream(uri)?.use {
if (!bitmap.compress(format, 95, it))
throw IOException("Failed to save bitmap.")
} ?: throw IOException("Failed to open output stream.")
return uri
} catch (e: IOException) {
uri?.let { orphanUri ->
// Don't leave an orphan entry in the MediaStore
resolver.delete(orphanUri, null, null)
}
throw e
}
}
@Throws(IOException::class)
fun saveBitmap(
context: Context, bitmap: Bitmap, format: Bitmap.CompressFormat,
mimeType: String, displayName: String
): Uri {
val values = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
}
var uri: Uri? = null
return runCatching {
with(context.contentResolver) {
insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)?.also {
uri = it // Keep uri reference so it can be removed on failure
openOutputStream(it)?.use { stream ->
if (!bitmap.compress(format, 95, stream))
throw IOException("Failed to save bitmap.")
} ?: throw IOException("Failed to open output stream.")
} ?: throw IOException("Failed to create new MediaStore record.")
}
}.getOrElse {
uri?.let { orphanUri ->
// Don't leave an orphan entry in the MediaStore
context.contentResolver.delete(orphanUri, null, null)
}
throw it
}
}
我想将用我的应用程序录制的mp3文件存储到带有MediaStore的音乐文件夹中,以便在Android 10的新“范围存储”中使用。 此方法效果很好,但这些文件使用时间戳命名(例如1576253519449),没有扩展名。 如果我用文件管理器手动添加扩展名,则文件将被正确记录。 如何使用来命名文件? 还有一个问题:只适用于Android 10。如何保持与旧版本的逆转兼容性? 编辑: 为了实现逆转兼
问题内容: 这是新的Android Q 范围存储的链接。 根据此Android开发者最佳实践博客,(这是我的情况)应使用MediaStore API完成。 深入研究文档,我找不到相关功能。 这是我在科特林的审判: 结果是,按照最佳做法博客中的描述,我的图像保存在此处为 我的问题是: 如何使用MediaStore API保存图像? 用Java回答同样可以接受。 提前致谢! 编辑 感谢PerracoL
问题内容: 我刚刚使用Python图像库(PIL)进行了一些图像处理,这是我之前发现的用于执行图像的傅立叶变换的文章,但是我无法使用save函数。整个代码运行良好,但不会保存生成的图像: 我得到的错误如下: 如何使用Pythons PIL保存图像? 问题答案: 已解决有关文件扩展名的错误,您可以使用(不带点)或将输出名称与扩展名一起传递。现在要处理该错误,您需要在频域中适当地修改数据以将其保存为整
问题内容: 我将Elasticsearch用作Ruby / Sinatra应用程序的数据存储,并且想保存图像。有没有办法将图像作为二进制文件索引到ES中?如果是这样,我应该怎么做,然后将二进制文件转换回图像,以便在站点上显示它? 问题答案: Elasticsearch可以使用二进制类型存储二进制数据。二进制类型需要使用base64编码,并且默认情况下不会被索引。这是一个ES映射示例 一些sinat
我想做一个像相册一样的lib改编成Android Q 由于范围存储,不推荐使用; 我们不能直接通过这样的路径读取文件 没有URI之类的值,因此我无法通过ContentProvider获取图片。 我们可以通过这种方式只打开一个图片(下面的代码),并且在回调中接收到一个URI; 但是我想访问所有的图片,那么,我如何扫描所有的图片在Android Q?
问题内容: 我没有收到任何错误,但是图像没有保存在文档中。 问题答案: 那里的问题是您正在检查文件夹是否不存在,但是应该检查文件是否存在。代码中的另一个问题是,您需要使用url.path而不是url.absoluteString。您还将使用“ png”文件扩展名保存jpeg图像。您应该使用“ jpg”。 编辑/更新: Swift 4.2或更高版本