iOS中使用vImageFloodFill_ARGB8888实现UIImage泛洪填充遇异常
使用Accelerate框架实现UIImage泛洪填充时结果异常的问题
我尝试用Accelerate框架(尚未完全理解)为UIImage实现泛洪填充功能,编写了UIImage扩展,但执行结果不可控:当UIImage为单色图时结果符合预期,但若使用相册图片调用floodFill方法,结果会混乱。
以下是当前使用的代码:
import Accelerate import Accelerate.vImage import Foundation import CoreGraphics extension UIImage { func floodFill(seedPoint: CGPoint, replacementColor: UIColor) -> UIImage? { guard var buffer = self.toVImage() else { return nil } guard var maskBuffer = createMaskBuffer(width: Int(buffer.width), height: Int(buffer.height)) else { return nil } let replacementRGBA = replacementColor.toRGBA() var cgImageFormatPlanarF = vImage_CGImageFormat( bitsPerComponent: 32, bitsPerPixel: 32, colorSpace: CGColorSpaceCreateDeviceGray(), bitmapInfo: CGBitmapInfo( rawValue: kCGBitmapByteOrder32Host.rawValue | CGBitmapInfo.floatComponents.rawValue | CGImageAlphaInfo.none.rawValue), renderingIntent: .defaultIntent)! let bufferPlanarF = try! vImage.PixelBuffer<vImage.PlanarF>( cgImage: self.cgImage!, cgImageFormat: &cgImageFormatPlanarF) bufferPlanarF.colorThreshold( 0.5, destination: bufferPlanarF) let bufferRGB8 = vImage.PixelBuffer<vImage.Interleaved8x4>( planarBuffers: [bufferPlanarF, bufferPlanarF, bufferPlanarF, bufferPlanarF]) // 创建RGBA组件的连续内存块 var rgbaComponents: [UInt8] = [replacementRGBA.0, replacementRGBA.1, replacementRGBA.2, replacementRGBA.3] bufferRGB8.withUnsafePointerToVImageBuffer { src in vImageFloodFill_ARGB8888(src, nil, UInt(seedPoint.x), UInt(seedPoint.y), &rgbaComponents, 8, 0) } let cgImageFormatRGB8 = vImage_CGImageFormat( bitsPerComponent: 8, bitsPerPixel: 8 * 4, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo( rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue), renderingIntent: .defaultIntent)! guard let result = bufferRGB8.makeCGImage(cgImageFormat: cgImageFormatRGB8) else{ return nil } return UIImage(cgImage: result) } private func toVImage() -> vImage_Buffer? { guard let cgImage = self.cgImage else { return nil } guard let colorSpace = cgImage.colorSpace else { return nil } var format = vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 8 * 4, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue))! var buffer = vImage_Buffer() let error = vImageBuffer_InitWithCGImage(&buffer, &format, nil, cgImage, vImage_Flags(kvImageNoFlags)) guard error == kvImageNoError else { print("创建vImage缓冲区出错: \(error)") return nil } return buffer } private func vImageToCGImage(buffer: vImage_Buffer) -> CGImage? { guard let context = CGContext(data: buffer.data, width: Int(buffer.width), height: Int(buffer.height), bitsPerComponent: 8, bytesPerRow: buffer.rowBytes, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).rawValue) else { return nil } return context.makeImage() } private func createMaskBuffer(width: Int, height: Int) -> vImage_Buffer? { let bytesPerPixel = 4 let bytesPerRow = width * bytesPerPixel let byteCount = bytesPerRow * height let maskData = UnsafeMutablePointer<UInt8>.allocate(capacity: byteCount) var maskBuffer = vImage_Buffer(data: maskData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow) memset(maskBuffer.data, 0, byteCount) return maskBuffer } } extension UIColor { func toRGBA() -> (UInt8, UInt8, UInt8, UInt8) { var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 getRed(&red, green: &green, blue: &blue, alpha: &alpha) return (UInt8(red * 255), UInt8(green * 255), UInt8(blue * 255), UInt8(alpha * 255)) } }
我尝试了多种传递替换颜色的方式,是不是我在做一件不可能的事?怀疑vImageFloodFill_ARGB8888并非为实际泛洪填充设计,仅适用于空白图像。
编辑补充:添加了结果示例图,同时更新了代码块,该代码直接基于Apple官方文档编写。
内容的提问来源于stack exchange,提问作者April G
相关产品推荐
相关产品推荐

