I have a swiftui view that displays a picture which users select from Photo app and shows some texts below the picture. I want to dynamically tune the background color of the view depending on the picture major color. Say, if users select a grass or forest image, the background auto changes to green. Is there any best practice?
how to detect major color in an image in iOS
picture major color
That's the challenge, defining it.
If I had to do it, I would do the following
- Compute the distribution of colours in the image
- Identify the maximum colour in the distribution
To compute distribution, use CIFilter CIAreaHistogram
and how to use histogram
See how to use a CIFilter (here to compute average colour, which is not what you are looking for) https://www.hackingwithswift.com/example-code/media/how-to-read-the-average-color-of-a-uiimage-using-ciareaaverage
You can try this , it work for me :
import SwiftUI import CoreImage import CoreImage.CIFilterBuiltins import UIKit
struct ContentView: View { var body: some View { if let image = UIImage(named: "ka") { DominantColorView(image: image) } else { Text("Image not found") } } }
func extractDominantColor(from image: UIImage) -> UIColor? { guard let inputImage = CIImage(image: image) 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!])
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.0, green: CGFloat(bitmap[1]) / 255.0, blue: CGFloat(bitmap[2]) / 255.0, alpha: CGFloat(bitmap[3]) / 255.0)
} struct DominantColorView: View { let image: UIImage
var dominantColor: Color {
if let uiColor = extractDominantColor(from: image) {
return Color(uiColor)
} else {
return Color.clear
}
}
var body: some View {
ZStack {
dominantColor
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(height: 200)
.shadow(radius: /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/, x: -12, y: 12)
}
}
}