You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Kotlin中实现图片编辑后保存至系统相册?(附已实现的图片选择功能代码)

解决Android保存图片到系统相册的问题

看起来你已经搞定了图片选择和展示的环节,接下来咱们一步步解决保存(包括编辑后)图片到系统相册的问题~

1. 先搞定权限适配

不同Android版本的存储权限规则不一样,得针对性处理:

  • Android 13(API 33)及以上:保存到系统相册不需要额外申请WRITE_EXTERNAL_STORAGE权限,直接通过MediaStore写入即可。
  • Android 10(API 29)到Android 12(API 32):同样不需要WRITE_EXTERNAL_STORAGE,但如果你的targetSdkVersion是29及以上,记得在AndroidManifest.xml里加一句兼容配置:
    <application
        ...
        android:requestLegacyExternalStorage="true">
    </application>
    
  • Android 9(API 28)及以下:需要先在AndroidManifest.xml声明权限,再动态申请:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
    

2. 通用保存图片核心方法

不管是用户选的原图,还是你编辑后的图片,都可以用这个方法保存到相册:

private fun saveImageToGallery(bitmap: Bitmap, context: Context) {
    // 配置图片的存储信息(文件名、格式、存储路径)
    val contentValues = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "my_edited_photo_${System.currentTimeMillis()}.jpg")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        // Android Q及以上可以指定自定义相册文件夹
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyAppAlbum")
        }
    }

    val resolver = context.contentResolver
    // 向媒体库插入图片记录
    val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)

    uri?.let {
        try {
            // 打开输出流写入Bitmap
            resolver.openOutputStream(it)?.use { outputStream ->
                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
                // 通知系统相册刷新,让图片立刻显示
                context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
                Toast.makeText(context, "图片保存成功啦", Toast.LENGTH_SHORT).show()
            }
        } catch (e: IOException) {
            e.printStackTrace()
            Toast.makeText(context, "保存失败了...", Toast.LENGTH_SHORT).show()
        }
    }
}

3. 两种场景的保存实现

场景1:保存用户选取的原图

你已经能拿到图片的URI了,先把URI转成Bitmap,再调用上面的保存方法就行:

// 把你的ActivityResultCallback改写成这样
val getaction = registerForActivityResult(
    ActivityResultContracts.GetContent(),
    ActivityResultCallback { uri ->
        uri?.let {
            photo.setImageURI(it)
            // 将URI转换为Bitmap
            val originalBitmap = MediaStore.Images.Media.getBitmap(contentResolver, it)
            // 这里可以绑定到保存按钮的点击事件,比如先存起来等用户点保存再调用
            // saveImageToGallery(originalBitmap, this)
        }
    }
)

场景2:保存编辑后的图片

等你加上编辑功能后,编辑完成会得到一个Bitmap对象,直接传给保存方法就好,给你个简单示例:

// 假设这是你添加的编辑按钮点击事件
val editBtn = findViewById<Button>(R.id.edit_btn)
editBtn.setOnClickListener {
    // 先把ImageView里的图片转成Bitmap
    val originalBitmap = photo.drawable.toBitmap()
    // 这里写你的编辑逻辑,比如加水印、裁剪、滤镜等,得到编辑后的Bitmap
    val editedBitmap = addWatermarkToBitmap(originalBitmap)
    // 保存编辑后的图片
    saveImageToGallery(editedBitmap, this)
}

// 简单的编辑示例:给图片加文字水印
private fun addWatermarkToBitmap(bitmap: Bitmap): Bitmap {
    val editedBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, bitmap.config)
    val canvas = Canvas(editedBitmap)
    // 先绘制原图
    canvas.drawBitmap(bitmap, 0f, 0f, null)
    // 绘制水印文字
    val paint = Paint().apply {
        color = Color.WHITE
        textSize = 60f
        isAntiAlias = true
        shadowLayer = 5f
    }
    canvas.drawText("Edited by MyApp", 60f, bitmap.height - 60f, paint)
    return editedBitmap
}

小提醒

  • 处理Bitmap后记得调用bitmap.recycle()释放内存,避免OOM。
  • 如果要保存PNG格式,把CompressFormat.JPEG改成CompressFormat.PNG,MIME_TYPE改成image/png
  • Android Q及以上自定义的文件夹会直接显示在系统相册里,用户找起来更方便。

内容的提问来源于stack exchange,提问作者Jan-86

火山引擎 最新活动