-
Notifications
You must be signed in to change notification settings - Fork 0
Add extension function to get dominant colors of an image #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // | ||
| // Created by ktiays on 2022/10/17. | ||
| // Copyright (c) 2022 ktiays. All rights reserved. | ||
| // | ||
|
|
||
| #if canImport(UIKit) | ||
|
|
||
| import UIKit | ||
|
|
||
| extension UIImage { | ||
|
|
||
| public convenience init?(with color: UIColor, size: CGSize = .init(width: 1, height: 1)) { | ||
| UIGraphicsBeginImageContextWithOptions(size, false, 0) | ||
| color.setFill() | ||
| UIRectFill(CGRect(origin: CGPoint.zero, size: size)) | ||
| let image = UIGraphicsGetImageFromCurrentImageContext() | ||
| UIGraphicsEndImageContext() | ||
| guard let cgImage = image?.cgImage else { | ||
| return nil | ||
| } | ||
| self.init(cgImage: cgImage) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #elseif canImport(AppKit) | ||
|
|
||
| import AppKit | ||
|
|
||
| extension NSImage { | ||
|
|
||
| public convenience init(color: NSColor, size: NSSize = .init(width: 1, height: 1)) { | ||
| self.init(size: size) | ||
| lockFocus() | ||
| color.drawSwatch(in: NSRect(origin: .zero, size: size)) | ||
| unlockFocus() | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // | ||
| // Created by ktiays on 2022/10/11. | ||
| // Copyright (c) 2022 ktiays. All rights reserved. | ||
| // | ||
|
|
||
| import CoreImage | ||
| import CyanExtensions | ||
|
|
||
| extension CIImage { | ||
|
|
||
| public func dominantColor(clusterCount: Int = 5) -> [PlatformColor] { | ||
| guard let kMeansFilter = CIFilter(name: "CIKMeans") else { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| return [] | ||
| } | ||
|
|
||
| kMeansFilter.setValue(self, forKey: kCIInputImageKey) | ||
| kMeansFilter.setValue(CIVector(cgRect: self.extent), forKey: kCIInputExtentKey) | ||
| kMeansFilter.setValue(clusterCount, forKey: "inputCount") | ||
| kMeansFilter.setValue(20, forKey: "inputPasses") | ||
|
|
||
| guard var outputImage = kMeansFilter.outputImage else { | ||
| return [] | ||
| } | ||
|
|
||
| outputImage = outputImage.settingAlphaOne(in: outputImage.extent) | ||
|
|
||
| let context = CIContext() | ||
| var bitmap = [UInt8](repeating: 0, count: 4 * clusterCount) | ||
| context.render(outputImage, | ||
| toBitmap: &bitmap, | ||
| rowBytes: 4 * clusterCount, | ||
| bounds: outputImage.extent, | ||
| format: CIFormat.RGBA8, | ||
| colorSpace: self.colorSpace!) | ||
|
|
||
| var dominantColors = [PlatformColor]() | ||
|
|
||
| for i in 0..<clusterCount { | ||
| let color = PlatformColor(red: CGFloat(bitmap[i * 4 + 0]) / 255.0, green: CGFloat(bitmap[i * 4 + 1]) / 255.0, blue: CGFloat(bitmap[i * 4 + 2]) / 255.0, alpha: CGFloat(bitmap[i * 4 + 3]) / 255.0) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some line breaks would be nice to have. |
||
| dominantColors.append(color) | ||
| } | ||
|
|
||
| return dominantColors | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #if canImport(UIKit) | ||
|
|
||
| import UIKit | ||
|
|
||
| extension UIImage { | ||
|
|
||
| @inlinable | ||
| public func dominantColors(clusterCount: Int = 5) -> [UIColor] { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can add a |
||
| CIImage(image: self)?.dominantColor(clusterCount: clusterCount) ?? [] | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #elseif canImport(AppKit) | ||
|
|
||
| import AppKit | ||
|
|
||
| extension NSImage { | ||
|
|
||
| public func dominantColors(clusterCount: Int = 5) -> [NSColor] { | ||
| ciImage?.dominantColor(clusterCount: clusterCount) ?? [] | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // | ||
| // Created by ktiays on 2022/10/14. | ||
| // Copyright (c) 2022 ktiays. All rights reserved. | ||
| // | ||
|
|
||
| #if canImport(AppKit) | ||
|
|
||
| import AppKit | ||
|
|
||
| extension NSImage { | ||
|
|
||
| public var ciImage: CIImage? { | ||
| guard let data = self.tiffRepresentation, | ||
| let bitmap = NSBitmapImageRep(data: data) else { | ||
| return nil | ||
| } | ||
| return CIImage(bitmapImageRep: bitmap) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| extension NSImage { | ||
|
|
||
| public convenience init(ciImage: CIImage) { | ||
| let imageRep = NSCIImageRep(ciImage: ciImage) | ||
| self.init(size: imageRep.size) | ||
| self.addRepresentation(imageRep) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we use
Image+Color.swiftas the file name to imply that this is an extension?