当前位置: 首页 > 知识库问答 >
问题:

保存位图Android 8时图像名称和类型错误

锺伟志
2023-03-14

我有一个有趣的是保存位图为PNG或JPG(都不工作),但似乎使用内容值不按预期工作。

  1. 文件名不正确
  2. 文件类型不正确

我错过了什么?适用于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(一些时间戳)

实际文件类型是带有0B的jpg-因为它没有正确保存?

共有2个答案

唐焕
2023-03-14

您正在创建文件,但仍需要将位图写入其中:

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()
}
谷梁英毅
2023-03-14

您必须维护将图像保存到共享存储的两种不同方式。这篇文章涵盖得很好。在旧手机中使用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功能中,我采用了一些快捷方式。请阅读这篇文章,标题是创建一个新文件,介绍如何进一步改进该功能

 类似资料:
  • 我正在尝试使用来保存图像,但它总是以这个名称保存文件1637955326427.jpg并且文件的大小0 B。 <代码>列表。获取(0)。getDocFile()返回一个文档文件,我也在API 28上测试了这个,谢谢 请注意,此图像已存在于外部存储器中,只需复制即可。 编辑:我删除此代码是重复的。我真的很抱歉。文件工作正常,但盗用了错误的名称。

  • 问题内容: 我正在显示一组图像,然后,如果用户希望,可以将图像保存到SD卡。我需要将其保存到外部存储的帮助。有人可以帮我这个忙吗? 网格视图: ImageAdapter: 问题答案: 嗨,我还没有使用过作为应用程序一部分提供的代码,但是我确实使用它来调试了其中一个应用程序在运行时生成的位图。 使用此代码,只要您有位图,就只需要此+清单权限 希望能帮到您 杰森

  • 谁能指导我怎么做这件事吗? 我是一个新的android所以请,如果我能有一个详细的程序,我会很感激。

  • 保存图像 能将图像保存至Memory Stick™或主机内存。 1. 让指针对准想要保存的图像,从选单列中选择[档案] > [保存图像]。 2. 选择[保存]。 提示 若想变更文件名或保存位置,请选择各项输入栏,并执行决定。

  • 我使用一个自定义的视图,在我使用画布,用户可以绘制任何东西,之后,我想保存在sd卡的图像,英国电信是不能做到这一点。不知道是怎么回事。

  • 更新: 我得到以下错误: ...newimg1.save(“img1.png”)文件“C:\python27\lib\site-packages\pil\image.py”,第1439行,在save save_handler(self,fp,filename)文件“C:\python27\lib\site-packages\pil\pngimageplugin.py”中,第572行,在_save