为什么我用下面的代码得到错误的像素颜色?

我用backgroundcolor RED创build一个UIImage:

let theimage:UIImage=imageWithColor(UIColor(red: 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 } 

我正在检索图像中间的颜色,如下所示:

 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(red: r, green: g, blue: b, alpha: a) } } 

结果我得到:

蓝色值:1.0红色值:0.0

为什么这个 ? 我找不到这个错误。

问题不是内置的getRed函数,而是从提供者数据中的各个颜色组件构buildUIColor对象的函数。 您的代码假设提供者数据以RGBA格式存储,但显然不是。 它似乎是在ARGB格式。 另外,我也不确定你的字节顺序是否正确。

当你有一张图片时,有很多方法可以将这些图片打包到提供者数据中。 “ Quartz 2D Programming Guide”中给出了一些例子:

在这里输入图像说明

如果你要有一个为特定格式硬编码的getPixelColor例程,我可以像这样检查CGImageGetAlphaInfoCGImageGetBitmapInfo

 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(red: r, green: g, blue: b, alpha: a) } } 

如果您始终以编程方式为依赖于位图信息的代码构build此图像,则在创build图像时我会明确指定这些详细信息:

 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 } 

也许更好,如技术问答1509中所示 ,您可能希望让getPixelData明确地创build自己的预定格式的上下文,将图像绘制到该上下文中,现在代码不取决于原始图像的格式你正在应用这个。

 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(red(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(red: r, green: g, blue: b, alpha: a) } private func alpha(color: UInt32) -> UInt8 { return UInt8((color >> 24) & 255) } private func red(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(red red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 { return (UInt32(alpha) << 24) | (UInt32(red) << 16) | (UInt32(green) << 8) | (UInt32(blue) << 0) } } 

显然,如果你要检查一堆像素,你需要重构这个(将标准像素缓冲区的创build与检查颜色的代码分开),但是希望这可以说明这个想法。