簡體   English   中英

"如何使用 Swift 獲取 UIImage 中像素的顏色?"

[英]How do I get the color of a pixel in a UIImage with 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)
}

提前致謝!

由於我面臨類似的問題,因此進行了一些搜索。 你的代碼工作正常。 問題可能是從您的圖像中提出的。

代碼:

  //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 中選擇像素顏色。 因此,請確保您從正確的圖像中挑選。 例如,如果您的 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)) 

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

我只測試了第一種方法,我正在使用它從調色板中獲取顏色。 兩者都應該工作。 快樂編碼:)

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

}

如果您多次調用已回答的問題,則不應在每個像素上使用該函數,因為您正在重新創建相同的數據集。 如果您想要圖像中的所有顏色,請執行以下操作:

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
}

我正在交換紅色和藍色的顏色。 原始函數也沒有考慮每行的實際字節數和每像素的字節數。 我也盡可能避免解開可選項。 這是一個更新的功能。

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)

重要提示: -這僅適用於@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)
    }

}

用法

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

您可以使用 tapGestureRecognizer 定位。

作為 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)")

這打印:

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

...這是正確的,因為我的圖像是一個純綠色方塊。

(“它似乎總是返回 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為: 在此處輸入圖片說明

我認為您需要將每個組件除以 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)

我試圖找到圖像所有四個角的顏色,但得到了意想不到的結果,包括UIColor.clear

問題是像素從 0 開始,因此在圖像寬度處請求像素實際上會回繞並給我第二行的第一個像素。

例如,640 x 480 圖像的右上角像素實際上是x: 639, y: 0 ,而右下角像素實際上是x: 639, y: 479

這是我通過此調整實現的 UIImage 擴展:

func getPixelColor(pos: CGPoint) -> UIColor {

    guard let cgImage = cgImage, let pixelData = cgImage.dataProvider?.data else { return UIColor.clear }
    let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)

    let bytesPerPixel = cgImage.bitsPerPixel / 8
    // adjust the pixels to constrain to be within the width/height of the image
    let y = pos.y > 0 ? pos.y - 1 : 0
    let x = pos.x > 0 ? pos.x - 1 : 0
    let pixelInfo = ((Int(self.size.width) * Int(y)) + Int(x)) * bytesPerPixel

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

Swift 5 ,包括@2x & @3x圖像的解決方案

extension UIImage {
    subscript(_ point: CGPoint) -> UIColor? {
        guard let pixelData = self.cgImage?.dataProvider?.data else { return nil }
        let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
        let pixelInfo: Int = Int((size.width * point.y + point.x) * 4.0 * scale * scale)
        let i = Array(0 ... 3).map { CGFloat(data[pixelInfo + $0]) / CGFloat(255) }
        return UIColor(red: i[0], green: i[1], blue: i[2], alpha: i[3])
    }
}

我使用這個擴展:

public extension UIImage {

    var pixelWidth: Int {
        return cgImage?.width ?? 0
    }

    var pixelHeight: Int {
        return cgImage?.height ?? 0
    }

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

        if 0..<pixelWidth ~= x && 0..<pixelHeight ~= y {
            log.info("Pixel coordinates are in bounds")
        }else {
            log.info("Pixel coordinates are out of bounds")
                        return .black
        }
        guard
            let cgImage = cgImage,
            let data = cgImage.dataProvider?.data,
            let dataPtr = CFDataGetBytePtr(data),
            let colorSpaceModel = cgImage.colorSpace?.model,
            let componentLayout = cgImage.bitmapInfo.componentLayout
        else {
            assertionFailure("Could not get a pixel of an image")
            return .clear
        }

        assert(
            colorSpaceModel == .rgb,
            "The only supported color space model is RGB")
        assert(
            cgImage.bitsPerPixel == 32 || cgImage.bitsPerPixel == 24,
            "A pixel is expected to be either 4 or 3 bytes in size")

        let bytesPerRow = cgImage.bytesPerRow
        let bytesPerPixel = cgImage.bitsPerPixel/8
        let pixelOffset = y*bytesPerRow + x*bytesPerPixel

