iOS中直接保存遮罩处理后的图片为何会保存原图?
为什么直接保存遮罩后的图片会失败?
首先得搞清楚你用CGImage.masking(_:)生成的遮罩图片到底是什么:这个方法返回的不是一个拥有独立像素数据的位图,它更像是一个“依赖型引用”——它没有自己的像素缓冲区,只是记录了「基于原图和掩码生成结果」的逻辑,完全依赖原始CGImage的存在。
当你调用UIImageWriteToSavedPhotosAlbum时,系统底层处理这个UIImage时,没有正确解析这种依赖关系,反而直接读取了原始CGImage的数据,导致最终保存的是原图而非遮罩后的结果。
而你用UIGraphicsBeginImageContextWithOptions的临时方法之所以有效,是因为这个过程会创建新的位图上下文,把遮罩后的图片完整绘制进去,相当于把依赖的像素数据都渲染成了独立的位图,生成的新UIImage拥有自己的像素缓冲区,系统保存时就能正确识别出遮罩后的内容。
技术建议
1. 换用CIImage滤镜实现遮罩(更可靠)
用Core Image的滤镜做遮罩,可以生成完全独立的图片,避免依赖原图的问题。比如用CIBlendWithMask滤镜:
func maskOriginalImageUsingCIImage() -> UIImage? { guard let originalImage = self.originalImage, let maskImage = self.maskImage, let ciOriginal = CIImage(image: originalImage), let ciMask = CIImage(image: maskImage) else { return nil } // 将灰度掩码转成带alpha通道的图 let maskToAlphaFilter = CIFilter(name: "CIMaskToAlpha")! maskToAlphaFilter.setValue(ciMask, forKey: kCIInputImageKey) guard let alphaMask = maskToAlphaFilter.outputImage else { return nil } // 用掩码混合原图 let blendFilter = CIFilter(name: "CIBlendWithMask")! blendFilter.setValue(ciOriginal, forKey: kCIInputImageKey) blendFilter.setValue(alphaMask, forKey: kCIInputMaskImageKey) guard let outputCIImage = blendFilter.outputImage else { return nil } let ciContext = CIContext(options: [.useSoftwareRenderer: false]) guard let outputCGImage = ciContext.createCGImage(outputCIImage, from: outputCIImage.extent) else { return nil } self.maskImage = nil return UIImage(cgImage: outputCGImage) }
2. 保留原有CGImage方案,但生成独立位图
如果不想换Core Image,你可以把遮罩后的图片转成PNG/JPEG数据,再重新生成UIImage——这个过程会把依赖的像素数据固化成独立文件:
func convertToStandaloneImage(_ image: UIImage) -> UIImage? { // 用PNG数据保证透明度不丢失 guard let imageData = image.pngData() else { return nil } return UIImage(data: imageData) }
保存时用这个转换后的图片即可:
func saveImageToLibrary(){ guard let maskedImage = self.segmentedimage, let standaloneImage = convertToStandaloneImage(maskedImage) else { // 处理错误逻辑 return } UIImageWriteToSavedPhotosAlbum(standaloneImage, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) }
3. 修复代码里的强制解包问题
你代码里用了很多!强制解包,很容易导致崩溃(比如maskImage或originalImage为nil时),建议用guard或可选绑定来处理:
func maskOriginalImage() -> UIImage? { guard let maskImage = self.maskImage, let originalImage = self.originalImage, let maskCGImage = maskImage.cgImage, let originalCGImage = originalImage.cgImage else { return nil } guard let maskedCGImage = originalCGImage.masking(maskCGImage) else { self.maskImage = nil return nil } self.maskImage = nil return UIImage(cgImage: maskedCGImage) }
内容的提问来源于stack exchange,提问作者mohit nihalani
相关产品推荐
相关产品推荐

