更改UIImage中某些像素的颜色

对于一个给定的多色PNG UIImage (透明度),什么是最好的/迅捷惯用的方式来:

  1. 创build一个重复的UIImage
  2. find副本中的所有黑色像素,并将其更改为红色
  3. (返回修改的副本)

有几个相关的问题,但我一直没能find有效的东西。

你必须提取图像的像素缓冲区,在这一点上,你可以循环,改变像素,你认为合适的。 最后,从缓冲区创build一个新的图像。

在Swift 3中,这看起来像:

 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) { color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(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 } } 

在Swift 2.x中,这看起来像:

 func processPixelsInImage(inputImage: UIImage) -> UIImage? { let inputCGImage = inputImage.CGImage let colorSpace = CGColorSpaceCreateDeviceRGB() let width = CGImageGetWidth(inputCGImage) let height = CGImageGetHeight(inputCGImage) let bytesPerPixel = 4 let bitsPerComponent = 8 let bytesPerRow = bytesPerPixel * width let bitmapInfo = RGBA32.bitmapInfo guard let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo) else { print("unable to create context") return nil } CGContextDrawImage(context, CGRectMake(0, 0, CGFloat(width), CGFloat(height)), inputCGImage) let pixelBuffer = UnsafeMutablePointer<RGBA32>(CGBitmapContextGetData(context)) var currentPixel = pixelBuffer let black = RGBA32(red: 0, green: 0, blue: 0, alpha: 255) let red = RGBA32(red: 255, green: 0, blue: 0, alpha: 255) for _ in 0 ..< Int(height) { for _ in 0 ..< Int(width) { if currentPixel.memory == black { currentPixel.memory = red } currentPixel += 1 } } let outputCGImage = CGBitmapContextCreateImage(context) let outputImage = UIImage(CGImage: outputCGImage!, scale: inputImage.scale, orientation: inputImage.imageOrientation) return outputImage } struct RGBA32: Equatable { var color: UInt32 var red: UInt8 { return UInt8((color >> 24) & 255) } var green: UInt8 { return UInt8((color >> 16) & 255) } var blue: UInt8 { return UInt8((color >> 8) & 255) } var alpha: UInt8 { return UInt8((color >> 0) & 255) } init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) { color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0) } static let bitmapInfo = CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue } func ==(lhs: RGBA32, rhs: RGBA32) -> Bool { return lhs.color == rhs.color }