        if componentLayout.count == 4 {
            let components = (
                dataPtr[pixelOffset + 0],
                dataPtr[pixelOffset + 1],
                dataPtr[pixelOffset + 2],
                dataPtr[pixelOffset + 3]
            )

            var alpha: UInt8 = 0
            var red: UInt8 = 0
            var green: UInt8 = 0
            var blue: UInt8 = 0

            switch componentLayout {
            case .bgra:
                alpha = components.3
                red = components.2
                green = components.1
                blue = components.0
            case .abgr:
                alpha = components.0
                red = components.3
                green = components.2
                blue = components.1
            case .argb:
                alpha = components.0
                red = components.1
                green = components.2
                blue = components.3
            case .rgba:
                alpha = components.3
                red = components.0
                green = components.1
                blue = components.2
            default:
                return .clear
            }

            // If chroma components are premultiplied by alpha and the alpha is `0`,
            // keep the chroma components to their current values.
            if cgImage.bitmapInfo.chromaIsPremultipliedByAlpha && alpha != 0 {
                let invUnitAlpha = 255/CGFloat(alpha)
                red = UInt8((CGFloat(red)*invUnitAlpha).rounded())
                green = UInt8((CGFloat(green)*invUnitAlpha).rounded())
                blue = UInt8((CGFloat(blue)*invUnitAlpha).rounded())
            }

            return .init(red: red, green: green, blue: blue, alpha: alpha)

        } else if componentLayout.count == 3 {
            let components = (
                dataPtr[pixelOffset + 0],
                dataPtr[pixelOffset + 1],
                dataPtr[pixelOffset + 2]
            )

            var red: UInt8 = 0
            var green: UInt8 = 0
            var blue: UInt8 = 0

            switch componentLayout {
            case .bgr:
                red = components.2
                green = components.1
                blue = components.0
            case .rgb:
                red = components.0
                green = components.1
                blue = components.2
            default:
                return .clear
            }

            return .init(red: red, green: green, blue: blue, alpha: UInt8(255))

        } else {
            assertionFailure("Unsupported number of pixel components")
            return .clear
        }
    }

}

但是對於正確的像素顏色,您只需要在 x1 中的 xcasset 中使用圖像,否則您的參考是錯誤的,您需要使用它: let CorrectImage = UIImage(data: image.pngData()!) 為您的點檢索正確的原點.

https://stackoverflow.com/a/40237504/3286489的解決方案,僅適用於 sRGB 色彩空間類型的圖像。 但是,對於不同的色彩空間(擴展 sRGB??),它不起作用。

因此,要使其工作,需要先將其轉換為普通的 sRGB 圖像類型,然后再從cgImage獲取顏色。 請注意,我們需要在計算中添加padding以確保寬度始終為 8 的系數

public extension UIImage {
    func getPixelColor(pos: CGPoint) -> UIColor {
        
        // convert to standard sRGB image
        guard let cgImage = cgImage,
            let colorSpace = CGColorSpace(name: CGColorSpace.sRGB),
            let context = CGContext(data: nil, 
                width: Int(size.width), height: Int(size.height),
                bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace,
                bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
        else { return .white }

        context.draw(cgImage, in: CGRect(origin: .zero, size: size))
        
        // Get the newly converted cgImage
        guard let newCGImage = context.makeImage(),
            let newDataProvider = newCGImage.dataProvider,
            let data = newDataProvider.data
        else { return .white }
        let pixelData: UnsafePointer<UInt8> = CFDataGetBytePtr(data)

        // Calculate the pixel position based on point given
        let remaining = 8 - ((Int(size.width)) % 8)
        let padding = (remaining < 8) ? remaining : 0
        let pixelInfo: Int = (((Int(size.width) + padding) * Int(pos.y)) + Int(pos.x)) * 4
        
        let r = CGFloat(pixelData[pixelInfo]) / CGFloat(255.0)
        let g = CGFloat(pixelData[pixelInfo+1]) / CGFloat(255.0)
        let b = CGFloat(pixelData[pixelInfo+2]) / CGFloat(255.0)
        let a = CGFloat(pixelData[pixelInfo+3]) / CGFloat(255.0)
        return UIColor(red: r, green: g, blue: b, alpha: a)
   }
}

或者,如果不想轉換為cgImage ,只需替換

        // Get the newly converted cgImage
        guard let newCGImage = context.makeImage(),
            let newDataProvider = newCGImage.dataProvider,
            let newData = newDataProvider.data
            else { return .white }
        let pixelData: UnsafePointer<UInt8> = CFDataGetBytePtr(newData)

        // Get the data and bind it from UnsafeMutableRawPointer to UInt8
        guard let data = context.data else { return .white }
        let pixelData = data.bindMemory(
            to: UInt8.self, capacity: Int(size.width * size.height * 4))

更新

為了得到更簡潔的代碼,我們可以直接使用UIGraphicsImageRenderer改進到 sRGB 的轉換。 由於這種重繪將像素進一步細化為 2 倍,因此計算確實發生了一些變化。

    func getPixelColor(pos: CGPoint) -> UIColor {
        
        let newImage = UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
        
        guard let cgImage = newImage.cgImage,
            let dataProvider = cgImage.dataProvider,
            let data = dataProvider.data else { return .white }
        let pixelData: UnsafePointer<UInt8> = CFDataGetBytePtr(data)
        let remaining = 8 - ((Int(size.width) * 2) % 8)
        let padding = (remaining < 8) ? remaining : 0
        let pixelInfo: Int = (((Int(size.width * 2) + padding) * Int(pos.y * 2)) + Int(pos.x * 2)) * 4
                
        let r = CGFloat(pixelData[pixelInfo]) / CGFloat(255.0)
        let g = CGFloat(pixelData[pixelInfo+1]) / CGFloat(255.0)
        let b = CGFloat(pixelData[pixelInfo+2]) / CGFloat(255.0)
        let a = CGFloat(pixelData[pixelInfo+3]) / CGFloat(255.0)
        return UIColor(red: r, green: g, blue: b, alpha: a)
    }

這是根據https://stackoverflow.com/a/64538344/3286489中轉換為 sRGB 的解決方案

我在提供的互聯網上的任何地方都沒有找到答案

