如何使用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 }