Created
August 19, 2019 20:49
-
-
Save robertmryan/8452b061c301c311b88a2573fa8ab367 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Accelerate | |
extension UIImage { | |
var averageColor: UIColor? { | |
guard let inputImage = CIImage(image: self) else { return nil } | |
let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height) | |
guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil } | |
guard let outputImage = filter.outputImage else { return nil } | |
var bitmap = [UInt8](repeating: 0, count: 4) | |
let context = CIContext(options: [.workingColorSpace: kCFNull as Any]) | |
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil) | |
return UIColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: 1) | |
} | |
var averageColorS: UIColor? { | |
guard let inputCGImage = cgImage else { | |
print("unable to get cgImage") | |
return nil | |
} | |
let colorSpace = CGColorSpaceCreateDeviceRGB() | |
let width = inputCGImage.width | |
let height = inputCGImage.height | |
let bytesPerPixel = 4 | |
let bitsPerComponent = 8 | |
let bytesPerRow = bytesPerPixel * width | |
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue | |
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { | |
print("unable to create context") | |
return nil | |
} | |
context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height)) | |
guard let buffer = context.data else { | |
print("unable to get context data") | |
return nil | |
} | |
let pixelBuffer = buffer.bindMemory(to: UInt8.self, capacity: width * height) | |
let pixelCount = width * height | |
let channelsPerPixel: Int = 4 | |
let m: Int32 = Int32(channelsPerPixel) | |
let n: Int32 = Int32(pixelCount) | |
let lda = m | |
var a = [Float](repeating: 0, count: pixelCount * channelsPerPixel) | |
vDSP_vfltu8(pixelBuffer, vDSP_Stride(1), &a, vDSP_Stride(1), vDSP_Length(pixelCount * channelsPerPixel)) | |
var x = [Float](repeating: 1 / Float(pixelCount) / 255, count: pixelCount) | |
var y = [Float](repeating: 0, count: channelsPerPixel) | |
cblas_sgemv(CblasColMajor, CblasNoTrans, m, n, 1, &a, lda, &x, 1, 1, &y, 1) | |
return UIColor(red: CGFloat(y[0]), green: CGFloat(y[1]), blue: CGFloat(y[2]), alpha: 1) | |
} | |
var averageColorD: UIColor? { | |
guard let inputCGImage = cgImage else { | |
print("unable to get cgImage") | |
return nil | |
} | |
let colorSpace = CGColorSpaceCreateDeviceRGB() | |
let width = inputCGImage.width | |
let height = inputCGImage.height | |
let bytesPerPixel = 4 | |
let bitsPerComponent = 8 | |
let bytesPerRow = bytesPerPixel * width | |
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue | |
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { | |
print("unable to create context") | |
return nil | |
} | |
context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height)) | |
guard let buffer = context.data else { | |
print("unable to get context data") | |
return nil | |
} | |
let pixelBuffer = buffer.bindMemory(to: UInt8.self, capacity: width * height) | |
let pixelCount = width * height | |
let channelsPerPixel: Int = 4 | |
let m: Int32 = Int32(channelsPerPixel) | |
let n: Int32 = Int32(pixelCount) | |
let lda = m | |
var a = [Double](repeating: 0, count: pixelCount * channelsPerPixel) | |
vDSP_vfltu8D(pixelBuffer, vDSP_Stride(1), &a, vDSP_Stride(1), vDSP_Length(pixelCount * channelsPerPixel)) | |
var x = [Double](repeating: 1 / Double(pixelCount) / 255, count: pixelCount) | |
var y = [Double](repeating: 0, count: channelsPerPixel) | |
cblas_dgemv(CblasColMajor, CblasNoTrans, m, n, 1, &a, lda, &x, 1, 1, &y, 1) | |
return UIColor(red: CGFloat(y[0]), green: CGFloat(y[1]), blue: CGFloat(y[2]), alpha: 1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment