
Я отредактировал сообщение, добавив изображение результатов. Я также отредактировал блок кода. чтобы показать, что я использую, это основано непосредственно на документации Apple для этого.
Используя платформу 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(
cgImage: self.cgImage!,
cgImageFormat: &cgImageFormatPlanarF)
bufferPlanarF.colorThreshold(
0.5,
destination: bufferPlanarF)
let bufferRGB8 = vImage.PixelBuffer(
planarBuffers: [bufferPlanarF, bufferPlanarF, bufferPlanarF, bufferPlanarF])
// Create a contiguous memory block for RGBA components
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("Error creating vImage buffer: \(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.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 не предназначена для настоящей заливки, а предназначена только для заполнения пустых изображений.
Подробнее здесь: https://stackoverflow.com/questions/784 ... -a-uiimage