如何使用Swift获取UIImage中的像素的颜色?

我试图用Swift获取UIImage中的一个像素的颜色,但它似乎总是返回0.这里是代码,从@Minas的这个线程的答案翻译:

func getPixelColor(pos: CGPoint) -> UIColor { var pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage)) var data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) var pixelInfo: Int = ((Int(self.size.width) * Int(pos.y)) + Int(pos.x)) * 4 var r = CGFloat(data[pixelInfo]) var g = CGFloat(data[pixelInfo+1]) var b = CGFloat(data[pixelInfo+2]) var a = CGFloat(data[pixelInfo+3]) return UIColor(red: r, green: g, blue: b, alpha: a) } 

提前致谢!

由于我面临类似的问题,所以有一点search引导我到这里。 你的代码工作正常。 问题可能会从您的图像中提出。

码:

  //On the top of your swift 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) } } 

这种方法会从图像的CGImage中选取像素颜色。 所以确保你从正确的形象中select。 例如,如果您的UIImage是200×200,但是Imgaes.xcassets的原始图像文件或来自哪里的原始图像文件是400×400,而您正在选取点(100,100),则实际上是在图像的左上部分选取点中等。

两种解决scheme
1,使用来自Imgaes.xcassets的图像,并且只在1x字段中放置一个@ 1x图像。 将@ 2x,@ 3x留空。 确保你知道图像大小,并select一个在该范围内的点。

 //Make sure only 1x image is set let image : UIImage = UIImage(named:"imageName") //Make sure point is within the image let color : UIColor = image.getPixelColor(CGPointMake(xValue, yValue)) 

2,缩放CGPoint上下的比例以匹配UIImage。 例如,在上例中let point = CGPoint(100,100)

 let xCoordinate : Float = Float(point.x) * (400.0/200.0) let yCoordinate : Float = Float(point.y) * (400.0/200.0) let newCoordinate : CGPoint = CGPointMake(CGFloat(xCoordinate), CGFloat(yCoordinate)) let image : UIImage = largeImage let color : UIColor = image.getPixelColor(CGPointMake(xValue, yValue)) 

我只testing了第一种方法,我使用它从一个调色板中获得一个颜色。 两者都应该工作。 快乐编码:)

SWIFT 3,XCODE 8经过testing和工作

 extension UIImage { func getPixelColor(pos: CGPoint) -> UIColor { let pixelData = self.cgImage!.dataProvider!.data 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) } } 

你的代码对我来说工作正常,作为UIImage的扩展。 你如何testing你的颜色? 这是我的例子:

  let green = UIImage(named: "green.png") let topLeft = CGPoint(x: 0, y: 0) // Use your extension let greenColour = green.getPixelColor(topLeft) // Dump RGBA values var redval: CGFloat = 0 var greenval: CGFloat = 0 var blueval: CGFloat = 0 var alphaval: CGFloat = 0 greenColour.getRed(&redval, green: &greenval, blue: &blueval, alpha: &alphaval) println("Green is r: \(redval) g: \(greenval) b: \(blueval) a: \(alphaval)") 

这打印:

  Green is r: 0.0 g: 1.0 b: 1.0 a: 1.0 

…这是正确的,因为我的形象是一个坚实的绿色广场。

(你的意思是“它似乎总是返回0”,你不是正在testing一个黑色的像素,是吗?)

我认为你需要将每个组件分成255:

 var r = CGFloat(data[pixelInfo]) / CGFloat(255.0) var g = CGFloat(data[pixelInfo + 1]) / CGFloat(255.0) var b = CGFloat(data[pixelInfo + 2]) / CGFloat(255.0) var a = CGFloat(data[pixelInfo + 3]) / CGFloat(255.0) 

进出口颜色的R和B交换,不知道为什么这我觉得订单是RGBA。

 func testGeneratedColorImage() { let color = UIColor(red: 0.5, green: 0, blue: 1, alpha: 1) let size = CGSize(width: 10, height: 10) let image = UIImage.image(fromColor: color, size: size) XCTAssert(image.size == size) XCTAssertNotNil(image.cgImage) XCTAssertNotNil(image.cgImage!.dataProvider) let pixelData = image.cgImage!.dataProvider!.data let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) let position = CGPoint(x: 1, y: 1) let pixelInfo: Int = ((Int(size.width) * Int(position.y)) + Int(position.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) let testColor = UIColor(red: r, green: g, blue: b, alpha: a) XCTAssert(testColor == color, "Colour: \(testColor) does not match: \(color)") } 