  • 簡單的代碼
  • HDR 支持
  • bgr 等的顏色配置文件支持。
  • 對@2x @3x 的縮放支持

所以在這里。 據我所知,最終的解決方案是:

斯威夫特 5


import UIKit

public extension CGBitmapInfo {
  // https://stackoverflow.com/a/60247693/2585092
  enum ComponentLayout {
    case bgra
    case abgr
    case argb
    case rgba
    case bgr
    case rgb

    var count: Int {
      switch self {
      case .bgr, .rgb: return 3
      default: return 4
      }
    }
  }

  var componentLayout: ComponentLayout? {
    guard let alphaInfo = CGImageAlphaInfo(rawValue: rawValue & Self.alphaInfoMask.rawValue) else { return nil }
    let isLittleEndian = contains(.byteOrder32Little)

    if alphaInfo == .none {
      return isLittleEndian ? .bgr : .rgb
    }
    let alphaIsFirst = alphaInfo == .premultipliedFirst || alphaInfo == .first || alphaInfo == .noneSkipFirst

    if isLittleEndian {
      return alphaIsFirst ? .bgra : .abgr
    } else {
      return alphaIsFirst ? .argb : .rgba
    }
  }

  var chromaIsPremultipliedByAlpha: Bool {
    let alphaInfo = CGImageAlphaInfo(rawValue: rawValue & Self.alphaInfoMask.rawValue)
    return alphaInfo == .premultipliedFirst || alphaInfo == .premultipliedLast
  }
}

extension UIImage {
  // https://stackoverflow.com/a/68103748/2585092
  subscript(_ point: CGPoint) -> UIColor? {
    guard
      let cgImage = cgImage,
      let space = cgImage.colorSpace,
      let pixelData = cgImage.dataProvider?.data,
      let layout = cgImage.bitmapInfo.componentLayout
    else {
      return nil
    }
    let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)

    let comp = CGFloat(layout.count)
    let hdr = CGFloat(space.isHDR() ? 2 : 1)
    let pixelInfo = Int((size.width * point.y * scale + point.x * scale) * comp * hdr)
    let i = Array(0 ... Int(comp - 1)).map {
      CGFloat(data[pixelInfo + $0 * Int(hdr)]) / CGFloat(255)
    }

    switch layout {
    case .bgra:
      return UIColor(red: i[2], green: i[1], blue: i[0], alpha: i[3])
    case .abgr:
      return UIColor(red: i[3], green: i[2], blue: i[1], alpha: i[0])
    case .argb:
      return UIColor(red: i[1], green: i[2], blue: i[3], alpha: i[0])
    case .rgba:
      return UIColor(red: i[0], green: i[1], blue: i[2], alpha: i[3])
    case .bgr:
      return UIColor(red: i[2], green: i[1], blue: i[0], alpha: 1)
    case .rgb:
      return UIColor(red: i[0], green: i[1], blue: i[2], alpha: 1)
    }
  }
}

如果您使用來自 Imgaes.xcassets 的圖像,並且只在 1x 字段中放置一張 @1x 圖像。 將@2x、@3x 留空。

像往常一樣,聚會遲到了,但我想提一下,上述方法並不總是有效。 如果圖像不是 RGBA,那么它可能會崩潰。 根據我的經驗,當調試代碼運行良好時,運行發布(優化)代碼可能會崩潰。

我傾向於在我的應用程序中使用大量矢量圖像,而 iOS 有時可以在單色空間中渲染它們。 我經歷了許多崩潰,這里給出的代碼。

此外,在垂直跳過時,我們應該使用 bytesPerRow。 Apple 傾向於為位圖添加填充,簡單的 4 字節像素偏移可能不起作用。

我將圖像繪制到屏幕外上下文中,然后從那里獲取樣本。

這就是我所做的。 它有效,但並不完全有效。 就我而言,這很好,因為我只在啟動時使用它一次:

extension UIImage {
    func getRGBColorOfThePixel(at inPoint: CGPoint) -> UIColor? {
        guard (0..<size.width).contains(inPoint.x),
              (0..<size.height).contains(inPoint.y)
        else { return nil }

        // We draw the image into a context, in order to be sure that we are accessing image data in our required format (RGBA).
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        draw(at: .zero, blendMode: .normal, alpha: 1)
        let imageData = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        guard let cgImage = imageData?.cgImage,
              let pixelData = cgImage.dataProvider?.data
        else { return nil }
    
        let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
        let bytesPerPixel = (cgImage.bitsPerPixel + 7) / 8
        var pixelByteOffset: Int = (cgImage.bytesPerRow * Int(inPoint.y)) + (Int(inPoint.x) * bytesPerPixel)

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

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM