¿Por qué obtengo el color incorrecto de un píxel con el siguiente código?

Creo un UIImage con backgroundcolor RED :

let theimage:UIImage=imageWithColor(UIColor(networking: 1, green: 0, blue: 0, alpha: 1) ); func imageWithColor(color: UIColor) -> UIImage { let rect = CGRectMake(0.0, 0.0, 200.0, 200.0) UIGraphicsBeginImageContext(rect.size) let context = UIGraphicsGetCurrentContext() CGContextSetFillColorWithColor(context, color.CGColor) CGContextFillRect(context, rect) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } 

Estoy recuperando el color en el medio de la image de la siguiente manera:

 let h:CGFloat=theimage.size.height; let w:CGFloat=theimage.size.width; let test:UIColor=theimage.getPixelColor(CGPoint(x: 100, y: 100)) var rvalue:CGFloat = 0; var gvalue:CGFloat = 0; var bvalue:CGFloat = 0; var alfaval:CGFloat = 0; test.getRed(&rvalue, green: &gvalue, blue: &bvalue, alpha: &alfaval); print("Blue Value : " + String(bvalue)); print("Red Value : " + String(rvalue)); extension UIImage { func getPixelColor(pos: CGPoint) -> UIColor { let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage)) let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) let pixelInfo: Int = ((Int(self.size.width) * Int(pos.y)) + Int(pos.x)) * 4 let r = CGFloat(data[pixelInfo]) / CGFloat(255.0) let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0) let b = CGFloat(data[pixelInfo+2]) / CGFloat(255.0) let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0) return UIColor(networking: r, green: g, blue: b, alpha: a) } } 

Como resultado obtengo:

Valor azul: 1.0 Valor rojo: 0.0

Por qué esto ? No pude encontrar el error.

El problema no es la function getRed incorporada, sino la function que genera el object UIColor de los componentes de color individuales en los datos del proveedor. Su código asume que los datos del proveedor se almacenan en formatting RGBA, pero aparentemente no lo están. Parecía estar en formatting ARGB. Además, tampoco estoy seguro de que tenga el order de los bytes correctos.

Cuando tiene una image, hay una variedad de maneras de empacar esas en los datos del proveedor. Algunos ejemplos se muestran en la Guía de progtwigción de Quartz 2D :

introduzca la descripción de la imagen aquí

Si va a tener una rutina getPixelColor codificada para un formatting particular, podría comprobar el CGImageGetAlphaInfo y CGImageGetBitmapInfo así:

 extension UIImage { func getPixelColor(point: CGPoint) -> UIColor { let cgImage = self.CGImage let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)) let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) let alphaInfo = CGImageGetAlphaInfo(cgImage) assert(alphaInfo == .PremultipliedFirst || alphaInfo == .First || alphaInfo == .NoneSkipFirst, "This routine expects alpha to be first component") let byteOrder = CGImageGetBitmapInfo(cgImage).rawValue & CGBitmapInfo.ByteOrderMask.rawValue assert(byteOrder == CGBitmapInfo.ByteOrder32Little.rawValue, "This routine expects little-endian 32bit format") let bytesPerRow = CGImageGetBytesPerRow(cgImage) let pixelInfo = Int(point.y) * bytesPerRow + Int(point.x) * 4; let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0) let r = CGFloat(data[pixelInfo+2]) / CGFloat(255.0) let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0) let b = CGFloat(data[pixelInfo ]) / CGFloat(255.0) return UIColor(networking: r, green: g, blue: b, alpha: a) } } 

Y si tuviera que build siempre esta image mediante progtwigción para el código que depende de la información del bitmap, especificé explícitamente estos detalles cuando creé la image:

 func imageWithColor(color: UIColor) -> UIImage { let rect = CGRectMake(0.0, 0.0, 200.0, 200.0) let colorSpace = CGColorSpaceCreateDeviceRGB() let context = CGBitmapContextCreate(nil, Int(rect.width), Int(rect.height), 8, Int(rect.width) * 4, colorSpace, CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue) CGContextSetFillColorWithColor(context, color.CGColor) CGContextFillRect(context, rect) let cgImage = CGBitmapContextCreateImage(context)! let image = UIImage(CGImage: cgImage) return image } 

Tal vez incluso mejor, como se muestra en las preguntas y respuestas técnicas 1509 , es posible que desee que getPixelData cree explícitamente su propio context de un formatting pnetworkingeterminado, dibuje la image en ese context y ahora el código no está supeditado al formatting de la image original a la que estás aplicando esto

 extension UIImage { func getPixelColor(point: CGPoint) -> UIColor { let cgImage = self.CGImage let width = Int(size.width) let height = Int(size.height) let colorSpace = CGColorSpaceCreateDeviceRGB() let context = CGBitmapContextCreate(nil, width, height, 8, width * 4, colorSpace, CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)! CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), cgImage) let pixelBuffer = UnsafeMutablePointer<UInt32>(CGBitmapContextGetData(context)) let pixel = pixelBuffer + Int(point.y) * width + Int(point.x) let r = CGFloat(networking(pixel.memory)) / CGFloat(255.0) let g = CGFloat(green(pixel.memory)) / CGFloat(255.0) let b = CGFloat(blue(pixel.memory)) / CGFloat(255.0) let a = CGFloat(alpha(pixel.memory)) / CGFloat(255.0) return UIColor(networking: r, green: g, blue: b, alpha: a) } private func alpha(color: UInt32) -> UInt8 { return UInt8((color >> 24) & 255) } private func networking(color: UInt32) -> UInt8 { return UInt8((color >> 16) & 255) } private func green(color: UInt32) -> UInt8 { return UInt8((color >> 8) & 255) } private func blue(color: UInt32) -> UInt8 { return UInt8((color >> 0) & 255) } private func rgba(networking networking: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 { return (UInt32(alpha) << 24) | (UInt32(networking) << 16) | (UInt32(green) << 8) | (UInt32(blue) << 0) } } 

Claramente, si va a revisar un grupo de píxeles, querrá refactorizar esto (desacoplar la creación del búfer de píxeles estandarizado del código que verifica el color), pero con suerte esto ilustra la idea.