如何为含不同灰度值的图像应用蒙版?仅去除纯黑色区域
解决蒙版仅移除纯黑色区域的问题
我需要将一张带有灰色区域的蒙版应用到原始图像,要求保留除纯黑色以外的所有内容,但找到的代码效果相反,会移除白色像素。当前用该代码处理纯色背景时,灰色区域会出现孔洞,不符合需求。
现有问题代码
func maskImage(image: UIImage, mask: UIImage) -> UIImage { let imageReference = (image.cgImage)! let maskReference = (mask.cgImage)! let imageMask = CGImage( maskWidth: maskReference.width , height: maskReference.height , bitsPerComponent: maskReference.bitsPerComponent , bitsPerPixel: maskReference.bitsPerPixel , bytesPerRow: maskReference.bytesPerRow , provider: maskReference.dataProvider! , decode: nil , shouldInterpolate: true ) return (UIImage(cgImage: (imageReference.masking(imageMask!))!)) }
问题原因
CGImage的masking(_:)方法遵循灰度蒙版规则:
- 纯黑色(像素值0):完全透明,移除原图对应区域
- 纯白色(像素值255):完全不透明,保留原图对应区域
- 灰色(0-255之间):半透明,原图对应区域会出现透明度
现有代码直接使用原蒙版,若蒙版中存在白色/灰色区域,会导致对应原图区域被透明/半透明,和需求完全相反。我们需要的是仅让蒙版的纯黑色区域对应原图透明,其他所有区域(灰、白)都完全保留,因此必须先预处理蒙版,将所有非纯黑的像素转为纯白色。
解决方案代码
func maskImageKeepNonBlack(image: UIImage, mask: UIImage) -> UIImage? { guard let maskCG = mask.cgImage else { return nil } let maskSize = CGSize(width: maskCG.width, height: maskCG.height) // 创建灰度色彩空间,用于处理蒙版 guard let colorSpace = CGColorSpaceCreateDeviceGray() else { return nil } // 创建单通道灰度位图上下文 guard let context = CGContext( data: nil, width: Int(maskSize.width), height: Int(maskSize.height), bitsPerComponent: 8, bytesPerRow: Int(maskSize.width), space: colorSpace, bitmapInfo: CGImageAlphaInfo.none.rawValue ) else { return nil } // 将原蒙版绘制到灰度上下文 context.draw(maskCG, in: CGRect(origin: .zero, size: maskSize)) // 获取并修改像素数据:仅保留纯黑,其余转为纯白 guard let pixelData = context.data else { return nil } let pixels = pixelData.bindMemory(to: UInt8.self, capacity: Int(maskSize.width * maskSize.height)) for i in 0..<pixels.count { // 非纯黑像素全部设为255(纯白) if pixels[i] != 0 { pixels[i] = 255 } } // 创建处理后的蒙版CGImage guard let processedMask = context.makeImage() else { return nil } // 创建符合mask要求的CGImage guard let imageMask = CGImage( maskWidth: processedMask.width, height: processedMask.height, bitsPerComponent: processedMask.bitsPerComponent, bitsPerPixel: processedMask.bitsPerPixel, bytesPerRow: processedMask.bytesPerRow, provider: processedMask.dataProvider!, decode: nil, shouldInterpolate: true ) else { return nil } // 应用蒙版到原图 guard let originalCG = image.cgImage, let maskedCG = originalCG.masking(imageMask) else { return nil } return UIImage(cgImage: maskedCG) }
代码说明
- 蒙版预处理:将原蒙版转为单通道灰度图,遍历所有像素,仅保留纯黑色(值为0),其他像素统一设为255(纯白色)。
- 蒙版应用:使用处理后的蒙版调用
masking(_:),此时只有蒙版纯黑对应的原图区域会被移除,其余区域完全保留,不会出现灰色孔洞。
内容的提问来源于stack exchange,提问作者erotsppa
相关产品推荐
相关产品推荐

