我在Swift中获取某个像素(由CGPoint指定)的像素颜色时遇到了很大的困难。这是我到目前为止的代码:
@IBOutlet weak var graphImage: UIImageView!
var image : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
}
func getPixelColor(pos: CGPoint) -> UIColor {
var pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.graphImage.image!.CGImage))
var data : UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
var pixelInfo : Int = ((Int(graphImage.image!.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)
}
@IBAction func playTapped(sender: AnyObject) {
getPixelColor(CGPoint(x: 100.0, y: 100.0))
}
我的应用程序在点击播放后崩溃,在“让g = CGFloat ......”这一行上我没有看到任何错误,尽管我对图像的任何事情都很陌生。我想知道我是否需要使用不同类型的图像,或者我的pixelInfo变量中的某些内容是否错误。顺便说一句,我从How do I get the color of a pixel in a UIImage with Swift?获得了大部分代码。任何人都可以指出可能是什么问题?任何帮助将不胜感激!
答案 0 :(得分:4)
Jassonnoahchoi给出了一个很好的答案 - 如果您在转换到Swift 3.0时遇到问题,请尝试使用相同的代码进行以下更改:
class PixelExtractor: NSObject {
let image: CGImage
let context: CGContext?
var width: Int {
get {
return image.width
}
}
var height: Int {
get {
return image.height
}
}
init(img: CGImage) {
image = img
context = PixelExtractor.createBitmapContext(cgImage: img)
}
class func createBitmapContext(cgImage: CGImage) -> CGContext {
// Get image width, height
let pixelsWide = cgImage.width
let pixelsHigh = cgImage.height
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 = CGSize(width: pixelsWide, height: pixelsHigh)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
// create bitmap
let context = CGContext(data: bitmapData, width: pixelsWide, height: pixelsHigh, bitsPerComponent: 8,
bytesPerRow: bitmapBytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
// draw the image onto the context
let rect = CGRect(x: 0, y: 0, width: pixelsWide, height: pixelsHigh)
context?.draw(cgImage, in: rect)
return context!
}
private func colorAt(x: Int, y: Int)->UIColor {
assert(0<=x && x<width)
assert(0<=y && y<height)
let data = context!.data!
let offset = 4 * (y * width + x)
let alpha = CGFloat(data.load(fromByteOffset: offset, as: UInt8.self)) / 255.0
let red = CGFloat(data.load(fromByteOffset: offset+1, as: UInt8.self)) / 255.0
let green = CGFloat(data.load(fromByteOffset: offset+2, as: UInt8.self)) / 255.0
let blue = CGFloat(data.load(fromByteOffset: offset+3, as: UInt8.self)) / 255.0
let color = UIColor(red: red, green: green, blue: blue, alpha: alpha)
return color
}
}
答案 1 :(得分:3)
之前我做过类似的事情。我所做的是创建一个名为PixelExtractor的单独类。
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
}
}
答案 2 :(得分:0)
经过几个小时的努力,我发现RGBA信息的存储方式与BGRA一样。 Check this answer for an extension in SWIFT 3/xcode8/ios10
答案 3 :(得分:0)
Swift 5版本的jasonnoahchoi答案
class PixelExtractor: NSObject {
let image: CGImage
let context: CGContext?
var width: Int {
get {
return image.width
}
}
var height: Int {
get {
return image.height
}
}
init(img: CGImage) {
image = img
context = PixelExtractor.createBitmapContext(img: img)
}
class func createBitmapContext(img: CGImage) -> CGContext {
// Get image width, height
let pixelsWide = img.width
let pixelsHigh = img.height
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 = CGSize(width: CGFloat(pixelsWide), height: CGFloat(pixelsHigh))
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
// create bitmap
let context = CGContext(data: bitmapData,
width: pixelsWide,
height: pixelsHigh,
bitsPerComponent: 8,
bytesPerRow: bitmapBytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue)
// draw the image onto the context
let rect = CGRect(x: 0, y: 0, width: pixelsWide, height: pixelsHigh)
context?.draw(img, in: rect)
return context!
}
func colorAt(x: Int, y: Int)->UIColor {
assert(0<=x && x<width)
assert(0<=y && y<height)
guard let pixelBuffer = context?.data else { return .white }
let data = pixelBuffer.bindMemory(to: UInt8.self, capacity: width * height)
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
}
}