ios swift uiimage image-manipulation

ios - Cambiar el color de ciertos píxeles en un UIImage



swift image-manipulation (2)

Debe extraer el búfer de píxeles de la imagen, en cuyo punto puede recorrer, cambiando los píxeles como mejor le parezca. Al final, cree una nueva imagen desde el búfer.

En Swift 3, esto se ve así:

func processPixels(in image: UIImage) -> UIImage? { guard let inputCGImage = image.cgImage else { print("unable to get cgImage") return nil } let colorSpace = CGColorSpaceCreateDeviceRGB() let width = inputCGImage.width let height = inputCGImage.height let bytesPerPixel = 4 let bitsPerComponent = 8 let bytesPerRow = bytesPerPixel * width let bitmapInfo = RGBA32.bitmapInfo guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { print("unable to create context") return nil } context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height)) guard let buffer = context.data else { print("unable to get context data") return nil } let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height) for row in 0 ..< Int(height) { for column in 0 ..< Int(width) { let offset = row * width + column if pixelBuffer[offset] == .black { pixelBuffer[offset] = .red } } } let outputCGImage = context.makeImage()! let outputImage = UIImage(cgImage: outputCGImage, scale: image.scale, orientation: image.imageOrientation) return outputImage } struct RGBA32: Equatable { private var color: UInt32 var redComponent: UInt8 { return UInt8((color >> 24) & 255) } var greenComponent: UInt8 { return UInt8((color >> 16) & 255) } var blueComponent: UInt8 { return UInt8((color >> 8) & 255) } var alphaComponent: UInt8 { return UInt8((color >> 0) & 255) } init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) { let red = UInt32(red) let green = UInt32(green) let blue = UInt32(blue) let alpha = UInt32(alpha) color = (red << 24) | (green << 16) | (blue << 8) | (alpha << 0) } static let red = RGBA32(red: 255, green: 0, blue: 0, alpha: 255) static let green = RGBA32(red: 0, green: 255, blue: 0, alpha: 255) static let blue = RGBA32(red: 0, green: 0, blue: 255, alpha: 255) static let white = RGBA32(red: 255, green: 255, blue: 255, alpha: 255) static let black = RGBA32(red: 0, green: 0, blue: 0, alpha: 255) static let magenta = RGBA32(red: 255, green: 0, blue: 255, alpha: 255) static let yellow = RGBA32(red: 255, green: 255, blue: 0, alpha: 255) static let cyan = RGBA32(red: 0, green: 255, blue: 255, alpha: 255) static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool { return lhs.color == rhs.color } }

Para la versión de Swift 2, vea la revisión anterior de esta respuesta .

Para un determinado PNG UIImage multicolor (con transparencia), cuál es la mejor manera / Swift-idiomatic para:

  1. crear un duplicado UIImage
  2. encuentre todos los píxeles negros en la copia y cámbielos a rojo
  3. (devuelva la copia modificada)

Hay algunas preguntas relacionadas sobre SO pero no he podido encontrar algo que funcione.


Para obtener un mejor resultado, podemos buscar el rango de color en píxeles de la imagen, refiriéndonos a la respuesta de @Rob, actualicé y ahora el resultado es mejor.

func processByPixel(in image: UIImage) -> UIImage? { guard let inputCGImage = image.cgImage else { print("unable to get cgImage"); return nil } let colorSpace = CGColorSpaceCreateDeviceRGB() let width = inputCGImage.width let height = inputCGImage.height let bytesPerPixel = 4 let bitsPerComponent = 8 let bytesPerRow = bytesPerPixel * width let bitmapInfo = RGBA32.bitmapInfo guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { print("Cannot create context!"); return nil } context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height)) guard let buffer = context.data else { print("Cannot get context data!"); return nil } let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height) for row in 0 ..< Int(height) { for column in 0 ..< Int(width) { let offset = row * width + column /* * Here I''m looking for color : RGBA32(red: 231, green: 239, blue: 247, alpha: 255) * and I will convert pixels color that in range of above color to transparent * so comparetion can done like this (pixelColorRedComp >= ourColorRedComp - 1 && pixelColorRedComp <= ourColorRedComp + 1 && green && blue) */ if pixelBuffer[offset].redComponent >= 230 && pixelBuffer[offset].redComponent <= 232 && pixelBuffer[offset].greenComponent >= 238 && pixelBuffer[offset].greenComponent <= 240 && pixelBuffer[offset].blueComponent >= 246 && pixelBuffer[offset].blueComponent <= 248 && pixelBuffer[offset].alphaComponent == 255 { pixelBuffer[offset] = .transparent } } } let outputCGImage = context.makeImage()! let outputImage = UIImage(cgImage: outputCGImage, scale: image.scale, orientation: image.imageOrientation) return outputImage }

Espero que esto ayude a alguien 🎉