使用Swift 3中的CGPoint从图像获取像素颜色

3

我在Swift 3中尝试使用PixelExtractor类,但出现了一个错误; 无法调用类型为'UnsafePointer'的初始化器,其参数列表类型为'(UnsafeMutableRawPointer?)'

class PixelExtractor: NSObject {

let image: CGImage
let context: CGContextRef?

var width: Int {
    get {
        return CGImageGetWidth(image)
    }
}

var height: Int {
    get {
        return CGImageGetHeight(image)
    }
}

init(img: CGImage) {
    image = img
    context = PixelExtractor.createBitmapContext(img)
}

class func createBitmapContext(img: CGImage) -> CGContextRef {

    // Get image width, height
    let pixelsWide = CGImageGetWidth(img)
    let pixelsHigh = CGImageGetHeight(img)

    let bitmapBytesPerRow = pixelsWide * 4
    let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)

    // Use the generic RGB color space.
    let colorSpace = CGColorSpaceCreateDeviceRGB()

    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    let bitmapData = malloc(bitmapByteCount)
    let bitmapInfo = CGBitmapInfo(rawValue:   CGImageAlphaInfo.PremultipliedFirst.rawValue)
    let size = CGSizeMake(CGFloat(pixelsWide), CGFloat(pixelsHigh))
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
    // create bitmap
    let context = CGBitmapContextCreate(bitmapData, pixelsWide, pixelsHigh, 8,
    bitmapBytesPerRow, colorSpace, bitmapInfo.rawValue)

    // draw the image onto the context
    let rect = CGRect(x: 0, y: 0, width: pixelsWide, height: pixelsHigh)
    CGContextDrawImage(context, rect, img)

    return context!
}

func colorAt(x x: Int, y: Int)->UIColor {

    assert(0<=x && x<width)
    assert(0<=y && y<height)

    let uncastedData = CGBitmapContextGetData(context)
    let data = UnsafePointer<UInt8>(uncastedData)

    let offset = 4 * (y * width + x)

    let alpha: UInt8 = data[offset]
    let red: UInt8 = data[offset+1]
    let green: UInt8 = data[offset+2]
    let blue: UInt8 = data[offset+3]

    let color = UIColor(red: CGFloat(red)/255.0, green: CGFloat(green)/255.0, blue: CGFloat(blue)/255.0, alpha: CGFloat(alpha)/255.0)

    return color
}

请修复此错误。

修复这个错误。

let data = UnsafePointer<UInt8>(uncastedData)

->

let data = UnsafeRawPointer(uncastedData)

遇到了另一个错误:'Type 'UnsafeRawPointer?' has no subscript members'

该如何修复这个错误?

4个回答

5
当您的数据中有一个UnsafeRawPointer时,您可以像这样编写代码:
    let alpha = data.load(fromByteOffset: offset, as: UInt8.self)
    let red = data.load(fromByteOffset: offset+1, as: UInt8.self)
    let green = data.load(fromByteOffset: offset+2, as: UInt8.self)
    let blue = data.load(fromByteOffset: offset+3, as: UInt8.self)

否则,您可以从uncastedData(假设它是UnsafeMutableRawPointer)获取UnsafeMutablePointer<UInt8>

    let data = uncastedData.assumingMemoryBound(to: UInt8.self)

4

SWIFT 3(2017年3月更新)Xcode 8 / IOS 10

重要提示:请注意返回值对应于红色: b ,绿色: r 和蓝色: r ,就像在数据中它们以相反的顺序存储一样。

  • First, create the extension (you can copy&paste somewhere in your code)

    extension UIImage {
    
        func getPixelColor(pos: CGPoint) -> UIColor {
    
            if 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+0]) / 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: b, green: g, blue: r, alpha: a)
            } else {
            //IF something is wrong I returned WHITE, but change as needed
                return UIColor.white
            }
        }
    }
    
  • Then just call it as:

    let colorAtPixel : UIColor = (theView.image?.getPixelColor(pos: CGPoint(x: 2, y: 2)))!
    

虽然代码返回了确切的颜色,但似乎对于不同的CGPoints它并没有返回正确的颜色。

这可能是因为屏幕分辨率吗?(x1,x2,x3)

如果有人能为这个谜团提供些启示,那就太好了...


虽然我仍然在处理视网膜显示器的问题,但我发现这篇文章可能会对某些人有所帮助:https://dev59.com/IF8e5IYBdhLWcg3w_-lN - MLBDG
我只是想知道,UIImage中的点使用哪个坐标系?它是UIKit - 例如点(0,0)在左上角吗?谢谢! - J.Treutlein

3

Swift-3 (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)
    }

}

用法:-

let color = yourImageView.image!.getPixelColor(atLocation: location, withFrameSize: yourImageView.frame.size)

location 是一个 CGPoint,size 是你的 imageView 的大小。


1
以下内容摘自我使用的一些Swift 3代码,用于从图像中取样像素以获取主要色调,我使用它来生成tableView行的背景。色调选择过程的机制不适用于您的问题,因此我只提供相关片段。
let colorSpace = CGColorSpaceCreateDeviceRGB() //  UIExtendedSRGBColorSpace
let newImage = image.cgImage?.copy(colorSpace: colorSpace)

let pixelData = newImage?.dataProvider!.data
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)

var hueFrequency = [Int: Double]()
hueFrequency[1] = 1                 // Add one entry so this serves as a default if no hues from the image pass the filters

let nStart = 1
let mStart = 1

for n in nStart...Int(image.size.width / samplingFactor) {
    for m in mStart...Int(image.size.height / samplingFactor) {
        let pixelInfo: Int = ((Int(image.size.width) * m * Int(samplingFactor)) + n * Int(samplingFactor)) * 4 // bytesPerPixel

        let b = CGFloat(data[pixelInfo]) / CGFloat(255.0)           // cgImage bitmapinfo = rawValue 8194 -> BGRA ordering
        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)

此外,注意到我发现了位图信息值(使用我的参数image.cgImage!.bitmapInfo)表示RGBA序列被重新排序为BGRA,因此我必须在排序步骤中处理它以提取数据。如果颜色不正确,您可能需要检查这一点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接