Android移除图片背景后保存至相册显示为黑色的问题
背景移除后图片保存到相册背景变黑色的问题
我通过以下代码实现图片背景移除功能,处理后的图片在应用内显示为透明背景,但保存到设备相册后,背景却变成了黑色。
实现代码
object BackgroundRemover { private val segment: Segmenter private var buffer = ByteBuffer.allocate(0) private var width = 0 private var height = 0 init { val segmentOptions = SelfieSegmenterOptions.Builder() .setDetectorMode(SelfieSegmenterOptions.SINGLE_IMAGE_MODE) .build() segment = Segmentation.getClient(segmentOptions) } /** * Process the image to get buffer and image height and width * @param bitmap Bitmap which you want to remove background. * @param trimEmptyPart After removing the background if its true it will remove the empty part of bitmap. by default its false. * @param listener listener for success and failure callback. **/ fun bitmapForProcessing( bitmap: Bitmap, trimEmptyPart: Boolean = false, listener: OnBackgroundChangeListener ) { //Generate a copy of bitmap just in case the if the bitmap is immutable. val copyBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true) val input = InputImage.fromBitmap(copyBitmap, 0) segment.process(input) .addOnSuccessListener { segmentationMask -> buffer = segmentationMask.buffer width = segmentationMask.width height = segmentationMask.height CoroutineScope(Dispatchers.IO).launch { val time = measureTimeMillis { val resultBitmap = if (trimEmptyPart) { val bgRemovedBitmap = removeBackgroundFromImage(copyBitmap) trim(bgRemovedBitmap) } else { removeBackgroundFromImage(copyBitmap) } withContext(Dispatchers.Main) { listener.onSuccess(resultBitmap) } } Log.e("TAG", "bitmapForProcessingTime: $time") } } .addOnFailureListener { e -> println("Image processing failed: $e") listener.onFailed(e) } } /** * Change the background pixels color to transparent. * */ private suspend fun removeBackgroundFromImage( image: Bitmap ): Bitmap { val bitmap = CoroutineScope(Dispatchers.IO).async { for (y in 0 until height) { for (x in 0 until width) { val bgConfidence = ((1.0 - buffer.float) * 255).toInt() if (bgConfidence >= 100) { image.setPixel(x, y, Color.TRANSPARENT) } } } buffer.rewind() return@async image } return bitmap.await() } /** * trim the empty part of a bitmap. **/ private suspend fun trim( bitmap: Bitmap ): Bitmap { val result = CoroutineScope(Dispatchers.Default).async { var firstX = 0 var firstY = 0 var lastX = bitmap.width var lastY = bitmap.height val pixels = IntArray(bitmap.width * bitmap.height) bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) loop@ for (x in 0 until bitmap.width) { for (y in 0 until bitmap.height) { if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) { firstX = x break@loop } } } loop@ for (y in 0 until bitmap.height) { for (x in firstX until bitmap.width) { if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) { firstY = y break@loop } } } loop@ for (x in bitmap.width - 1 downTo firstX) { for (y in bitmap.height - 1 downTo firstY) { if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) { lastX = x break@loop } } } loop@ for (y in bitmap.height - 1 downTo firstY) { for (x in bitmap.width - 1 downTo firstX) { if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) { lastY = y break@loop } } } return@async Bitmap.createBitmap(bitmap, firstX, firstY, lastX - firstX, lastY - firstY) } return result.await() }
效果说明
- 处理后:图片在应用内显示为透明背景
- 保存到相册后:背景变为黑色
问题原因
相册默认通常会以JPG格式展示图片,而JPG格式不支持透明通道,透明区域会被自动填充为黑色。另外如果你的保存代码默认使用JPEG格式写入图片,也会直接丢失透明信息,导致背景变黑。
解决方案
要保留透明背景,必须以PNG格式保存图片,因为PNG支持Alpha透明通道。
以下是Android中保存透明Bitmap到相册的示例代码:
fun saveBitmapToGallery(context: Context, bitmap: Bitmap) { val filename = "transparent_image_${System.currentTimeMillis()}.png" val outputStream: OutputStream? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/png") put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/YourAppName") } val uri = context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) outputStream = uri?.let { context.contentResolver.openOutputStream(it) } } else { val picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).absolutePath val dir = File(picturesDir, "YourAppName") if (!dir.exists()) dir.mkdirs() val file = File(dir, filename) outputStream = FileOutputStream(file) } outputStream?.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(File(filename)))) Toast.makeText(context, "图片保存成功", Toast.LENGTH_SHORT).show() } }
关键注意点:
- 压缩格式必须指定为
Bitmap.CompressFormat.PNG - MIME类型设置为
image/png - 文件名后缀用
.png
这样保存后的图片在相册中就能正确显示透明背景了。
内容的提问来源于stack exchange,提问作者alfietap
相关产品推荐
相关产品推荐

