以下方法获取所选照片中特定点的像素颜色。选择JPG时,以下图像处理很快。 选择HEIC照片时,以下图像处理很慢。大约慢40倍(7秒vs 5分钟)。
我想知道为什么会这样,如何解决?为清楚起见,下面的代码有效,处理HEIC需要很长时间。
class 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)
var color: UIColor? = nil
if let context = context {
context.translateBy(x: -point.x, y: -point.y)
sourceView.layer.render(in: context)
color = 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!
}
答案 0 :(得分:0)
如果要花费5分钟,我假设您必须重复调用此例程,每次渲染此0.5
。您应该一次又一次地将整个视图渲染到一个完整的像素缓冲区中,然后可以从该缓冲区中有效地检索多个像素的颜色。
例如:
sourceView
很显然,可以根据需要将其渲染到缓冲区,但是基本思想是将像素缓冲区保存到某个var data: Data?
var width: Int!
var height: Int!
func pixelColor(at point: CGPoint, for sourceView: UIView) -> UIColor? {
if data == nil { fillBuffer(for: sourceView) }
return data?.withUnsafeBytes { rawBufferPointer in
let pixels = rawBufferPointer.bindMemory(to: Pixel.self)
let pixel = pixels[Int(point.y) * width + Int(point.x)]
return pixel.color
}
}
func fillBuffer(for sourceView: UIView) {
// get image snapshot
let bounds = sourceView.bounds
let format = UIGraphicsImageRendererFormat()
format.scale = 1
let image = UIGraphicsImageRenderer(bounds: bounds, format: format).image { _ in
sourceView.drawHierarchy(in: bounds, afterScreenUpdates: false)
}
guard let cgImage = image.cgImage else { return }
// prepare to get pixel buffer
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
width = Int(bounds.width)
height = Int(bounds.height)
// populate and save pixel buffer
if let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) {
context.draw(cgImage, in: bounds)
data = context.data.flatMap { Data(bytes: $0, count: 4 * width * height) }
}
}
中,您可以从中快速检索颜色值。
顺便说一句,我认为使用Data
(如下所示)来渲染稍微更直观的代码是有用的,而不是分别导航RGBA字节:
struct
更有趣的问题,恕我直言,是为什么要检索多个像素的颜色。您是否真的需要单个像素的颜色,还是根据结果(例如直方图,平均颜色等)进行一些计算?即如果您确实只需要逐像素地设置颜色,那很好,但是如果您要解决一个更广泛的问题,我们可能会向您展示比逐像素处理更有效的方法。这些范围包括并行例程,vImage高性能图像处理等。但是,如果不知道您对这些重复调用以获取像素颜色所做的工作,我们就不能说更多。