I was recently attempting to convert the code from here into Swift. However, I keep getting a white color, no matter the image. Here's my code:
// Playground - noun: a place where people can play
import UIKit
extension UIImage {
func averageColor() -> UIColor {
var colorSpace = CGColorSpaceCreateDeviceRGB()
var rgba: [CGFloat] = [0,0,0,0]
var context = CGBitmapContextCreate(&rgba, 1, 1, 8, 4, colorSpace, CGBitmapInfo.fromRaw(CGImageAlphaInfo.PremultipliedLast.toRaw())!)
rgba
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), self.CGImage)
if rgba[3] > 0 {
var alpha = rgba[3] / 255
var multiplier = alpha / 255
return UIColor(red: rgba[0] * multiplier, green: rgba[1] * multiplier, blue: rgba[2] * multiplier, alpha: alpha)
} else {
return UIColor(red: rgba[0] / 255, green: rgba[1] / 255, blue: rgba[2] / 255, alpha: rgba[3] / 255)
}
}
}
var img = UIImage(data: NSData(contentsOfURL: NSURL(string: "http://upload.wikimedia.org/wikipedia/commons/c/c3/Aurora_as_seen_by_IMAGE.PNG")))
img.averageColor()
Thanks in advance.
CoreImage in iOS 9: use the CIAreaAverage filter and pass the extent of your entire image to be averaged.
Plus, it's much faster since it'll either be running on the GPU or as a highly-optimized CPU CIKernel.
import UIKit
extension UIImage {
func areaAverage() -> UIColor {
var bitmap = [UInt8](count: 4, repeatedValue: 0)
if #available(iOS 9.0, *) {
// Get average color.
let context = CIContext()
let inputImage = CIImage ?? CoreImage.CIImage(CGImage: CGImage!)
let extent = inputImage.extent
let inputExtent = CIVector(x: extent.origin.x, y: extent.origin.y, z: extent.size.width, w: extent.size.height)
let filter = CIFilter(name: "CIAreaAverage", withInputParameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: inputExtent])!
let outputImage = filter.outputImage!
let outputExtent = outputImage.extent
assert(outputExtent.size.width == 1 && outputExtent.size.height == 1)
// Render to bitmap.
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: kCIFormatRGBA8, colorSpace: CGColorSpaceCreateDeviceRGB())
} else {
// Create 1x1 context that interpolates pixels when drawing to it.
let context = CGBitmapContextCreate(&bitmap, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), CGBitmapInfo.ByteOrderDefault.rawValue | CGImageAlphaInfo.PremultipliedLast.rawValue)!
let inputImage = CGImage ?? CIContext().createCGImage(CIImage!, fromRect: CIImage!.extent)
// Render to bitmap.
CGContextDrawImage(context, CGRect(x: 0, y: 0, width: 1, height: 1), inputImage)
}
// Compute result.
let result = UIColor(red: CGFloat(bitmap[0]) / 255.0, green: CGFloat(bitmap[1]) / 255.0, blue: CGFloat(bitmap[2]) / 255.0, alpha: CGFloat(bitmap[3]) / 255.0)
return result
}
}
Swift 3
func areaAverage() -> UIColor {
var bitmap = [UInt8](repeating: 0, count: 4)
if #available(iOS 9.0, *) {
// Get average color.
let context = CIContext()
let inputImage: CIImage = ciImage ?? CoreImage.CIImage(cgImage: cgImage!)
let extent = inputImage.extent
let inputExtent = CIVector(x: extent.origin.x, y: extent.origin.y, z: extent.size.width, w: extent.size.height)
let filter = CIFilter(name: "CIAreaAverage", withInputParameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: inputExtent])!
let outputImage = filter.outputImage!
let outputExtent = outputImage.extent
assert(outputExtent.size.width == 1 && outputExtent.size.height == 1)
// Render to bitmap.
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: kCIFormatRGBA8, colorSpace: CGColorSpaceCreateDeviceRGB())
} else {
// Create 1x1 context that interpolates pixels when drawing to it.
let context = CGContext(data: &bitmap, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let inputImage = cgImage ?? CIContext().createCGImage(ciImage!, from: ciImage!.extent)
// Render to bitmap.
context.draw(inputImage!, in: CGRect(x: 0, y: 0, width: 1, height: 1))
}
// Compute result.
let result = UIColor(red: CGFloat(bitmap[0]) / 255.0, green: CGFloat(bitmap[1]) / 255.0, blue: CGFloat(bitmap[2]) / 255.0, alpha: CGFloat(bitmap[3]) / 255.0)
return result
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With