color看起来像这样: 在这里输入图像描述

image看起来像这样: 在这里输入图像描述

testColor看起来像: 在这里输入图像描述

(我可以理解,蓝色值可能会稍微偏离0.502浮点不准确)

随着代码切换到:

  let b = CGFloat(data[pixelInfo]) / CGFloat(255.0) let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0) let r = CGFloat(data[pixelInfo+2]) / CGFloat(255.0) let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0) 

我得到testColor为: 在这里输入图像描述

我正在交换红色和蓝色的颜色。 原始函数也没有考虑每行的实际字节数和每个像素的字节数。 我也尽可能避免解包可选项。 这是一个更新的function。

 import UIKit extension UIImage { /// Get the pixel color at a point in the image func pixelColor(atLocation point: CGPoint) -> UIColor? { guard let cgImage = cgImage, let pixelData = cgImage.dataProvider?.data else { return nil } let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) let bytesPerPixel = cgImage.bitsPerPixel / 8 let pixelInfo: Int = ((cgImage.bytesPerRow * Int(point.y)) + (Int(point.x) * bytesPerPixel)) let b = CGFloat(data[pixelInfo]) / CGFloat(255.0) let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0) let r = 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) } } 

Swift3(IOS 10.3)

 extension UIImage { func getPixelColor(atLocation location: CGPoint, withFrameSize size: CGSize) -> UIColor { let x: CGFloat = (self.size.width) * location.x / size.width let y: CGFloat = (self.size.height) * location.y / size.height let pixelPoint: CGPoint = CGPoint(x: x, y: y) let pixelData = self.cgImage!.dataProvider!.data let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) let pixelIndex: Int = ((Int(self.size.width) * Int(pixelPoint.y)) + Int(pixelPoint.x)) * 4 let r = CGFloat(data[pixelIndex]) / CGFloat(255.0) let g = CGFloat(data[pixelIndex+1]) / CGFloat(255.0) let b = CGFloat(data[pixelIndex+2]) / CGFloat(255.0) let a = CGFloat(data[pixelIndex+3]) / CGFloat(255.0) return UIColor(red: r, green: g, blue: b, alpha: a) } } 

用法

 print(yourImageView.image!.getPixelColor(atLocation: location, withFrameSize: yourImageView.frame.size)) 

您可以从tapGestureRecognizer获取位置

如果您不止一次地调用回答的问题,则不应该在每个像素上都使用该function,因为您正在重新创build相同的一组数据。 如果您想要图像中的所有颜色,请执行以下操作:

 func findColors(_ image: UIImage) -> [UIColor] { let pixelsWide = Int(image.size.width) let pixelsHigh = Int(image.size.height) guard let pixelData = image.cgImage?.dataProvider?.data else { return [] } let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) var imageColors: [UIColor] = [] for x in 0..<pixelsWide { for y in 0..<pixelsHigh { let point = CGPoint(x: x, y: y) let pixelInfo: Int = ((pixelsWide * Int(point.y)) + Int(point.x)) * 4 let color = UIColor(red: CGFloat(data[pixelInfo]) / 255.0, green: CGFloat(data[pixelInfo + 1]) / 255.0, blue: CGFloat(data[pixelInfo + 2]) / 255.0, alpha: CGFloat(data[pixelInfo + 3]) / 255.0) imageColors.append(color) } } return imageColors } 

这是一个示例项目

作为一个方面说明,这个函数比接受的答案快得多,但它给出了一个不太明确的结果..我只是把UIImageView放在sourceView参数中。

 func getPixelColorAtPoint(point: CGPoint, sourceView: UIView) -> UIColor { let pixel = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: 4) let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue) let context = CGContext(data: pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) context!.translateBy(x: -point.x, y: -point.y) sourceView.layer.render(in: context!) let color: UIColor = UIColor(red: CGFloat(pixel[0])/255.0, green: CGFloat(pixel[1])/255.0, blue: CGFloat(pixel[2])/255.0, alpha: CGFloat(pixel[3])/255.0) pixel.deallocate(capacity: 4) return color }