├── ios.png ├── mac.png ├── DominantColor ├── .gitignore ├── Mac │ ├── ExampleMac-Bridging-Header.h │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── DragAndDropImageView.swift │ ├── AppDelegate.swift │ └── Base.lproj │ │ └── MainMenu.xib ├── iOS │ ├── ExampleiOS-Bridging-Header.h │ ├── AppDelegate.swift │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── ViewController.swift │ └── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard └── Shared │ ├── DominantColor.h │ ├── Memoization.swift │ ├── INVector3SwiftExtensions.swift │ ├── Info.plist │ ├── KMeans.swift │ ├── PlatformExtensions.swift │ ├── ColorDifference.swift │ ├── ColorSpaceConversion.swift │ └── DominantColors.swift ├── DominantColor.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ ├── DominantColor-Mac.xcscheme │ │ ├── DominantColor-iOS.xcscheme │ │ ├── ExampleMac.xcscheme │ │ └── ExampleiOS.xcscheme └── project.pbxproj ├── .gitignore ├── Package.swift ├── DominantColor.podspec ├── LICENSE └── README.md /ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indragiek/DominantColor/HEAD/ios.png -------------------------------------------------------------------------------- /mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indragiek/DominantColor/HEAD/mac.png -------------------------------------------------------------------------------- /DominantColor/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | _test 4 | *.swp 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DominantColor/Mac/ExampleMac-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #include 6 | extern uint64_t dispatch_benchmark(size_t count, void (^block)(void)); 7 | -------------------------------------------------------------------------------- /DominantColor/iOS/ExampleiOS-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #include 6 | extern uint64_t dispatch_benchmark(size_t count, void (^block)(void)); 7 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | .DS_Store 20 | contents.xcworkspacedata 21 | -------------------------------------------------------------------------------- /DominantColor/iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DominantColor-iOS 4 | // 5 | // Created by Jamal E. Kharrat on 12/22/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /DominantColor/Shared/DominantColor.h: -------------------------------------------------------------------------------- 1 | // 2 | // DominantColor.h 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/22/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for DominantColor. 12 | FOUNDATION_EXPORT double DominantColorVersionNumber; 13 | 14 | //! Project version string for DominantColor. 15 | FOUNDATION_EXPORT const unsigned char DominantColorVersionString[]; 16 | -------------------------------------------------------------------------------- /DominantColor/Shared/Memoization.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Memoization.swift 3 | // DominantColor 4 | // 5 | // Created by Emmanuel Odeke on 2014-12-25. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | func memoize(_ f: @escaping (T) -> U) -> (T) -> U { 10 | var cache = [T : U]() 11 | 12 | return { key in 13 | var value = cache[key] 14 | if value == nil { 15 | value = f(key) 16 | cache[key] = value 17 | } 18 | return value! 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | /** 4 | * DominantColor 5 | * Copyright (c) Indragie Karunaratne 2021 6 | * See LICENSE file. 7 | */ 8 | 9 | import PackageDescription 10 | 11 | let package = Package( 12 | name: "DominantColor", 13 | platforms: [ 14 | .macOS(.v10_13), 15 | .iOS(.v11), 16 | .tvOS(.v11) 17 | ], 18 | products: [ 19 | .library(name: "DominantColor", targets: ["DominantColor"]), 20 | .library(name: "DominantColor_Dynamic", type: .dynamic, targets: ["DominantColor"]), 21 | ], 22 | targets: [ 23 | .target( 24 | name: "DominantColor", 25 | path: "DominantColor/Shared" 26 | ), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /DominantColor.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'DominantColor' 3 | spec.version = '0.2.2' 4 | spec.summary = 'Finding dominant colors of an image using k-means clustering.' 5 | spec.homepage = 'https://github.com/indragiek/DominantColor' 6 | spec.license = 'MIT' 7 | spec.author = { 'Indragie Karunaratne' => 'i@indragie.com' } 8 | spec.source = { :git => 'https://github.com/indragiek/DominantColor.git', :tag => spec.version.to_s } 9 | spec.source_files = 'DominantColor/Shared/*.{swift,h,m}' 10 | spec.requires_arc = true 11 | spec.frameworks = ['GameKit'] 12 | spec.ios.deployment_target = '11.0' 13 | spec.osx.deployment_target = '10.13' 14 | spec.ios.frameworks = 'UIKit' 15 | spec.osx.frameworks = 'Cocoa' 16 | spec.swift_versions = ['5.0'] 17 | end 18 | -------------------------------------------------------------------------------- /DominantColor/iOS/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /DominantColor/Shared/INVector3SwiftExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // INVector3SwiftExtensions.swift 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/24/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | import simd 10 | 11 | extension simd_float3 { 12 | func unpack() -> (Float, Float, Float) { 13 | return (x, y, z) 14 | } 15 | 16 | static var identity: simd_float3 { 17 | return simd_float3(0, 0, 0) 18 | } 19 | 20 | static func +(lhs: simd_float3, rhs: simd_float3) -> simd_float3 { 21 | return simd_float3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z) 22 | } 23 | 24 | static func /(lhs: simd_float3, rhs: Float) -> simd_float3 { 25 | return simd_float3(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs) 26 | } 27 | 28 | static func /(lhs: simd_float3, rhs: Int) -> simd_float3 { 29 | return lhs / Float(rhs) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DominantColor/Shared/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2014 Indragie Karunaratne. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Indragie Karunaratne 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /DominantColor/Mac/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /DominantColor/Mac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2014 Indragie Karunaratne. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /DominantColor/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSRequiresIPhoneOS 24 | 25 | NSPhotoLibraryUsageDescription 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /DominantColor/Mac/DragAndDropImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DragAndDropImageView.swift 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/19/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @objc protocol DragAndDropImageViewDelegate { 12 | func dragAndDropImageView(imageView: DragAndDropImageView, droppedImage image: NSImage?) 13 | } 14 | 15 | class DragAndDropImageView: NSImageView { 16 | @IBOutlet weak var delegate: DragAndDropImageViewDelegate? 17 | 18 | private let filenameType = NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType") 19 | 20 | required init?(coder: NSCoder) { 21 | super.init(coder: coder) 22 | registerForDraggedTypes([filenameType]) 23 | } 24 | 25 | private func fileURL(for pasteboard: NSPasteboard) -> URL? { 26 | if let files = pasteboard.propertyList(forType: filenameType) as? [String] { 27 | guard let filename = files.first else { return nil } 28 | 29 | return URL(fileURLWithPath: filename) 30 | } 31 | return nil 32 | } 33 | 34 | // MARK: NSDraggingDestination 35 | 36 | override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { 37 | let pasteboard = sender.draggingPasteboard 38 | if let fileURL = fileURL(for: pasteboard) { 39 | let pathExtension = fileURL.pathExtension as CFString 40 | guard let UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, nil)?.takeRetainedValue() else { return [] } 41 | return (UTTypeConformsTo(UTI, kUTTypeImage) == true) ? .copy : [] 42 | } 43 | return [] 44 | } 45 | 46 | override func performDragOperation(_ sender: NSDraggingInfo) -> Bool { 47 | let pasteboard = sender.draggingPasteboard 48 | if let fileURL = fileURL(for: pasteboard) { 49 | self.delegate?.dragAndDropImageView(imageView: self, droppedImage: NSImage(contentsOf: fileURL)) 50 | return true 51 | } 52 | return false 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DominantColor/Mac/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/18/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import DominantColor 11 | 12 | @NSApplicationMain 13 | class AppDelegate: NSObject, NSApplicationDelegate, DragAndDropImageViewDelegate { 14 | 15 | @IBOutlet weak var window: NSWindow! 16 | @IBOutlet weak var box1: NSBox! 17 | @IBOutlet weak var box2: NSBox! 18 | @IBOutlet weak var box3: NSBox! 19 | @IBOutlet weak var box4: NSBox! 20 | @IBOutlet weak var box5: NSBox! 21 | @IBOutlet weak var box6: NSBox! 22 | @IBOutlet weak var imageView: DragAndDropImageView! 23 | 24 | var image: NSImage? 25 | 26 | func applicationDidFinishLaunching(aNotification: NSNotification) { 27 | } 28 | 29 | // MARK: DragAndDropImageViewDelegate 30 | 31 | @IBAction func runBenchmark(_ sender: NSButton) { 32 | if let image = image { 33 | let nValues: [Int] = [100, 1000, 2000, 5000, 10000] 34 | let CGImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil)! 35 | for n in nValues { 36 | let ns = dispatch_benchmark(5) { 37 | _ = dominantColorsInImage(CGImage, maxSampledPixels: n) 38 | return 39 | } 40 | print("n = \(n) averaged \(ns/1000000) ms") 41 | } 42 | } 43 | } 44 | 45 | func dragAndDropImageView(imageView: DragAndDropImageView, droppedImage image: NSImage?) { 46 | if let image = image { 47 | imageView.image = image 48 | 49 | self.image = image 50 | let colors = image.dominantColors() 51 | let boxes = [box1, box2, box3, box4, box5, box6] 52 | 53 | for box in boxes { 54 | box?.fillColor = .clear 55 | } 56 | for i in 0.. [String: Any] { 70 | return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)}) 71 | } 72 | 73 | // Helper function inserted by Swift 4.2 migrator. 74 | fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String { 75 | return input.rawValue 76 | } 77 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/xcshareddata/xcschemes/DominantColor-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/xcshareddata/xcschemes/DominantColor-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/xcshareddata/xcschemes/ExampleMac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/xcshareddata/xcschemes/ExampleiOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /DominantColor/iOS/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /DominantColor/Shared/KMeans.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KMeans.swift 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/20/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | import GameKit 11 | 12 | // Represents a type that can be clustered using the k-means clustering 13 | // algorithm. 14 | protocol ClusteredType { 15 | // Used to compute average values to determine the cluster centroids. 16 | static func +(lhs: Self, rhs: Self) -> Self 17 | static func /(lhs: Self, rhs: Int) -> Self 18 | 19 | // Identity value such that x + identity = x. Typically the 0 vector. 20 | static var identity: Self { get } 21 | } 22 | 23 | struct Cluster { 24 | let centroid: T 25 | let size: Int 26 | } 27 | 28 | // k-means clustering algorithm from 29 | // http://users.eecs.northwestern.edu/~wkliao/Kmeans/ 30 | 31 | func kmeans( 32 | _ points: [T], 33 | k: Int, 34 | seed: UInt64, 35 | distance: ((T, T) -> Float), 36 | threshold: Float = 0.0001 37 | ) -> [Cluster] { 38 | 39 | let n = points.count 40 | assert(k <= n, "k cannot be larger than the total number of points") 41 | 42 | var centroids = points.randomValues(k, seed: seed) 43 | var memberships = [Int](repeating: -1, count: n) 44 | var clusterSizes = [Int](repeating: 0, count: k) 45 | 46 | var error: Float = 0 47 | var previousError: Float = 0 48 | 49 | repeat { 50 | error = 0 51 | var newCentroids = [T](repeating: T.identity, count: k) 52 | var newClusterSizes = [Int](repeating: 0, count: k) 53 | 54 | for i in 0.. 0 { 67 | centroids[i] = newCentroids[i] / size 68 | } 69 | } 70 | 71 | clusterSizes = newClusterSizes 72 | previousError = error 73 | } while abs(error - previousError) > threshold 74 | 75 | return zip(centroids, clusterSizes).map { Cluster(centroid: $0, size: $1) } 76 | } 77 | 78 | private func findNearestCluster(_ point: T, centroids: [T], k: Int, distance: (T, T) -> Float) -> Int { 79 | var minDistance = Float.infinity 80 | var clusterIndex = 0 81 | for i in 0.. [Element] { 93 | if self.isEmpty { 94 | return self 95 | } 96 | let rs = GKMersenneTwisterRandomSource() 97 | rs.seed = seed 98 | 99 | let rd = GKRandomDistribution(randomSource: rs, lowestValue: 0, highestValue: self.count - 1) 100 | 101 | var indices = [Int]() 102 | indices.reserveCapacity(num) 103 | 104 | for _ in 0.. [NSColor] { 40 | let image = cgImage(forProposedRect: nil, context: nil, hints: nil)! 41 | let colors = dominantColorsInImage(image, maxSampledPixels: maxSampledPixels, accuracy: accuracy, seed: seed, memoizeConversions: memoizeConversions) 42 | return colors.map { NSColor(cgColor: $0)! } 43 | } 44 | } 45 | 46 | #elseif os(iOS) 47 | import UIKit 48 | 49 | public extension UIImage { 50 | /** 51 | Computes the dominant colors in the receiver 52 | 53 | - parameter maxSampledPixels: Maximum number of pixels to sample in the image. If 54 | the total number of pixels in the image exceeds this 55 | value, it will be downsampled to meet the constraint. 56 | - parameter accuracy: Level of accuracy to use when grouping similar colors. 57 | Higher accuracy will come with a performance tradeoff. 58 | - parameter seed: Seed to use when choosing the initial points for grouping 59 | of similar colors. The same seed is guaranteed to return 60 | the same colors every time. 61 | - parameter memoizeConversions: Whether to memoize conversions from RGB to the LAB color 62 | space (used for grouping similar colors). Memoization 63 | will only yield better performance for large values of 64 | `maxSampledPixels` in images that are primarily comprised 65 | of flat colors. If this information about the image is 66 | not known beforehand, it is best to not memoize. 67 | 68 | - returns: A list of dominant colors in the image sorted from most dominant to 69 | least dominant. 70 | */ 71 | func dominantColors( 72 | _ maxSampledPixels: Int = DefaultParameterValues.maxSampledPixels, 73 | accuracy: GroupingAccuracy = DefaultParameterValues.accuracy, 74 | seed: UInt64 = DefaultParameterValues.seed, 75 | memoizeConversions: Bool = DefaultParameterValues.memoizeConversions 76 | ) -> [UIColor] { 77 | if let CGImage = self.cgImage { 78 | let colors = dominantColorsInImage(CGImage, maxSampledPixels: maxSampledPixels, accuracy: accuracy, seed: seed, memoizeConversions: memoizeConversions) 79 | return colors.map { UIColor(cgColor: $0) } 80 | } else { 81 | return [] 82 | } 83 | } 84 | } 85 | 86 | #endif 87 | 88 | -------------------------------------------------------------------------------- /DominantColor/Shared/ColorDifference.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorDifference.swift 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/22/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | import simd 10 | 11 | @inlinable func SIMDMathDegreesToRadians(_ degrees: Float) -> Float { 12 | return degrees * (Float.pi / 180.0) 13 | } 14 | 15 | @inlinable func SIMDMathRadiansToDegrees(_ radians: Float) -> Float { 16 | return radians * (180.0 / Float.pi) 17 | } 18 | 19 | // These functions return the squared color difference because for distance 20 | // calculations it doesn't matter and saves an unnecessary computation. 21 | 22 | // From http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE76.html 23 | func CIE76SquaredColorDifference(_ lab1: simd_float3, lab2: simd_float3) -> Float { 24 | let (L1, a1, b1) = lab1.unpack() 25 | let (L2, a2, b2) = lab2.unpack() 26 | 27 | return pow(L2 - L1, 2) + pow(a2 - a1, 2) + pow(b2 - b1, 2) 28 | } 29 | 30 | private func C(_ a: Float, b: Float) -> Float { 31 | return sqrt(pow(a, 2) + pow(b, 2)) 32 | } 33 | 34 | // From http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE94.html 35 | func CIE94SquaredColorDifference( 36 | _ kL: Float = 1, 37 | kC: Float = 1, 38 | kH: Float = 1, 39 | K1: Float = 0.045, 40 | K2: Float = 0.015 41 | ) -> (_ lab1:simd_float3, _ lab2:simd_float3) -> Float { 42 | 43 | return { (lab1:simd_float3, lab2:simd_float3) -> Float in 44 | 45 | let (L1, a1, b1) = lab1.unpack() 46 | let (L2, a2, b2) = lab2.unpack() 47 | let ΔL = L1 - L2 48 | 49 | let (C1, C2) = (C(a1, b: b1), C(a2, b: b2)) 50 | let ΔC = C1 - C2 51 | 52 | let ΔH = sqrt(pow(a1 - a2, 2) + pow(b1 - b2, 2) - pow(ΔC, 2)) 53 | 54 | let Sl: Float = 1 55 | let Sc = 1 + K1 * C1 56 | let Sh = 1 + K2 * C1 57 | 58 | return pow(ΔL / (kL * Sl), 2) + pow(ΔC / (kC * Sc), 2) + pow(ΔH / (kH * Sh), 2) 59 | } 60 | } 61 | 62 | // From http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html 63 | func CIE2000SquaredColorDifference( 64 | _ kL: Float = 1, 65 | kC: Float = 1, 66 | kH: Float = 1 67 | ) -> (_ lab1:simd_float3, _ lab2:simd_float3) -> Float { 68 | 69 | return { (lab1:simd_float3, lab2:simd_float3) -> Float in 70 | let (L1, a1, b1) = lab1.unpack() 71 | let (L2, a2, b2) = lab2.unpack() 72 | 73 | let ΔLp = L2 - L1 74 | let Lbp = (L1 + L2) / 2 75 | 76 | let (C1, C2) = (C(a1, b: b1), C(a2, b: b2)) 77 | let Cb = (C1 + C2) / 2 78 | 79 | let G = (1 - sqrt(pow(Cb, 7) / (pow(Cb, 7) + pow(25, 7)))) / 2 80 | let ap: (Float) -> Float = { a in 81 | return a * (1 + G) 82 | } 83 | let (a1p, a2p) = (ap(a1), ap(a2)) 84 | 85 | let (C1p, C2p) = (C(a1p, b: b1), C(a2p, b: b2)) 86 | let ΔCp = C2p - C1p 87 | let Cbp = (C1p + C2p) / 2 88 | 89 | let hp: (Float, Float) -> Float = { ap, b in 90 | if ap == 0 && b == 0 { return 0 } 91 | let θ = SIMDMathRadiansToDegrees(atan2(b, ap)) 92 | return fmod(θ < 0 ? (θ + 360) : θ, 360) 93 | } 94 | let (h1p, h2p) = (hp(a1p, b1), hp(a2p, b2)) 95 | let Δhabs = abs(h1p - h2p) 96 | let Δhp: Float = { 97 | if (C1p == 0 || C2p == 0) { 98 | return 0 99 | } else if Δhabs <= 180 { 100 | return h2p - h1p 101 | } else if h2p <= h1p { 102 | return h2p - h1p + 360 103 | } else { 104 | return h2p - h1p - 360 105 | } 106 | }() 107 | 108 | let ΔHp = 2 * sqrt(C1p * C2p) * sin(SIMDMathDegreesToRadians(Δhp / 2)) 109 | let Hbp: Float = { 110 | if (C1p == 0 || C2p == 0) { 111 | return h1p + h2p 112 | } else if Δhabs > 180 { 113 | return (h1p + h2p + 360) / 2 114 | } else { 115 | return (h1p + h2p) / 2 116 | } 117 | }() 118 | 119 | var T = 1 120 | - 0.17 * cos(SIMDMathDegreesToRadians(Hbp - 30)) 121 | + 0.24 * cos(SIMDMathDegreesToRadians(2 * Hbp)) 122 | 123 | T = T 124 | + 0.32 * cos(SIMDMathDegreesToRadians(3 * Hbp + 6)) 125 | - 0.20 * cos(SIMDMathDegreesToRadians(4 * Hbp - 63)) 126 | 127 | let Sl = 1 + (0.015 * pow(Lbp - 50, 2)) / sqrt(20 + pow(Lbp - 50, 2)) 128 | let Sc = 1 + 0.045 * Cbp 129 | let Sh = 1 + 0.015 * Cbp * T 130 | 131 | let Δθ = 30 * exp(-pow((Hbp - 275) / 25, 2)) 132 | let Rc = 2 * sqrt(pow(Cbp, 7) / (pow(Cbp, 7) + pow(25, 7))) 133 | let Rt = -Rc * sin(SIMDMathDegreesToRadians(2 * Δθ)) 134 | 135 | let Lterm = ΔLp / (kL * Sl) 136 | let Cterm = ΔCp / (kC * Sc) 137 | let Hterm = ΔHp / (kH * Sh) 138 | return pow(Lterm, 2) + pow(Cterm, 2) + pow(Hterm, 2) + Rt * Cterm * Hterm 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /DominantColor/Shared/ColorSpaceConversion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorSpaceConversion.swift 3 | // DominantColor 4 | // 5 | // Created by Jernej Strasner on 2/5/19. 6 | // Copyright © 2019 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | #if os(iOS) || os(tvOS) 10 | import UIKit 11 | #elseif os(OSX) 12 | import AppKit 13 | #endif 14 | 15 | import simd 16 | 17 | // MARK: - RGB 18 | 19 | func RGBToSRGB(_ rgbVector: simd_float3) -> simd_float3 { 20 | #if os(iOS) || os(tvOS) 21 | return rgbVector 22 | #elseif os(OSX) 23 | let rgbColor = NSColor(deviceRed: CGFloat(rgbVector.x), green: CGFloat(rgbVector.y), blue: CGFloat(rgbVector.z), alpha: 1.0) 24 | guard let srgbColor = rgbColor.usingColorSpace(.sRGB) else { 25 | fatalError("Could not convert color space") 26 | } 27 | return simd_float3(Float(srgbColor.redComponent), Float(srgbColor.greenComponent), Float(srgbColor.blueComponent)) 28 | #endif 29 | } 30 | 31 | func SRGBToRGB(_ srgbVector: simd_float3) -> simd_float3 { 32 | #if os(iOS) || os(tvOS) 33 | return srgbVector 34 | #elseif os(OSX) 35 | let components: [CGFloat] = [CGFloat(srgbVector.x), CGFloat(srgbVector.y), CGFloat(srgbVector.z), 1.0] 36 | let srgbColor = NSColor(colorSpace: .sRGB, components: components, count: 4) 37 | guard let rgbColor = srgbColor.usingColorSpace(.deviceRGB) else { 38 | fatalError("Could not convert color space") 39 | } 40 | return simd_float3(Float(rgbColor.redComponent), Float(rgbColor.greenComponent), Float(rgbColor.blueComponent)) 41 | #endif 42 | } 43 | 44 | // MARK: - SRGB 45 | 46 | func SRGBToLinearSRGB(_ srgbVector: simd_float3) -> simd_float3 { 47 | func f(_ c: Float) -> Float { 48 | if (c <= 0.04045) { 49 | return c / 12.92 50 | } else { 51 | return powf((c + 0.055) / 1.055, 2.4) 52 | } 53 | } 54 | return simd_float3(f(srgbVector.x), f(srgbVector.y), f(srgbVector.z)) 55 | } 56 | 57 | func LinearSRGBToSRGB(_ lSrgbVector: simd_float3) -> simd_float3 { 58 | func f(_ c: Float) -> Float { 59 | if (c <= 0.0031308) { 60 | return c * 12.92 61 | } else { 62 | return (1.055 * powf(c, 1.0 / 2.4)) - 0.055 63 | } 64 | }; 65 | return simd_float3(f(lSrgbVector.x), f(lSrgbVector.y), f(lSrgbVector.z)); 66 | } 67 | 68 | // MARK: - XYZ (CIE 1931) 69 | // http://en.wikipedia.org/wiki/CIE_1931_color_space#Construction_of_the_CIE_XYZ_color_space_from_the_Wright.E2.80.93Guild_data 70 | 71 | let LinearSRGBToXYZMatrix = simd_float3x3([ 72 | SIMD3(0.4124, 0.2126, 0.0193), 73 | SIMD3(0.3576, 0.7152, 0.1192), 74 | SIMD3(0.1805, 0.0722, 0.9505) 75 | ]) 76 | 77 | func LinearSRGBToXYZ(_ linearSrgbVector: simd_float3) -> simd_float3 { 78 | let unscaledXYZVector = LinearSRGBToXYZMatrix * linearSrgbVector 79 | return unscaledXYZVector * 100.0 80 | } 81 | 82 | let XYZToLinearSRGBMatrix = simd_float3x3([ 83 | SIMD3(3.2406, -0.9689, 0.0557), 84 | SIMD3(-1.5372, 1.8758, -0.2040), 85 | SIMD3(-0.4986, 0.0415, 1.0570) 86 | ]) 87 | 88 | func XYZToLinearSRGB(_ xyzVector: simd_float3) -> simd_float3 { 89 | let scaledXYZVector = xyzVector / 100.0 90 | return XYZToLinearSRGBMatrix * scaledXYZVector 91 | } 92 | 93 | 94 | // MARK: - LAB 95 | // http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions 96 | 97 | func XYZToLAB(_ xyzVector: simd_float3, _ tristimulus: simd_float3) -> simd_float3 { 98 | func f(_ t: Float) -> Float { 99 | if (t > powf(6.0 / 29.0, 3.0)) { 100 | return powf(t, 1.0 / 3.0) 101 | } else { 102 | return ((1.0 / 3.0) * powf(29.0 / 6.0, 2.0) * t) + (4.0 / 29.0) 103 | } 104 | }; 105 | let fx = f(xyzVector.x / tristimulus.x) 106 | let fy = f(xyzVector.y / tristimulus.y) 107 | let fz = f(xyzVector.z / tristimulus.z) 108 | 109 | let l = (116.0 * fy) - 16.0 110 | let a = 500 * (fx - fy) 111 | let b = 200 * (fy - fz) 112 | 113 | return simd_float3(l, a, b) 114 | } 115 | 116 | func LABToXYZ(_ labVector: simd_float3, _ tristimulus: simd_float3) -> simd_float3 { 117 | func f(_ t: Float) -> Float { 118 | if (t > (6.0 / 29.0)) { 119 | return powf(t, 3.0) 120 | } else { 121 | return 3.0 * powf(6.0 / 29.0, 2.0) * (t - (4.0 / 29.0)) 122 | } 123 | }; 124 | let c = (1.0 / 116.0) * (labVector.x + 16.0) 125 | 126 | let y = tristimulus.y * f(c) 127 | let x = tristimulus.x * f(c + ((1.0 / 500.0) * labVector.y)) 128 | let z = tristimulus.z * f(c - ((1.0 / 200.0) * labVector.z)) 129 | 130 | return simd_float3(x, y, z) 131 | } 132 | 133 | // MARK: - Public 134 | 135 | // From http://www.easyrgb.com/index.php?X=MATH&H=15#text15 136 | let D65Tristimulus = simd_float3(95.047, 100.0, 108.883) 137 | 138 | func IN_RGBToLAB(_ gVector: simd_float3) -> simd_float3 { 139 | let srgbVector = RGBToSRGB(gVector) 140 | let lSrgbVector = SRGBToLinearSRGB(srgbVector) 141 | let xyzVector = LinearSRGBToXYZ(lSrgbVector) 142 | let labVector = XYZToLAB(xyzVector, D65Tristimulus) 143 | return labVector 144 | } 145 | 146 | func IN_LABToRGB(_ gVector: simd_float3) -> simd_float3 { 147 | let xyzVector = LABToXYZ(gVector, D65Tristimulus) 148 | let lSrgbVector = XYZToLinearSRGB(xyzVector) 149 | let srgbVector = LinearSRGBToSRGB(lSrgbVector) 150 | let rgbVector = SRGBToRGB(srgbVector) 151 | return rgbVector 152 | } 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DominantColor 2 | 3 | Finding the dominant colors of an image using the CIE LAB color space and the k-means clustering algorithm. 4 | 5 | ### Algorithm 6 | 7 | #### Color Space 8 | 9 | The RGB color space does not take human perception into account, so the CIELAB color space is used instead, which is designed to approximate human vision [[1]](http://en.wikipedia.org/wiki/Lab_color_space#Advantages). 10 | 11 | ##### Conversion from RGB 12 | 13 | The conversion from RGB values to LAB values requires first transforming the RGB values to an absolute color space like sRGB[[2]](http://en.wikipedia.org/wiki/Lab_color_space#RGB_and_CMYK_conversions). On iOS, this conversion is not necessary because sRGB is the native device color space[[3]](https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGColorSpace/index.html). On OS X, the conversion can be performed using [`-[NSColorSpace sRGBColorSpace]`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSColorSpace_Class/index.html). 14 | 15 | Once the colors have been converted to sRGB, they are first converted to linear sRGB values and then to CIE XYZ values[[4]](http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29). Finally, they are converted to the CIE LAB color space[[5]](http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions) using a D65 standard illuminant[[6]](http://en.wikipedia.org/wiki/Illuminant_D65)[[7]](http://www.easyrgb.com/index.php?X=MATH&H=15#text15). 16 | 17 | #### Color Difference 18 | 19 | A color difference algorithm is used to group similar colors. API consumers can choose between the CIE 76[[8]](http://en.wikipedia.org/wiki/Color_difference#CIE76), CIE 94[[9]](http://en.wikipedia.org/wiki/Color_difference#CIE94), and CIE 2000[[10]](http://en.wikipedia.org/wiki/Color_difference#CIEDE2000) algorithms for low, medium, and high color grouping accuracy, respectively. The default algorithm is CIE 94, as it provides results that are close to CIE 2000 with a negligible performance impact in comparison to CIE 76. 20 | 21 | #### Clustering (k-means) 22 | 23 | Pixels are grouped into clusters of dominant colors using a standard k-means clustering algorithm[[11](http://en.wikipedia.org/wiki/K-means_clustering)][[12](http://users.eecs.northwestern.edu/~wkliao/Kmeans/)][[13](http://cs.smu.ca/~r_zhang/code/kmeans.c)]. 24 | 25 | ##### Choosing K 26 | 27 | The k-value was originally chosen based on the rule of thumb `k = sqrt(n/2)`[[14](http://en.wikipedia.org/wiki/Determining_the_number_of_clusters_in_a_data_set#cite_note-1)] but this resulted in `k`-values that were too large to run in a reasonable amount of time for large values of `n`. Right now, I'm using a magic value of `16` because empirical testing showed that it yielded the best results for many different images but I'm still looking into a number of more data-driven alternate approaches. 28 | 29 | ##### Selecting Initial Centroids 30 | 31 | The initial centroids are currently selected on a random basis. An alternative approach is to use the [k-means++ algorithm](http://en.wikipedia.org/wiki/K-means%2B%2B), in which after the first centroid is selected randomly, the subsequent centroids are selected with probability proportional to the distance from the randomly selected centroid. 32 | 33 | #### Downsampling 34 | 35 | The k-means algorithm has a worst case runtime that is super-polynomial in the input size[[15](http://en.wikipedia.org/wiki/K-means%2B%2B)], so sampling large numbers of pixels is a problem. Images are automatically downsampled such that the total number of pixels is less than or equal to a specified maximum number of pixels to sample. The value I've been using is `1000`, which is a good balance between accurate results and runtime. 36 | 37 | ### Implementation 38 | 39 | Everything is implemented in Swift except for the functions that convert between color spaces, which use GLKit and thus must be written in C (since Swift doesn't support C unions at this time). 40 | 41 | ### Apps 42 | 43 | The project includes Mac and iOS apps that can be used to see the results of the algorithm and to run a simple benchmark. 44 | 45 | ![Mac app](mac.png) 46 | ![iOS app](ios.png) 47 | 48 | ### Contact 49 | 50 | * Indragie Karunaratne 51 | * [@indragie](http://twitter.com/indragie) 52 | * [http://indragie.com](http://indragie.com) 53 | 54 | ### License 55 | 56 | Licensed under the MIT License. 57 | 58 | ### References 59 | 60 | 1 [http://en.wikipedia.org/wiki/Lab_color_space#Advantages](http://en.wikipedia.org/wiki/Lab_color_space#Advantages) 61 | 2 [http://en.wikipedia.org/wiki/Lab_color_space#RGB_and_CMYK_conversions](http://en.wikipedia.org/wiki/Lab_color_space#RGB_and_CMYK_conversions) 62 | 3 [https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGColorSpace/index.html](https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGColorSpace/index.html) 63 | 4 [http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29](http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29) 64 | 5 [http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions](http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions) 65 | 6 [http://en.wikipedia.org/wiki/Illuminant_D65](http://en.wikipedia.org/wiki/Illuminant_D65) 66 | 7 [http://www.easyrgb.com/index.php?X=MATH&H=15#text15](http://www.easyrgb.com/index.php?X=MATH&H=15#text15) 67 | 8 [http://en.wikipedia.org/wiki/Color_difference#CIE76](http://en.wikipedia.org/wiki/Color_difference#CIE76) 68 | 9 [http://en.wikipedia.org/wiki/Color_difference#CIEDE2000](http://en.wikipedia.org/wiki/Color_difference#CIE94) 69 | 10 [http://en.wikipedia.org/wiki/Color_difference#CIEDE2000](http://en.wikipedia.org/wiki/Color_difference#CIEDE2000) 70 | 11 [http://en.wikipedia.org/wiki/K-means_clustering](http://en.wikipedia.org/wiki/K-means_clustering) 71 | 12 [http://users.eecs.northwestern.edu/~wkliao/Kmeans/](http://users.eecs.northwestern.edu/~wkliao/Kmeans/) 72 | 13 [http://cs.smu.ca/~r_zhang/code/kmeans.c](http://cs.smu.ca/~r_zhang/code/kmeans.c) 73 | 14 [http://en.wikipedia.org/wiki/Determining_the_number_of_clusters_in_a_data_set#cite_note-1](http://en.wikipedia.org/wiki/Determining_the_number_of_clusters_in_a_data_set#cite_note-1) 74 | 15 [http://en.wikipedia.org/wiki/K-means%2B%2B](http://en.wikipedia.org/wiki/K-means%2B%2B) -------------------------------------------------------------------------------- /DominantColor/Shared/DominantColors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DominantColors.swift 3 | // DominantColor 4 | // 5 | // Created by Indragie on 12/20/14. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | 9 | #if os(OSX) 10 | import Foundation 11 | #elseif os(iOS) 12 | import UIKit 13 | #endif 14 | 15 | import CoreGraphics 16 | import simd 17 | 18 | // MARK: Bitmaps 19 | 20 | private struct RGBAPixel { 21 | let r: UInt8 22 | let g: UInt8 23 | let b: UInt8 24 | let a: UInt8 25 | } 26 | 27 | extension RGBAPixel: Hashable { 28 | func hash(into hasher: inout Hasher) { 29 | hasher.combine(r) 30 | hasher.combine(g) 31 | hasher.combine(b) 32 | } 33 | } 34 | 35 | private func ==(lhs: RGBAPixel, rhs: RGBAPixel) -> Bool { 36 | return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b 37 | } 38 | 39 | private func createRGBAContext(_ width: Int, height: Int) -> CGContext { 40 | return CGContext( 41 | data: nil, 42 | width: width, 43 | height: height, 44 | bitsPerComponent: 8, // bits per component 45 | bytesPerRow: width * 4, // bytes per row 46 | space: CGColorSpaceCreateDeviceRGB(), 47 | bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).rawValue 48 | )! 49 | } 50 | 51 | // Enumerates over all of the pixels in an RGBA bitmap context 52 | // in the order that they are stored in memory, for faster access. 53 | // 54 | // From: https://www.mikeash.com/pyblog/friday-qa-2012-08-31-obtaining-and-interpreting-image-data.html 55 | private func enumerateRGBAContext(_ context: CGContext, handler: (Int, Int, RGBAPixel) -> Void) { 56 | let (width, height) = (context.width, context.height) 57 | let data = unsafeBitCast(context.data, to: UnsafeMutablePointer.self) 58 | for y in 0.. CGColor { 68 | return CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [CGFloat(rgbVector.x), CGFloat(rgbVector.y), CGFloat(rgbVector.z), 1.0])! 69 | } 70 | 71 | private extension RGBAPixel { 72 | func toRGBVector() -> simd_float3 { 73 | return simd_float3( 74 | Float(r) / Float(UInt8.max), 75 | Float(g) / Float(UInt8.max), 76 | Float(b) / Float(UInt8.max) 77 | ) 78 | } 79 | } 80 | 81 | // MARK: Clustering 82 | 83 | extension simd_float3 : ClusteredType {} 84 | 85 | // MARK: Main 86 | 87 | public enum GroupingAccuracy { 88 | case low // CIE 76 - Euclidian distance 89 | case medium // CIE 94 - Perceptual non-uniformity corrections 90 | case high // CIE 2000 - Additional corrections for neutral colors, lightness, chroma, and hue 91 | } 92 | 93 | public struct DefaultParameterValues { 94 | public static var maxSampledPixels: Int = 1000 95 | public static var accuracy: GroupingAccuracy = .medium 96 | public static var seed: UInt64 = 3571 97 | public static var memoizeConversions: Bool = false 98 | } 99 | 100 | /** 101 | Computes the dominant colors in an image 102 | 103 | - parameter image: The image 104 | - parameter maxSampledPixels: Maximum number of pixels to sample in the image. If 105 | the total number of pixels in the image exceeds this 106 | value, it will be downsampled to meet the constraint. 107 | - parameter accuracy: Level of accuracy to use when grouping similar colors. 108 | Higher accuracy will come with a performance tradeoff. 109 | - parameter seed: Seed to use when choosing the initial points for grouping 110 | of similar colors. The same seed is guaranteed to return 111 | the same colors every time. 112 | - parameter memoizeConversions: Whether to memoize conversions from RGB to the LAB color 113 | space (used for grouping similar colors). Memoization 114 | will only yield better performance for large values of 115 | `maxSampledPixels` in images that are primarily comprised 116 | of flat colors. If this information about the image is 117 | not known beforehand, it is best to not memoize. 118 | 119 | - returns: A list of dominant colors in the image sorted from most dominant to 120 | least dominant. 121 | */ 122 | public func dominantColorsInImage( 123 | _ image: CGImage, 124 | maxSampledPixels: Int = DefaultParameterValues.maxSampledPixels, 125 | accuracy: GroupingAccuracy = DefaultParameterValues.accuracy, 126 | seed: UInt64 = DefaultParameterValues.seed, 127 | memoizeConversions: Bool = DefaultParameterValues.memoizeConversions 128 | ) -> [CGColor] { 129 | 130 | let (width, height) = (image.width, image.height) 131 | let (scaledWidth, scaledHeight) = scaledDimensionsForPixelLimit(maxSampledPixels, width: width, height: height) 132 | 133 | // Downsample the image if necessary, so that the total number of 134 | // pixels sampled does not exceed the specified maximum. 135 | let context = createRGBAContext(scaledWidth, height: scaledHeight) 136 | context.draw(image, in: CGRect(x: 0, y: 0, width: Int(scaledWidth), height: Int(scaledHeight))) 137 | 138 | // Get the RGB colors from the bitmap context, ignoring any pixels 139 | // that have alpha transparency. 140 | // Also convert the colors to the LAB color space 141 | var labValues = [simd_float3]() 142 | labValues.reserveCapacity(Int(scaledWidth * scaledHeight)) 143 | 144 | let RGBToLAB: (RGBAPixel) -> simd_float3 = { 145 | let f: (RGBAPixel) -> simd_float3 = { IN_RGBToLAB($0.toRGBVector()) } 146 | return memoizeConversions ? memoize(f) : f 147 | }() 148 | enumerateRGBAContext(context) { (_, _, pixel) in 149 | if pixel.a == UInt8.max { 150 | labValues.append(RGBToLAB(pixel)) 151 | } 152 | } 153 | // Cluster the colors using the k-means algorithm 154 | let k = selectKForElements(labValues) 155 | var clusters = kmeans(labValues, k: k, seed: seed, distance: distanceForAccuracy(accuracy)) 156 | 157 | // Sort the clusters by size in descending order so that the 158 | // most dominant colors come first. 159 | clusters.sort { $0.size > $1.size } 160 | 161 | return clusters.map { RGBVectorToCGColor(IN_LABToRGB($0.centroid)) } 162 | } 163 | 164 | private func distanceForAccuracy(_ accuracy: GroupingAccuracy) -> (simd_float3, simd_float3) -> Float { 165 | switch accuracy { 166 | case .low: 167 | return CIE76SquaredColorDifference 168 | case .medium: 169 | return CIE94SquaredColorDifference() 170 | case .high: 171 | return CIE2000SquaredColorDifference() 172 | } 173 | } 174 | 175 | // Computes the proportionally scaled dimensions such that the 176 | // total number of pixels does not exceed the specified limit. 177 | private func scaledDimensionsForPixelLimit(_ limit: Int, width: Int, height: Int) -> (Int, Int) { 178 | if (width * height > limit) { 179 | let ratio = Float(width) / Float(height) 180 | let maxWidth = sqrtf(ratio * Float(limit)) 181 | return (Int(maxWidth), Int(Float(limit) / maxWidth)) 182 | } 183 | return (width, height) 184 | } 185 | 186 | private func selectKForElements(_ elements: [T]) -> Int { 187 | // Seems like a magic number... 188 | return 16 189 | } 190 | -------------------------------------------------------------------------------- /DominantColor/iOS/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /DominantColor.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 194EDC4F220AB84C00B4EE26 /* ColorSpaceConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194EDC4E220AB84C00B4EE26 /* ColorSpaceConversion.swift */; }; 11 | 194EDC50220AB84C00B4EE26 /* ColorSpaceConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194EDC4E220AB84C00B4EE26 /* ColorSpaceConversion.swift */; }; 12 | 2F3D09861A4C212A001ED0BF /* Memoization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3D09851A4C212A001ED0BF /* Memoization.swift */; }; 13 | 2F3D09871A4C212A001ED0BF /* Memoization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3D09851A4C212A001ED0BF /* Memoization.swift */; }; 14 | 723DE5291A4934E200C357E3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5261A4934E200C357E3 /* AppDelegate.swift */; }; 15 | 723DE52A1A4934E200C357E3 /* DragAndDropImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5271A4934E200C357E3 /* DragAndDropImageView.swift */; }; 16 | 723DE52B1A4934E200C357E3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 723DE5281A4934E200C357E3 /* Images.xcassets */; }; 17 | 723DE52E1A4934F800C357E3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 723DE52C1A4934F800C357E3 /* MainMenu.xib */; }; 18 | 723DE54D1A49353C00C357E3 /* DominantColor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 723DE5361A49353C00C357E3 /* DominantColor.framework */; }; 19 | 723DE54E1A49353C00C357E3 /* DominantColor.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 723DE5361A49353C00C357E3 /* DominantColor.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 20 | 723DE5591A49358F00C357E3 /* DominantColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 723DE5581A49358F00C357E3 /* DominantColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | 723DE55C1A49360F00C357E3 /* ColorDifference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5141A49348D00C357E3 /* ColorDifference.swift */; }; 22 | 723DE55D1A49361100C357E3 /* DominantColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5171A49348D00C357E3 /* DominantColors.swift */; }; 23 | 723DE55E1A49361200C357E3 /* KMeans.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE51A1A49348D00C357E3 /* KMeans.swift */; }; 24 | 723DE5691A49385C00C357E3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5661A49385C00C357E3 /* AppDelegate.swift */; }; 25 | 723DE56A1A49385C00C357E3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 723DE5671A49385C00C357E3 /* Images.xcassets */; }; 26 | 723DE56B1A49385C00C357E3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5681A49385C00C357E3 /* ViewController.swift */; }; 27 | 723DE5701A49386B00C357E3 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 723DE56C1A49386B00C357E3 /* LaunchScreen.xib */; }; 28 | 723DE5711A49386B00C357E3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 723DE56E1A49386B00C357E3 /* Main.storyboard */; }; 29 | 723DE5B61A4938DD00C357E3 /* DominantColor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 723DE59F1A4938DD00C357E3 /* DominantColor.framework */; }; 30 | 723DE5B71A4938DD00C357E3 /* DominantColor.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 723DE59F1A4938DD00C357E3 /* DominantColor.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 31 | 723DE5C01A49395A00C357E3 /* DominantColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 723DE5581A49358F00C357E3 /* DominantColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32 | 723DE5C31A49399E00C357E3 /* ColorDifference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5141A49348D00C357E3 /* ColorDifference.swift */; }; 33 | 723DE5C41A4939A000C357E3 /* DominantColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE5171A49348D00C357E3 /* DominantColors.swift */; }; 34 | 723DE5C51A4939A200C357E3 /* KMeans.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723DE51A1A49348D00C357E3 /* KMeans.swift */; }; 35 | 72431C0F1A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72431C0E1A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift */; }; 36 | 72431C101A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72431C0E1A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift */; }; 37 | 724C2DCD1A4CD64600472402 /* PlatformExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 724C2DCC1A4CD64600472402 /* PlatformExtensions.swift */; }; 38 | 724C2DCE1A4CD64600472402 /* PlatformExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 724C2DCC1A4CD64600472402 /* PlatformExtensions.swift */; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXContainerItemProxy section */ 42 | 723DE54B1A49353C00C357E3 /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 72D797B01A43F44D00D32E7C /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 723DE5351A49353C00C357E3; 47 | remoteInfo = DominantColor; 48 | }; 49 | 723DE5B41A4938DD00C357E3 /* PBXContainerItemProxy */ = { 50 | isa = PBXContainerItemProxy; 51 | containerPortal = 72D797B01A43F44D00D32E7C /* Project object */; 52 | proxyType = 1; 53 | remoteGlobalIDString = 723DE59E1A4938DD00C357E3; 54 | remoteInfo = DominantColor; 55 | }; 56 | /* End PBXContainerItemProxy section */ 57 | 58 | /* Begin PBXCopyFilesBuildPhase section */ 59 | 723DE5521A49353C00C357E3 /* Embed Frameworks */ = { 60 | isa = PBXCopyFilesBuildPhase; 61 | buildActionMask = 2147483647; 62 | dstPath = ""; 63 | dstSubfolderSpec = 10; 64 | files = ( 65 | 723DE54E1A49353C00C357E3 /* DominantColor.framework in Embed Frameworks */, 66 | ); 67 | name = "Embed Frameworks"; 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 723DE5921A4938B500C357E3 /* Embed Frameworks */ = { 71 | isa = PBXCopyFilesBuildPhase; 72 | buildActionMask = 2147483647; 73 | dstPath = ""; 74 | dstSubfolderSpec = 10; 75 | files = ( 76 | 723DE5B71A4938DD00C357E3 /* DominantColor.framework in Embed Frameworks */, 77 | ); 78 | name = "Embed Frameworks"; 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXCopyFilesBuildPhase section */ 82 | 83 | /* Begin PBXFileReference section */ 84 | 194EDC4E220AB84C00B4EE26 /* ColorSpaceConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorSpaceConversion.swift; sourceTree = ""; }; 85 | 2F3D09851A4C212A001ED0BF /* Memoization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Memoization.swift; sourceTree = ""; }; 86 | 723DE5141A49348D00C357E3 /* ColorDifference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorDifference.swift; sourceTree = ""; }; 87 | 723DE5171A49348D00C357E3 /* DominantColors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DominantColors.swift; sourceTree = ""; }; 88 | 723DE51A1A49348D00C357E3 /* KMeans.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KMeans.swift; sourceTree = ""; }; 89 | 723DE5261A4934E200C357E3 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Mac/AppDelegate.swift; sourceTree = ""; }; 90 | 723DE5271A4934E200C357E3 /* DragAndDropImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DragAndDropImageView.swift; path = Mac/DragAndDropImageView.swift; sourceTree = ""; }; 91 | 723DE5281A4934E200C357E3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Mac/Images.xcassets; sourceTree = ""; }; 92 | 723DE52D1A4934F800C357E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Mac/Base.lproj/MainMenu.xib; sourceTree = ""; }; 93 | 723DE52F1A49350000C357E3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Mac/Info.plist; sourceTree = ""; }; 94 | 723DE5361A49353C00C357E3 /* DominantColor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DominantColor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 95 | 723DE5561A49357D00C357E3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Shared/Info.plist; sourceTree = ""; }; 96 | 723DE5581A49358F00C357E3 /* DominantColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DominantColor.h; sourceTree = ""; }; 97 | 723DE5641A4937AD00C357E3 /* ExampleMac-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ExampleMac-Bridging-Header.h"; path = "Mac/ExampleMac-Bridging-Header.h"; sourceTree = ""; }; 98 | 723DE5661A49385C00C357E3 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = DominantColor/iOS/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 99 | 723DE5671A49385C00C357E3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = DominantColor/iOS/Images.xcassets; sourceTree = SOURCE_ROOT; }; 100 | 723DE5681A49385C00C357E3 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = DominantColor/iOS/ViewController.swift; sourceTree = SOURCE_ROOT; }; 101 | 723DE56D1A49386B00C357E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = DominantColor/iOS/Base.lproj/LaunchScreen.xib; sourceTree = SOURCE_ROOT; }; 102 | 723DE56F1A49386B00C357E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = DominantColor/iOS/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; }; 103 | 723DE5721A49387800C357E3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = DominantColor/iOS/Info.plist; sourceTree = SOURCE_ROOT; }; 104 | 723DE5741A49388400C357E3 /* ExampleiOS-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ExampleiOS-Bridging-Header.h"; path = "DominantColor/iOS/ExampleiOS-Bridging-Header.h"; sourceTree = SOURCE_ROOT; }; 105 | 723DE59F1A4938DD00C357E3 /* DominantColor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DominantColor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 106 | 723DE5BE1A49394D00C357E3 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/GLKit.framework; sourceTree = DEVELOPER_DIR; }; 107 | 72431C0E1A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = INVector3SwiftExtensions.swift; sourceTree = ""; }; 108 | 724C2DCC1A4CD64600472402 /* PlatformExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlatformExtensions.swift; sourceTree = ""; }; 109 | 72D797B81A43F44D00D32E7C /* ExampleMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleMac.app; sourceTree = BUILT_PRODUCTS_DIR; }; 110 | 72D797DE1A43F89000D32E7C /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; 111 | 898845D21A490CE000003EF2 /* ExampleiOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleiOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | /* End PBXFileReference section */ 113 | 114 | /* Begin PBXFrameworksBuildPhase section */ 115 | 723DE5321A49353C00C357E3 /* Frameworks */ = { 116 | isa = PBXFrameworksBuildPhase; 117 | buildActionMask = 2147483647; 118 | files = ( 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | 723DE59B1A4938DD00C357E3 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | 72D797B51A43F44D00D32E7C /* Frameworks */ = { 130 | isa = PBXFrameworksBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | 723DE54D1A49353C00C357E3 /* DominantColor.framework in Frameworks */, 134 | ); 135 | runOnlyForDeploymentPostprocessing = 0; 136 | }; 137 | 898845CF1A490CE000003EF2 /* Frameworks */ = { 138 | isa = PBXFrameworksBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | 723DE5B61A4938DD00C357E3 /* DominantColor.framework in Frameworks */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXFrameworksBuildPhase section */ 146 | 147 | /* Begin PBXGroup section */ 148 | 723DE5131A49348D00C357E3 /* Shared */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 723DE5581A49358F00C357E3 /* DominantColor.h */, 152 | 723DE5141A49348D00C357E3 /* ColorDifference.swift */, 153 | 723DE5171A49348D00C357E3 /* DominantColors.swift */, 154 | 72431C0E1A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift */, 155 | 723DE51A1A49348D00C357E3 /* KMeans.swift */, 156 | 2F3D09851A4C212A001ED0BF /* Memoization.swift */, 157 | 724C2DCC1A4CD64600472402 /* PlatformExtensions.swift */, 158 | 194EDC4E220AB84C00B4EE26 /* ColorSpaceConversion.swift */, 159 | 723DE5381A49353C00C357E3 /* Supporting Files */, 160 | ); 161 | name = Shared; 162 | path = DominantColor/Shared; 163 | sourceTree = ""; 164 | }; 165 | 723DE5381A49353C00C357E3 /* Supporting Files */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 723DE5561A49357D00C357E3 /* Info.plist */, 169 | ); 170 | name = "Supporting Files"; 171 | path = ..; 172 | sourceTree = ""; 173 | }; 174 | 72B92ADA1A44CCCD00A2C24C /* Frameworks */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 723DE5BE1A49394D00C357E3 /* GLKit.framework */, 178 | 72D797DE1A43F89000D32E7C /* GLKit.framework */, 179 | ); 180 | name = Frameworks; 181 | path = DominantColor; 182 | sourceTree = ""; 183 | }; 184 | 72D797AF1A43F44D00D32E7C = { 185 | isa = PBXGroup; 186 | children = ( 187 | 723DE5131A49348D00C357E3 /* Shared */, 188 | 72D797BA1A43F44D00D32E7C /* Mac */, 189 | 898845D31A490CE000003EF2 /* iOS */, 190 | 72B92ADA1A44CCCD00A2C24C /* Frameworks */, 191 | 72D797B91A43F44D00D32E7C /* Products */, 192 | ); 193 | sourceTree = ""; 194 | }; 195 | 72D797B91A43F44D00D32E7C /* Products */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 72D797B81A43F44D00D32E7C /* ExampleMac.app */, 199 | 898845D21A490CE000003EF2 /* ExampleiOS.app */, 200 | 723DE5361A49353C00C357E3 /* DominantColor.framework */, 201 | 723DE59F1A4938DD00C357E3 /* DominantColor.framework */, 202 | ); 203 | name = Products; 204 | sourceTree = ""; 205 | }; 206 | 72D797BA1A43F44D00D32E7C /* Mac */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 723DE5261A4934E200C357E3 /* AppDelegate.swift */, 210 | 723DE5271A4934E200C357E3 /* DragAndDropImageView.swift */, 211 | 723DE5641A4937AD00C357E3 /* ExampleMac-Bridging-Header.h */, 212 | 723DE5281A4934E200C357E3 /* Images.xcassets */, 213 | 723DE52C1A4934F800C357E3 /* MainMenu.xib */, 214 | 72D797BB1A43F44D00D32E7C /* Supporting Files */, 215 | ); 216 | name = Mac; 217 | path = DominantColor; 218 | sourceTree = ""; 219 | }; 220 | 72D797BB1A43F44D00D32E7C /* Supporting Files */ = { 221 | isa = PBXGroup; 222 | children = ( 223 | 723DE52F1A49350000C357E3 /* Info.plist */, 224 | ); 225 | name = "Supporting Files"; 226 | sourceTree = ""; 227 | }; 228 | 898845D31A490CE000003EF2 /* iOS */ = { 229 | isa = PBXGroup; 230 | children = ( 231 | 723DE5661A49385C00C357E3 /* AppDelegate.swift */, 232 | 723DE5681A49385C00C357E3 /* ViewController.swift */, 233 | 723DE5741A49388400C357E3 /* ExampleiOS-Bridging-Header.h */, 234 | 723DE5671A49385C00C357E3 /* Images.xcassets */, 235 | 723DE56C1A49386B00C357E3 /* LaunchScreen.xib */, 236 | 723DE56E1A49386B00C357E3 /* Main.storyboard */, 237 | 898845D41A490CE000003EF2 /* Supporting Files */, 238 | ); 239 | name = iOS; 240 | path = "DominantColor-iOS"; 241 | sourceTree = ""; 242 | }; 243 | 898845D41A490CE000003EF2 /* Supporting Files */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | 723DE5721A49387800C357E3 /* Info.plist */, 247 | ); 248 | name = "Supporting Files"; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXGroup section */ 252 | 253 | /* Begin PBXHeadersBuildPhase section */ 254 | 723DE5331A49353C00C357E3 /* Headers */ = { 255 | isa = PBXHeadersBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | 723DE5591A49358F00C357E3 /* DominantColor.h in Headers */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | 723DE59C1A4938DD00C357E3 /* Headers */ = { 263 | isa = PBXHeadersBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | 723DE5C01A49395A00C357E3 /* DominantColor.h in Headers */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXHeadersBuildPhase section */ 271 | 272 | /* Begin PBXNativeTarget section */ 273 | 723DE5351A49353C00C357E3 /* DominantColor-Mac */ = { 274 | isa = PBXNativeTarget; 275 | buildConfigurationList = 723DE54F1A49353C00C357E3 /* Build configuration list for PBXNativeTarget "DominantColor-Mac" */; 276 | buildPhases = ( 277 | 723DE5311A49353C00C357E3 /* Sources */, 278 | 723DE5321A49353C00C357E3 /* Frameworks */, 279 | 723DE5331A49353C00C357E3 /* Headers */, 280 | 723DE5341A49353C00C357E3 /* Resources */, 281 | ); 282 | buildRules = ( 283 | ); 284 | dependencies = ( 285 | ); 286 | name = "DominantColor-Mac"; 287 | productName = DominantColor; 288 | productReference = 723DE5361A49353C00C357E3 /* DominantColor.framework */; 289 | productType = "com.apple.product-type.framework"; 290 | }; 291 | 723DE59E1A4938DD00C357E3 /* DominantColor-iOS */ = { 292 | isa = PBXNativeTarget; 293 | buildConfigurationList = 723DE5B81A4938DD00C357E3 /* Build configuration list for PBXNativeTarget "DominantColor-iOS" */; 294 | buildPhases = ( 295 | 723DE59A1A4938DD00C357E3 /* Sources */, 296 | 723DE59B1A4938DD00C357E3 /* Frameworks */, 297 | 723DE59C1A4938DD00C357E3 /* Headers */, 298 | 723DE59D1A4938DD00C357E3 /* Resources */, 299 | ); 300 | buildRules = ( 301 | ); 302 | dependencies = ( 303 | ); 304 | name = "DominantColor-iOS"; 305 | productName = DominantColor; 306 | productReference = 723DE59F1A4938DD00C357E3 /* DominantColor.framework */; 307 | productType = "com.apple.product-type.framework"; 308 | }; 309 | 72D797B71A43F44D00D32E7C /* ExampleMac */ = { 310 | isa = PBXNativeTarget; 311 | buildConfigurationList = 72D797D21A43F44D00D32E7C /* Build configuration list for PBXNativeTarget "ExampleMac" */; 312 | buildPhases = ( 313 | 72D797B41A43F44D00D32E7C /* Sources */, 314 | 72D797B51A43F44D00D32E7C /* Frameworks */, 315 | 72D797B61A43F44D00D32E7C /* Resources */, 316 | 723DE5521A49353C00C357E3 /* Embed Frameworks */, 317 | ); 318 | buildRules = ( 319 | ); 320 | dependencies = ( 321 | 723DE54C1A49353C00C357E3 /* PBXTargetDependency */, 322 | ); 323 | name = ExampleMac; 324 | productName = DominantColor; 325 | productReference = 72D797B81A43F44D00D32E7C /* ExampleMac.app */; 326 | productType = "com.apple.product-type.application"; 327 | }; 328 | 898845D11A490CE000003EF2 /* ExampleiOS */ = { 329 | isa = PBXNativeTarget; 330 | buildConfigurationList = 898845F21A490CE000003EF2 /* Build configuration list for PBXNativeTarget "ExampleiOS" */; 331 | buildPhases = ( 332 | 898845CE1A490CE000003EF2 /* Sources */, 333 | 898845CF1A490CE000003EF2 /* Frameworks */, 334 | 898845D01A490CE000003EF2 /* Resources */, 335 | 723DE5921A4938B500C357E3 /* Embed Frameworks */, 336 | ); 337 | buildRules = ( 338 | ); 339 | dependencies = ( 340 | 723DE5B51A4938DD00C357E3 /* PBXTargetDependency */, 341 | ); 342 | name = ExampleiOS; 343 | productName = "DominantColor-iOS"; 344 | productReference = 898845D21A490CE000003EF2 /* ExampleiOS.app */; 345 | productType = "com.apple.product-type.application"; 346 | }; 347 | /* End PBXNativeTarget section */ 348 | 349 | /* Begin PBXProject section */ 350 | 72D797B01A43F44D00D32E7C /* Project object */ = { 351 | isa = PBXProject; 352 | attributes = { 353 | LastSwiftMigration = 0700; 354 | LastSwiftUpdateCheck = 0700; 355 | LastUpgradeCheck = 1170; 356 | ORGANIZATIONNAME = "Indragie Karunaratne"; 357 | TargetAttributes = { 358 | 723DE5351A49353C00C357E3 = { 359 | CreatedOnToolsVersion = 6.1.1; 360 | LastSwiftMigration = 1170; 361 | }; 362 | 723DE59E1A4938DD00C357E3 = { 363 | CreatedOnToolsVersion = 6.1.1; 364 | LastSwiftMigration = 1170; 365 | }; 366 | 72D797B71A43F44D00D32E7C = { 367 | CreatedOnToolsVersion = 6.1.1; 368 | LastSwiftMigration = 1170; 369 | }; 370 | 898845D11A490CE000003EF2 = { 371 | CreatedOnToolsVersion = 6.1; 372 | LastSwiftMigration = 1170; 373 | }; 374 | }; 375 | }; 376 | buildConfigurationList = 72D797B31A43F44D00D32E7C /* Build configuration list for PBXProject "DominantColor" */; 377 | compatibilityVersion = "Xcode 3.2"; 378 | developmentRegion = en; 379 | hasScannedForEncodings = 0; 380 | knownRegions = ( 381 | en, 382 | Base, 383 | ); 384 | mainGroup = 72D797AF1A43F44D00D32E7C; 385 | productRefGroup = 72D797B91A43F44D00D32E7C /* Products */; 386 | projectDirPath = ""; 387 | projectRoot = ""; 388 | targets = ( 389 | 72D797B71A43F44D00D32E7C /* ExampleMac */, 390 | 898845D11A490CE000003EF2 /* ExampleiOS */, 391 | 723DE5351A49353C00C357E3 /* DominantColor-Mac */, 392 | 723DE59E1A4938DD00C357E3 /* DominantColor-iOS */, 393 | ); 394 | }; 395 | /* End PBXProject section */ 396 | 397 | /* Begin PBXResourcesBuildPhase section */ 398 | 723DE5341A49353C00C357E3 /* Resources */ = { 399 | isa = PBXResourcesBuildPhase; 400 | buildActionMask = 2147483647; 401 | files = ( 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | }; 405 | 723DE59D1A4938DD00C357E3 /* Resources */ = { 406 | isa = PBXResourcesBuildPhase; 407 | buildActionMask = 2147483647; 408 | files = ( 409 | ); 410 | runOnlyForDeploymentPostprocessing = 0; 411 | }; 412 | 72D797B61A43F44D00D32E7C /* Resources */ = { 413 | isa = PBXResourcesBuildPhase; 414 | buildActionMask = 2147483647; 415 | files = ( 416 | 723DE52B1A4934E200C357E3 /* Images.xcassets in Resources */, 417 | 723DE52E1A4934F800C357E3 /* MainMenu.xib in Resources */, 418 | ); 419 | runOnlyForDeploymentPostprocessing = 0; 420 | }; 421 | 898845D01A490CE000003EF2 /* Resources */ = { 422 | isa = PBXResourcesBuildPhase; 423 | buildActionMask = 2147483647; 424 | files = ( 425 | 723DE5711A49386B00C357E3 /* Main.storyboard in Resources */, 426 | 723DE5701A49386B00C357E3 /* LaunchScreen.xib in Resources */, 427 | 723DE56A1A49385C00C357E3 /* Images.xcassets in Resources */, 428 | ); 429 | runOnlyForDeploymentPostprocessing = 0; 430 | }; 431 | /* End PBXResourcesBuildPhase section */ 432 | 433 | /* Begin PBXSourcesBuildPhase section */ 434 | 723DE5311A49353C00C357E3 /* Sources */ = { 435 | isa = PBXSourcesBuildPhase; 436 | buildActionMask = 2147483647; 437 | files = ( 438 | 724C2DCD1A4CD64600472402 /* PlatformExtensions.swift in Sources */, 439 | 2F3D09861A4C212A001ED0BF /* Memoization.swift in Sources */, 440 | 194EDC4F220AB84C00B4EE26 /* ColorSpaceConversion.swift in Sources */, 441 | 723DE55C1A49360F00C357E3 /* ColorDifference.swift in Sources */, 442 | 72431C0F1A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift in Sources */, 443 | 723DE55D1A49361100C357E3 /* DominantColors.swift in Sources */, 444 | 723DE55E1A49361200C357E3 /* KMeans.swift in Sources */, 445 | ); 446 | runOnlyForDeploymentPostprocessing = 0; 447 | }; 448 | 723DE59A1A4938DD00C357E3 /* Sources */ = { 449 | isa = PBXSourcesBuildPhase; 450 | buildActionMask = 2147483647; 451 | files = ( 452 | 724C2DCE1A4CD64600472402 /* PlatformExtensions.swift in Sources */, 453 | 2F3D09871A4C212A001ED0BF /* Memoization.swift in Sources */, 454 | 194EDC50220AB84C00B4EE26 /* ColorSpaceConversion.swift in Sources */, 455 | 723DE5C31A49399E00C357E3 /* ColorDifference.swift in Sources */, 456 | 72431C101A4BCF3B00470BD7 /* INVector3SwiftExtensions.swift in Sources */, 457 | 723DE5C41A4939A000C357E3 /* DominantColors.swift in Sources */, 458 | 723DE5C51A4939A200C357E3 /* KMeans.swift in Sources */, 459 | ); 460 | runOnlyForDeploymentPostprocessing = 0; 461 | }; 462 | 72D797B41A43F44D00D32E7C /* Sources */ = { 463 | isa = PBXSourcesBuildPhase; 464 | buildActionMask = 2147483647; 465 | files = ( 466 | 723DE5291A4934E200C357E3 /* AppDelegate.swift in Sources */, 467 | 723DE52A1A4934E200C357E3 /* DragAndDropImageView.swift in Sources */, 468 | ); 469 | runOnlyForDeploymentPostprocessing = 0; 470 | }; 471 | 898845CE1A490CE000003EF2 /* Sources */ = { 472 | isa = PBXSourcesBuildPhase; 473 | buildActionMask = 2147483647; 474 | files = ( 475 | 723DE56B1A49385C00C357E3 /* ViewController.swift in Sources */, 476 | 723DE5691A49385C00C357E3 /* AppDelegate.swift in Sources */, 477 | ); 478 | runOnlyForDeploymentPostprocessing = 0; 479 | }; 480 | /* End PBXSourcesBuildPhase section */ 481 | 482 | /* Begin PBXTargetDependency section */ 483 | 723DE54C1A49353C00C357E3 /* PBXTargetDependency */ = { 484 | isa = PBXTargetDependency; 485 | target = 723DE5351A49353C00C357E3 /* DominantColor-Mac */; 486 | targetProxy = 723DE54B1A49353C00C357E3 /* PBXContainerItemProxy */; 487 | }; 488 | 723DE5B51A4938DD00C357E3 /* PBXTargetDependency */ = { 489 | isa = PBXTargetDependency; 490 | target = 723DE59E1A4938DD00C357E3 /* DominantColor-iOS */; 491 | targetProxy = 723DE5B41A4938DD00C357E3 /* PBXContainerItemProxy */; 492 | }; 493 | /* End PBXTargetDependency section */ 494 | 495 | /* Begin PBXVariantGroup section */ 496 | 723DE52C1A4934F800C357E3 /* MainMenu.xib */ = { 497 | isa = PBXVariantGroup; 498 | children = ( 499 | 723DE52D1A4934F800C357E3 /* Base */, 500 | ); 501 | name = MainMenu.xib; 502 | sourceTree = ""; 503 | }; 504 | 723DE56C1A49386B00C357E3 /* LaunchScreen.xib */ = { 505 | isa = PBXVariantGroup; 506 | children = ( 507 | 723DE56D1A49386B00C357E3 /* Base */, 508 | ); 509 | name = LaunchScreen.xib; 510 | sourceTree = ""; 511 | }; 512 | 723DE56E1A49386B00C357E3 /* Main.storyboard */ = { 513 | isa = PBXVariantGroup; 514 | children = ( 515 | 723DE56F1A49386B00C357E3 /* Base */, 516 | ); 517 | name = Main.storyboard; 518 | sourceTree = ""; 519 | }; 520 | /* End PBXVariantGroup section */ 521 | 522 | /* Begin XCBuildConfiguration section */ 523 | 723DE5501A49353C00C357E3 /* Debug */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | CODE_SIGN_IDENTITY = ""; 527 | COMBINE_HIDPI_IMAGES = YES; 528 | CURRENT_PROJECT_VERSION = 2; 529 | DEFINES_MODULE = YES; 530 | DYLIB_COMPATIBILITY_VERSION = 1; 531 | DYLIB_CURRENT_VERSION = 1; 532 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 533 | FRAMEWORK_VERSION = A; 534 | GCC_PREPROCESSOR_DEFINITIONS = ( 535 | "DEBUG=1", 536 | "$(inherited)", 537 | ); 538 | INFOPLIST_FILE = DominantColor/Shared/Info.plist; 539 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 540 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 541 | MACOSX_DEPLOYMENT_TARGET = 10.11; 542 | MARKETING_VERSION = 0.2.0; 543 | PRODUCT_BUNDLE_IDENTIFIER = "com.indragie.$(PRODUCT_NAME:rfc1034identifier)"; 544 | PRODUCT_NAME = DominantColor; 545 | SKIP_INSTALL = YES; 546 | SWIFT_OBJC_BRIDGING_HEADER = ""; 547 | SWIFT_VERSION = 5.0; 548 | VERSIONING_SYSTEM = "apple-generic"; 549 | VERSION_INFO_PREFIX = ""; 550 | }; 551 | name = Debug; 552 | }; 553 | 723DE5511A49353C00C357E3 /* Release */ = { 554 | isa = XCBuildConfiguration; 555 | buildSettings = { 556 | CODE_SIGN_IDENTITY = ""; 557 | COMBINE_HIDPI_IMAGES = YES; 558 | CURRENT_PROJECT_VERSION = 2; 559 | DEFINES_MODULE = YES; 560 | DYLIB_COMPATIBILITY_VERSION = 1; 561 | DYLIB_CURRENT_VERSION = 1; 562 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 563 | FRAMEWORK_VERSION = A; 564 | INFOPLIST_FILE = DominantColor/Shared/Info.plist; 565 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 566 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 567 | MACOSX_DEPLOYMENT_TARGET = 10.11; 568 | MARKETING_VERSION = 0.2.0; 569 | PRODUCT_BUNDLE_IDENTIFIER = "com.indragie.$(PRODUCT_NAME:rfc1034identifier)"; 570 | PRODUCT_NAME = DominantColor; 571 | SKIP_INSTALL = YES; 572 | SWIFT_OBJC_BRIDGING_HEADER = ""; 573 | SWIFT_VERSION = 5.0; 574 | VERSIONING_SYSTEM = "apple-generic"; 575 | VERSION_INFO_PREFIX = ""; 576 | }; 577 | name = Release; 578 | }; 579 | 723DE5B91A4938DD00C357E3 /* Debug */ = { 580 | isa = XCBuildConfiguration; 581 | buildSettings = { 582 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 583 | CURRENT_PROJECT_VERSION = 2; 584 | DEFINES_MODULE = YES; 585 | DYLIB_COMPATIBILITY_VERSION = 1; 586 | DYLIB_CURRENT_VERSION = 1; 587 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 588 | GCC_PREPROCESSOR_DEFINITIONS = ( 589 | "DEBUG=1", 590 | "$(inherited)", 591 | ); 592 | INFOPLIST_FILE = DominantColor/iOS/Info.plist; 593 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 594 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 595 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 596 | MARKETING_VERSION = 0.2.0; 597 | PRODUCT_BUNDLE_IDENTIFIER = "com.jamalDesigns.$(PRODUCT_NAME:rfc1034identifier)"; 598 | PRODUCT_NAME = DominantColor; 599 | SDKROOT = iphoneos; 600 | SKIP_INSTALL = YES; 601 | SWIFT_VERSION = 5.0; 602 | TARGETED_DEVICE_FAMILY = "1,2"; 603 | VERSIONING_SYSTEM = "apple-generic"; 604 | VERSION_INFO_PREFIX = ""; 605 | }; 606 | name = Debug; 607 | }; 608 | 723DE5BA1A4938DD00C357E3 /* Release */ = { 609 | isa = XCBuildConfiguration; 610 | buildSettings = { 611 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 612 | CURRENT_PROJECT_VERSION = 2; 613 | DEFINES_MODULE = YES; 614 | DYLIB_COMPATIBILITY_VERSION = 1; 615 | DYLIB_CURRENT_VERSION = 1; 616 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 617 | INFOPLIST_FILE = DominantColor/iOS/Info.plist; 618 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 619 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 620 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 621 | MARKETING_VERSION = 0.2.0; 622 | PRODUCT_BUNDLE_IDENTIFIER = "com.jamalDesigns.$(PRODUCT_NAME:rfc1034identifier)"; 623 | PRODUCT_NAME = DominantColor; 624 | SDKROOT = iphoneos; 625 | SKIP_INSTALL = YES; 626 | SWIFT_VERSION = 5.0; 627 | TARGETED_DEVICE_FAMILY = "1,2"; 628 | VALIDATE_PRODUCT = YES; 629 | VERSIONING_SYSTEM = "apple-generic"; 630 | VERSION_INFO_PREFIX = ""; 631 | }; 632 | name = Release; 633 | }; 634 | 72D797D01A43F44D00D32E7C /* Debug */ = { 635 | isa = XCBuildConfiguration; 636 | buildSettings = { 637 | ALWAYS_SEARCH_USER_PATHS = NO; 638 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 639 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 640 | CLANG_CXX_LIBRARY = "libc++"; 641 | CLANG_ENABLE_MODULES = YES; 642 | CLANG_ENABLE_OBJC_ARC = YES; 643 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 644 | CLANG_WARN_BOOL_CONVERSION = YES; 645 | CLANG_WARN_COMMA = YES; 646 | CLANG_WARN_CONSTANT_CONVERSION = YES; 647 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 648 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 649 | CLANG_WARN_EMPTY_BODY = YES; 650 | CLANG_WARN_ENUM_CONVERSION = YES; 651 | CLANG_WARN_INFINITE_RECURSION = YES; 652 | CLANG_WARN_INT_CONVERSION = YES; 653 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 654 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 655 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 656 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 657 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 658 | CLANG_WARN_STRICT_PROTOTYPES = YES; 659 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 660 | CLANG_WARN_UNREACHABLE_CODE = YES; 661 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 662 | CODE_SIGN_IDENTITY = "-"; 663 | COPY_PHASE_STRIP = NO; 664 | ENABLE_STRICT_OBJC_MSGSEND = YES; 665 | ENABLE_TESTABILITY = YES; 666 | GCC_C_LANGUAGE_STANDARD = gnu99; 667 | GCC_DYNAMIC_NO_PIC = NO; 668 | GCC_NO_COMMON_BLOCKS = YES; 669 | GCC_OPTIMIZATION_LEVEL = 0; 670 | GCC_PREPROCESSOR_DEFINITIONS = ( 671 | "DEBUG=1", 672 | "$(inherited)", 673 | ); 674 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 675 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 676 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 677 | GCC_WARN_UNDECLARED_SELECTOR = YES; 678 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 679 | GCC_WARN_UNUSED_FUNCTION = YES; 680 | GCC_WARN_UNUSED_VARIABLE = YES; 681 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 682 | MACOSX_DEPLOYMENT_TARGET = 10.11; 683 | MTL_ENABLE_DEBUG_INFO = YES; 684 | ONLY_ACTIVE_ARCH = YES; 685 | SDKROOT = macosx; 686 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 687 | SWIFT_VERSION = 4.0; 688 | }; 689 | name = Debug; 690 | }; 691 | 72D797D11A43F44D00D32E7C /* Release */ = { 692 | isa = XCBuildConfiguration; 693 | buildSettings = { 694 | ALWAYS_SEARCH_USER_PATHS = NO; 695 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 696 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 697 | CLANG_CXX_LIBRARY = "libc++"; 698 | CLANG_ENABLE_MODULES = YES; 699 | CLANG_ENABLE_OBJC_ARC = YES; 700 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 701 | CLANG_WARN_BOOL_CONVERSION = YES; 702 | CLANG_WARN_COMMA = YES; 703 | CLANG_WARN_CONSTANT_CONVERSION = YES; 704 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 705 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 706 | CLANG_WARN_EMPTY_BODY = YES; 707 | CLANG_WARN_ENUM_CONVERSION = YES; 708 | CLANG_WARN_INFINITE_RECURSION = YES; 709 | CLANG_WARN_INT_CONVERSION = YES; 710 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 711 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 712 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 713 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 714 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 715 | CLANG_WARN_STRICT_PROTOTYPES = YES; 716 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 717 | CLANG_WARN_UNREACHABLE_CODE = YES; 718 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 719 | CODE_SIGN_IDENTITY = "-"; 720 | COPY_PHASE_STRIP = NO; 721 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 722 | ENABLE_NS_ASSERTIONS = NO; 723 | ENABLE_STRICT_OBJC_MSGSEND = YES; 724 | GCC_C_LANGUAGE_STANDARD = gnu99; 725 | GCC_NO_COMMON_BLOCKS = YES; 726 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 727 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 728 | GCC_WARN_UNDECLARED_SELECTOR = YES; 729 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 730 | GCC_WARN_UNUSED_FUNCTION = YES; 731 | GCC_WARN_UNUSED_VARIABLE = YES; 732 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 733 | MACOSX_DEPLOYMENT_TARGET = 10.11; 734 | MTL_ENABLE_DEBUG_INFO = NO; 735 | SDKROOT = macosx; 736 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 737 | SWIFT_VERSION = 4.0; 738 | }; 739 | name = Release; 740 | }; 741 | 72D797D31A43F44D00D32E7C /* Debug */ = { 742 | isa = XCBuildConfiguration; 743 | buildSettings = { 744 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 745 | CLANG_ENABLE_MODULES = YES; 746 | CODE_SIGN_IDENTITY = "-"; 747 | COMBINE_HIDPI_IMAGES = YES; 748 | CURRENT_PROJECT_VERSION = 2; 749 | HEADER_SEARCH_PATHS = ( 750 | "$(inherited)", 751 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 752 | ); 753 | INFOPLIST_FILE = DominantColor/Mac/Info.plist; 754 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 755 | MACOSX_DEPLOYMENT_TARGET = 10.11; 756 | MARKETING_VERSION = 0.2.0; 757 | PRODUCT_BUNDLE_IDENTIFIER = "com.indragie.$(PRODUCT_NAME:rfc1034identifier)"; 758 | PRODUCT_NAME = "$(TARGET_NAME)"; 759 | SWIFT_OBJC_BRIDGING_HEADER = "DominantColor/Mac/ExampleMac-Bridging-Header.h"; 760 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 761 | SWIFT_VERSION = 5.0; 762 | }; 763 | name = Debug; 764 | }; 765 | 72D797D41A43F44D00D32E7C /* Release */ = { 766 | isa = XCBuildConfiguration; 767 | buildSettings = { 768 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 769 | CLANG_ENABLE_MODULES = YES; 770 | CODE_SIGN_IDENTITY = "-"; 771 | COMBINE_HIDPI_IMAGES = YES; 772 | CURRENT_PROJECT_VERSION = 2; 773 | HEADER_SEARCH_PATHS = ( 774 | "$(inherited)", 775 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 776 | ); 777 | INFOPLIST_FILE = DominantColor/Mac/Info.plist; 778 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 779 | MACOSX_DEPLOYMENT_TARGET = 10.11; 780 | MARKETING_VERSION = 0.2.0; 781 | PRODUCT_BUNDLE_IDENTIFIER = "com.indragie.$(PRODUCT_NAME:rfc1034identifier)"; 782 | PRODUCT_NAME = "$(TARGET_NAME)"; 783 | SWIFT_OBJC_BRIDGING_HEADER = "DominantColor/Mac/ExampleMac-Bridging-Header.h"; 784 | SWIFT_VERSION = 5.0; 785 | }; 786 | name = Release; 787 | }; 788 | 898845EE1A490CE000003EF2 /* Debug */ = { 789 | isa = XCBuildConfiguration; 790 | buildSettings = { 791 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 792 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 793 | CURRENT_PROJECT_VERSION = 2; 794 | GCC_PREPROCESSOR_DEFINITIONS = ( 795 | "DEBUG=1", 796 | "$(inherited)", 797 | ); 798 | INFOPLIST_FILE = DominantColor/iOS/Info.plist; 799 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 800 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 801 | MARKETING_VERSION = 0.2.0; 802 | PRODUCT_BUNDLE_IDENTIFIER = "com.jamalDesigns.$(PRODUCT_NAME:rfc1034identifier)"; 803 | PRODUCT_NAME = "$(TARGET_NAME)"; 804 | SDKROOT = iphoneos; 805 | SWIFT_OBJC_BRIDGING_HEADER = "DominantColor/iOS/ExampleiOS-Bridging-Header.h"; 806 | SWIFT_VERSION = 5.0; 807 | }; 808 | name = Debug; 809 | }; 810 | 898845EF1A490CE000003EF2 /* Release */ = { 811 | isa = XCBuildConfiguration; 812 | buildSettings = { 813 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 814 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 815 | CURRENT_PROJECT_VERSION = 2; 816 | INFOPLIST_FILE = DominantColor/iOS/Info.plist; 817 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 818 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 819 | MARKETING_VERSION = 0.2.0; 820 | PRODUCT_BUNDLE_IDENTIFIER = "com.jamalDesigns.$(PRODUCT_NAME:rfc1034identifier)"; 821 | PRODUCT_NAME = "$(TARGET_NAME)"; 822 | SDKROOT = iphoneos; 823 | SWIFT_OBJC_BRIDGING_HEADER = "DominantColor/iOS/ExampleiOS-Bridging-Header.h"; 824 | SWIFT_VERSION = 5.0; 825 | VALIDATE_PRODUCT = YES; 826 | }; 827 | name = Release; 828 | }; 829 | /* End XCBuildConfiguration section */ 830 | 831 | /* Begin XCConfigurationList section */ 832 | 723DE54F1A49353C00C357E3 /* Build configuration list for PBXNativeTarget "DominantColor-Mac" */ = { 833 | isa = XCConfigurationList; 834 | buildConfigurations = ( 835 | 723DE5501A49353C00C357E3 /* Debug */, 836 | 723DE5511A49353C00C357E3 /* Release */, 837 | ); 838 | defaultConfigurationIsVisible = 0; 839 | defaultConfigurationName = Release; 840 | }; 841 | 723DE5B81A4938DD00C357E3 /* Build configuration list for PBXNativeTarget "DominantColor-iOS" */ = { 842 | isa = XCConfigurationList; 843 | buildConfigurations = ( 844 | 723DE5B91A4938DD00C357E3 /* Debug */, 845 | 723DE5BA1A4938DD00C357E3 /* Release */, 846 | ); 847 | defaultConfigurationIsVisible = 0; 848 | defaultConfigurationName = Release; 849 | }; 850 | 72D797B31A43F44D00D32E7C /* Build configuration list for PBXProject "DominantColor" */ = { 851 | isa = XCConfigurationList; 852 | buildConfigurations = ( 853 | 72D797D01A43F44D00D32E7C /* Debug */, 854 | 72D797D11A43F44D00D32E7C /* Release */, 855 | ); 856 | defaultConfigurationIsVisible = 0; 857 | defaultConfigurationName = Release; 858 | }; 859 | 72D797D21A43F44D00D32E7C /* Build configuration list for PBXNativeTarget "ExampleMac" */ = { 860 | isa = XCConfigurationList; 861 | buildConfigurations = ( 862 | 72D797D31A43F44D00D32E7C /* Debug */, 863 | 72D797D41A43F44D00D32E7C /* Release */, 864 | ); 865 | defaultConfigurationIsVisible = 0; 866 | defaultConfigurationName = Release; 867 | }; 868 | 898845F21A490CE000003EF2 /* Build configuration list for PBXNativeTarget "ExampleiOS" */ = { 869 | isa = XCConfigurationList; 870 | buildConfigurations = ( 871 | 898845EE1A490CE000003EF2 /* Debug */, 872 | 898845EF1A490CE000003EF2 /* Release */, 873 | ); 874 | defaultConfigurationIsVisible = 0; 875 | defaultConfigurationName = Release; 876 | }; 877 | /* End XCConfigurationList section */ 878 | }; 879 | rootObject = 72D797B01A43F44D00D32E7C /* Project object */; 880 | } 881 | -------------------------------------------------------------------------------- /DominantColor/Mac/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | Default 548 | 549 | 550 | 551 | 552 | 553 | 554 | Left to Right 555 | 556 | 557 | 558 | 559 | 560 | 561 | Right to Left 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | Default 573 | 574 | 575 | 576 | 577 | 578 | 579 | Left to Right 580 | 581 | 582 | 583 | 584 | 585 | 586 | Right to Left 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | --------------------------------------------------------------------------------