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

Zoy*_*oyt 46 uiimage ios swift

我试图用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)
}
Run Code Online (Sandbox Code Playgroud)

提前致谢!

Jac*_*ong 63

由于我遇到了类似的问题,因此我在这里进行了一些搜索.您的代码工作正常.问题可能会从您的图像中提出.

码:

  //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)
      }  
  }
Run Code Online (Sandbox Code Playgroud)

这种方法会从图像的CGImage中选择像素颜色.因此,请确保从正确的图像中选择.例如,如果您的UIImage是200x200,但是来自Imgaes.xcassets的原始图像文件或其来自的任何地方,则为400x400,并且您正在拾取点(100,100),实际上您正在选择图像左上部分的点,而不是中.

两种解决方案:
1,使用来自Imgaes.xcassets的图像,并且只在1x字段中放置一个@ 1x图像.保留@ 2x,@ 3x为空.确保您知道图像大小,并选择一个范围内的点.

//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)) 
Run Code Online (Sandbox Code Playgroud)

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)) 
Run Code Online (Sandbox Code Playgroud)

我只测试了第一种方法,我用它来从调色板中获取颜色.两者都应该有效.快乐编码:)

  • 该解决方案对我来说是有效的,但是随后发生了一些变化,数据以ARGB而不是RGBA的形式输入。请查看此链接以获取更多信息和解决方法:http://stackoverflow.com/questions/34593706/why-do-i-get-the-wrong-color-of-a-pixel-with-following-code (2认同)

Dim*_*ski 28

SWIFT 3,XCODE 8经过测试和工作

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)
    }

}
Run Code Online (Sandbox Code Playgroud)


Set*_*hmr 16

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

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
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例项目

作为旁注,此函数明显快于接受的答案,但它给出了较少定义的结果.我只是将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
}
Run Code Online (Sandbox Code Playgroud)


MJL*_*yco 8

我换了红色和蓝色的颜色.原始函数也没有考虑每行的实际字节数和每像素的字节数.我也尽可能避免打开选项.这是一个更新的功能.

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)
    }
}
Run Code Online (Sandbox Code Playgroud)


ram*_*a n 7

Swift3(IOS 10.3)

重要: -这仅适用于 @ 1x图像.

要求: -

如果您有@ 2x@ 3x图像的解决方案,请分享.谢谢 :)

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)
    }

}
Run Code Online (Sandbox Code Playgroud)

用法

print(yourImageView.image!.getPixelColor(atLocation: location, withFrameSize: yourImageView.frame.size))
Run Code Online (Sandbox Code Playgroud)

您可以使用tapGestureRecognizer进行定位.

  • 用self.scale乘以x和y.这将应用所使用的图像的比例 (3认同)

Mat*_*son 5

作为 UIImage 的扩展,您的代码对我来说很好用。你是如何测试你的颜色的?这是我的例子:

    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)")
Run Code Online (Sandbox Code Playgroud)

这打印:

    Green is r: 0.0 g: 1.0 b: 1.0 a: 1.0
Run Code Online (Sandbox Code Playgroud)

...这是正确的,因为我的图像是一个纯绿色方块。

(“它似乎总是返回 0”是什么意思?您不会碰巧在黑色像素上进行测试,对吗?)


ric*_*chy 5

我在 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)")
}
Run Code Online (Sandbox Code Playgroud)

哪里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)
Run Code Online (Sandbox Code Playgroud)

我得到testColor在此处输入图片说明