我有一个有趣的功能,可以将位图另存为PNG或JPG(两者均无法正常工作),但是好像使用的内容值无法正常工作。
我想念什么? 在Android 10上有效,但在Android 8上无效
fun Bitmap.save(context: Context) {
val contentResolver = context.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "test.png")
put(MediaStore.MediaColumns.TITLE, "test")
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val uri = contentResolver.insert(contentUri, contentValues)
if (uri != null) {
try {
contentResolver.openFileDescriptor(uri, "w", null)?.use {
if (it.fileDescriptor != null) {
with(FileOutputStream(it.fileDescriptor)) {
compress(
Bitmap.CompressFormat.PNG,
DEFAULT_IMAGE_QUALITY,
this
)
flush()
close()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear()
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
MediaScannerConnection.scanFile(context, arrayOf(uri.toString()), null, null)
}
recycle()
}
实际文件名为 1592205828045 (带有时间戳)
实际文件类型为 jpg 和 0B -由于未正确保存?
答案 0 :(得分:1)
您正在创建文件,但仍需要向其中写入Bitmap
:
fun Bitmap.save(context: Context) {
...
val bitmap = this
val maxImageQuality = 100
val uri = contentResolver.insert(contentUri, contentValues)
if (uri != null) {
try {
contentResolver.openFileDescriptor(uri, "w", null)?.use {
if (it.fileDescriptor != null) {
with(FileOutputStream(it.fileDescriptor)) {
bitmap.compress(
Bitmap.CompressFormat.PNG,
maxImageQuality, this
)
flush()
close()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
// release pending status of the file
contentValues.clear()
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
// notify media scanner there's a new picture
MediaScannerConnection.scanFile(context, arrayOf(uri.toString()), null, null)
}
// don't forget to recycle the bitmap when you don't need it any longer
bitmap.recycle()
}
答案 1 :(得分:0)
您将必须维护2种将图像保存到共享存储的不同方式。 post涵盖得很好。在较旧的手机中使用Media Store API会导致您描述的问题。一些适合您的代码示例(已在Android 8、10和11上进行了测试)。
将这些添加到您的清单
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- File save functions handles this -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
向您的应用添加权限检查(未提供代码)
准备好位图调用后,可以使用以下两个功能之一(取决于应用程序当前运行的手机的SDK版本)
//TODO - bitmap needs null check
val bitmap = BitmapFactory.decodeFile(bitmapFile.canonicalPath)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
{
saveBitmapPreQ(bitmap)
} else {
saveBitmapPostQ(bitmap)
}
最后,这些是 saveBitmapPreQ 和 saveBitmapPostQ
的实现@Suppress("DEPRECATION") // Check is preformed on function call
private fun saveBitmapPreQ(thisBitmap: Bitmap){
Log.d("HOME_4", "in pre Q")
val pictureDirectory =
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyFolder")
if (!pictureDirectory.exists()){
pictureDirectory.mkdir()
}
val dateTimeStamp = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
val name = "Image_$dateTimeStamp"
val bitmapFile = File(pictureDirectory, "$name.png")
try {
val fileOutputStream = bitmapFile.outputStream()
thisBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)
fileOutputStream.flush()
fileOutputStream.close()
} catch (e: Exception) {
Log.d("HOME_5", "Pre Q error $e")
}
}
private fun saveBitmapPostQ(thisBitmap: Bitmap){
Log.d("HOME_6", "in post Q")
val dateTimeStamp = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
val name = "Image_$dateTimeStamp"
val relativePath = Environment.DIRECTORY_PICTURES + File.separator + "MyFolder"
val contentValues = ContentValues().apply {
put(MediaStore.Images.ImageColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
put(MediaStore.MediaColumns.TITLE, name)
put(MediaStore.Images.ImageColumns.RELATIVE_PATH, relativePath)
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var outputStream: OutputStream? = null
var uri: Uri? = null
try {
uri = contentResolver.insert(contentUri, contentValues)
if (uri == null){
throw IOException("Failed to create new MediaStore record.")
}
outputStream = contentResolver.openOutputStream(uri)
if (outputStream == null){
throw IOException("Failed to get output stream.")
}
if (!thisBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)){
throw IOException("Failed to save bitmap.")
}
} catch (e: IOException){
if (uri != null)
{
contentResolver.delete(uri, null, null)
}
throw IOException(e)
}
finally {
outputStream?.close()
}
}
我在那里留下了日志消息,以帮助您了解流程。在 saveBitmapPostQ 功能中,我采用了一些快捷方式。请阅读创建新文件标题下的post,以了解如何进一步改善该功能。