) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_1.imageset/61IWOsLc2QL._SS500_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_1.imageset/61IWOsLc2QL._SS500_.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "61IWOsLc2QL._SS500_.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cri_000000319870.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_2.imageset/cri_000000319870.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_2.imageset/cri_000000319870.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Hotel-California.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_3.imageset/Hotel-California.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_3.imageset/Hotel-California.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Never_Mind_the_Bollocks,_Here's_the_Sex_Pistols.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_4.imageset/Never_Mind_the_Bollocks,_Here's_the_Sex_Pistols.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_4.imageset/Never_Mind_the_Bollocks,_Here's_the_Sex_Pistols.png
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Pink-Floyd-Dark-Side-of-the-Moon-album-covers-billboard-1000x1000-compressed.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_5.imageset/Pink-Floyd-Dark-Side-of-the-Moon-album-covers-billboard-1000x1000-compressed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_5.imageset/Pink-Floyd-Dark-Side-of-the-Moon-album-covers-billboard-1000x1000-compressed.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Tommy.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_6.imageset/Tommy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_6.imageset/Tommy.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "PetSoundsCover.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_7.imageset/PetSoundsCover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_7.imageset/PetSoundsCover.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_8.imageset/51KHXRnEG5L._SX466_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_8.imageset/51KHXRnEG5L._SX466_.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "51KHXRnEG5L._SX466_.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "iconic-80s-rap-album-covers-featuring-classic-sneakers-2.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_9.imageset/iconic-80s-rap-album-covers-featuring-classic-sneakers-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Album_cover_9.imageset/iconic-80s-rap-album-covers-featuring-classic-sneakers-2.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_20pt@2x.jpg",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "icon_20pt@3x.jpg",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "icon_29pt@2x.jpg",
17 | "idiom" : "iphone",
18 | "scale" : "2x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "icon_29pt@3x.jpg",
23 | "idiom" : "iphone",
24 | "scale" : "3x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "icon_40pt@2x.jpg",
29 | "idiom" : "iphone",
30 | "scale" : "2x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "icon_40pt@3x.jpg",
35 | "idiom" : "iphone",
36 | "scale" : "3x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "icon_60pt@2x.jpg",
41 | "idiom" : "iphone",
42 | "scale" : "2x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "filename" : "icon_60pt@3x.jpg",
47 | "idiom" : "iphone",
48 | "scale" : "3x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "idiom" : "ipad",
53 | "scale" : "1x",
54 | "size" : "20x20"
55 | },
56 | {
57 | "idiom" : "ipad",
58 | "scale" : "2x",
59 | "size" : "20x20"
60 | },
61 | {
62 | "idiom" : "ipad",
63 | "scale" : "1x",
64 | "size" : "29x29"
65 | },
66 | {
67 | "idiom" : "ipad",
68 | "scale" : "2x",
69 | "size" : "29x29"
70 | },
71 | {
72 | "idiom" : "ipad",
73 | "scale" : "1x",
74 | "size" : "40x40"
75 | },
76 | {
77 | "idiom" : "ipad",
78 | "scale" : "2x",
79 | "size" : "40x40"
80 | },
81 | {
82 | "idiom" : "ipad",
83 | "scale" : "1x",
84 | "size" : "76x76"
85 | },
86 | {
87 | "idiom" : "ipad",
88 | "scale" : "2x",
89 | "size" : "76x76"
90 | },
91 | {
92 | "idiom" : "ipad",
93 | "scale" : "2x",
94 | "size" : "83.5x83.5"
95 | },
96 | {
97 | "idiom" : "ios-marketing",
98 | "scale" : "1x",
99 | "size" : "1024x1024"
100 | }
101 | ],
102 | "info" : {
103 | "author" : "xcode",
104 | "version" : 1
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Banner.imageset/Banner@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Banner.imageset/Banner@2x.png
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Banner.imageset/Banner@3x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Banner.imageset/Banner@3x.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Banner.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "Banner@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "Banner@3x.jpg",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dominant_Color_Image_4.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_1.imageset/Dominant_Color_Image_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_1.imageset/Dominant_Color_Image_4.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dominant_Color_Image_2.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_2.imageset/Dominant_Color_Image_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_2.imageset/Dominant_Color_Image_2.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dominant_Color_Image_3.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_3.imageset/Dominant_Color_Image_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_3.imageset/Dominant_Color_Image_3.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dominant_Color_Image_1.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_4.imageset/Dominant_Color_Image_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_4.imageset/Dominant_Color_Image_1.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dominant_Color_Image_5.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_5.imageset/Dominant_Color_Image_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_5.imageset/Dominant_Color_Image_5.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dominant_Color_Image_6.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_6.imageset/Dominant_Color_Image_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitSampleApp/Assets.xcassets/Dominant_Color_Image_6.imageset/Dominant_Color_Image_6.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Base.lproj/LaunchScreen.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 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/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 |
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 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/ColorDetailViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorDetailViewController.swift
3 | // ColorKitSampleApp
4 | //
5 | // Created by Boris Emorine on 7/17/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ColorKit
11 |
12 | class ColorDetailViewController: UITableViewController {
13 |
14 | var color: UIColor!
15 |
16 | @IBOutlet weak var colorView: UIView!
17 | @IBOutlet weak var colorNameLabel: UILabel!
18 | @IBOutlet weak var rgbLabel: UILabel!
19 | @IBOutlet weak var hexLabel: UILabel!
20 | @IBOutlet weak var cielabLabel: UILabel!
21 | @IBOutlet weak var xyzLabel: UILabel!
22 | @IBOutlet weak var cmykLabel: UILabel!
23 | @IBOutlet weak var relativeLuminanceLabel: UILabel!
24 | @IBOutlet weak var complementaryColorView: UIView!
25 |
26 | override func viewDidLoad() {
27 | super.viewDidLoad()
28 |
29 | colorView.backgroundColor = color
30 | colorNameLabel.text = "Name: \(color.name())"
31 | rgbLabel.text = String(format: "Red: %.2f Green: %.2f Blue: %.2f", color.red, color.green, color.blue)
32 | hexLabel.text = "Hex: \(color.hex)"
33 | cielabLabel.text = "CIE L: \(color.L) a: \(color.a) b: \(color.b)"
34 | xyzLabel.text = "X: \(color.X) Y: \(color.Y) Z:\(color.Z)"
35 | cmykLabel.text = String(format: "C: %.2f M: %.2f Y: %.2f K: %.2f", color.cyan, color.magenta, color.yellow, color.key)
36 | relativeLuminanceLabel.text = "Relative Luminance: \(color.relativeLuminance)"
37 | complementaryColorView.backgroundColor = color.complementaryColor
38 | complementaryColorView.layer.cornerRadius = 5
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/DominantColorsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DominantColorsViewController.swift
3 | // ColorKitSampleApp
4 | //
5 | // Created by Boris Emorine on 5/31/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ColorKit
11 |
12 | class ImageColorsViewController: UIViewController {
13 |
14 | @IBOutlet private weak var scrollView: UIScrollView!
15 | @IBOutlet private weak var tableView: UITableView!
16 |
17 | private var currentImage: UIImage! {
18 | didSet {
19 | guard oldValue != currentImage else { return }
20 | do {
21 | averageColor = try currentImage.averageColor()
22 | dominantColors = try currentImage.dominantColorFrequencies()
23 | } catch {
24 | fatalError(error.localizedDescription)
25 | }
26 | }
27 | }
28 |
29 | private var dominantColors = [ColorFrequency]() {
30 | didSet {
31 | tableView.reloadData()
32 | }
33 | }
34 |
35 | private var averageColor: UIColor!
36 |
37 | private static let images = [
38 | UIImage(named: "Dominant_Color_Image_1")!,
39 | UIImage(named: "Dominant_Color_Image_2")!,
40 | UIImage(named: "Dominant_Color_Image_3")!,
41 | UIImage(named: "Dominant_Color_Image_4")!,
42 | UIImage(named: "Dominant_Color_Image_5")!,
43 | UIImage(named: "Dominant_Color_Image_6")!
44 | ]
45 |
46 | private lazy var imageViews: [UIImageView] = {
47 | return ImageColorsViewController.images.map { (image) -> UIImageView in
48 | let imageView = UIImageView(image: image)
49 | imageView.contentMode = .scaleAspectFit
50 | imageView.translatesAutoresizingMaskIntoConstraints = false
51 | return imageView
52 | }
53 | }()
54 |
55 | override func viewDidLoad() {
56 | super.viewDidLoad()
57 |
58 | tableView.dataSource = self
59 | tableView.delegate = self
60 |
61 | scrollView.delegate = self
62 | scrollView.subviews.first?.removeFromSuperview()
63 |
64 | imageViews.forEach { (imageView) in
65 | scrollView.addSubview(imageView)
66 | }
67 |
68 | currentImage = ImageColorsViewController.images.first!
69 |
70 | var constraints = [NSLayoutConstraint]()
71 |
72 | for (index, imageView) in imageViews.enumerated() {
73 | constraints += [
74 | imageView.topAnchor.constraint(equalTo: scrollView.topAnchor),
75 | imageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
76 | imageView.heightAnchor.constraint(equalTo: scrollView.heightAnchor),
77 | ]
78 | if index == 0 {
79 | constraints.append(imageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor))
80 | } else {
81 | let previousImageView = imageViews[index - 1]
82 | constraints.append(imageView.leadingAnchor.constraint(equalTo: previousImageView.trailingAnchor))
83 | }
84 |
85 | if index == imageViews.count - 1 {
86 | constraints.append(scrollView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor))
87 | }
88 | }
89 |
90 | NSLayoutConstraint.activate(constraints)
91 | }
92 |
93 | override func viewDidLayoutSubviews() {
94 | super.viewDidLayoutSubviews()
95 |
96 | scrollView.contentSize = CGSize(width: scrollView.bounds.width * CGFloat(ImageColorsViewController.images.count), height: scrollView.bounds.height)
97 | }
98 |
99 | }
100 |
101 | extension ImageColorsViewController: UITableViewDataSource {
102 |
103 | enum DominantColorsTableViewSection: Int, CaseIterable {
104 | case dominantColor = 0
105 | case averageColor = 1
106 | }
107 |
108 | func numberOfSections(in tableView: UITableView) -> Int {
109 | return DominantColorsTableViewSection.allCases.count
110 | }
111 |
112 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
113 | guard let section = DominantColorsTableViewSection(rawValue: section) else {
114 | fatalError("Could not map section to `DominantColorsTableViewSection` enum")
115 | }
116 |
117 | switch section {
118 | case .dominantColor:
119 | return dominantColors.count
120 | case .averageColor:
121 | return 1
122 | }
123 | }
124 |
125 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
126 | guard let section = DominantColorsTableViewSection(rawValue: indexPath.section) else {
127 | fatalError("Could not map section to `DominantColorsTableViewSection` enum")
128 | }
129 |
130 | let cell = UITableViewCell()
131 |
132 | switch section {
133 | case .dominantColor:
134 | let colorFrequency = dominantColors[indexPath.row]
135 | cell.backgroundColor = colorFrequency.color
136 | cell.textLabel?.text = "\(colorFrequency.frequency)"
137 | case .averageColor:
138 | cell.backgroundColor = averageColor
139 | }
140 | return cell
141 | }
142 |
143 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
144 | guard let section = DominantColorsTableViewSection(rawValue: section) else {
145 | fatalError("Could not map section to `DominantColorsTableViewSection` enum")
146 | }
147 |
148 | switch section {
149 | case .dominantColor:
150 | return "Dominant Colors"
151 | case .averageColor:
152 | return "Average Color"
153 | }
154 | }
155 |
156 | }
157 |
158 | extension ImageColorsViewController: UITableViewDelegate {
159 |
160 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
161 | performSegue(withIdentifier: "toColorDetail", sender: nil)
162 | }
163 |
164 | }
165 |
166 | extension ImageColorsViewController: UIScrollViewDelegate {
167 |
168 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
169 | let numberOfPages = imageViews.count
170 | let currentPage = Int(scrollView.contentOffset.x / (scrollView.contentSize.width / CGFloat(numberOfPages)))
171 | guard let currentImage = imageViews[currentPage].image else {
172 | fatalError("Could not find image.")
173 | }
174 |
175 | self.currentImage = currentImage
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/ImageColorsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageColorsViewController.swift
3 | // ColorKitSampleApp
4 | //
5 | // Created by Boris Emorine on 5/31/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ColorKit
11 |
12 | class ImageColorsViewController: UIViewController {
13 |
14 | @IBOutlet private weak var scrollView: UIScrollView!
15 | @IBOutlet private weak var tableView: UITableView!
16 | @IBOutlet weak var pageControl: UIPageControl!
17 |
18 | private var currentImage: UIImage! {
19 | didSet {
20 | guard oldValue != currentImage else { return }
21 | do {
22 | averageColor = try currentImage.averageColor()
23 | dominantColors = try currentImage.dominantColorFrequencies()
24 | } catch {
25 | fatalError(error.localizedDescription)
26 | }
27 | }
28 | }
29 |
30 | private var dominantColors = [ColorFrequency]() {
31 | didSet {
32 | tableView.reloadData()
33 | }
34 | }
35 |
36 | private var averageColor: UIColor!
37 |
38 | private static let images = [
39 | UIImage(named: "Dominant_Color_Image_1")!,
40 | UIImage(named: "Dominant_Color_Image_2")!,
41 | UIImage(named: "Dominant_Color_Image_3")!,
42 | UIImage(named: "Dominant_Color_Image_4")!,
43 | UIImage(named: "Dominant_Color_Image_5")!,
44 | UIImage(named: "Dominant_Color_Image_6")!
45 | ]
46 |
47 | private lazy var imageViews: [UIImageView] = {
48 | return ImageColorsViewController.images.map { (image) -> UIImageView in
49 | let imageView = UIImageView(image: image)
50 | imageView.contentMode = .scaleAspectFit
51 | imageView.translatesAutoresizingMaskIntoConstraints = false
52 | return imageView
53 | }
54 | }()
55 |
56 | override func viewDidLoad() {
57 | super.viewDidLoad()
58 |
59 | tableView.dataSource = self
60 | tableView.delegate = self
61 |
62 | scrollView.delegate = self
63 | scrollView.subviews.first?.removeFromSuperview()
64 |
65 | imageViews.forEach { (imageView) in
66 | scrollView.addSubview(imageView)
67 | }
68 |
69 | currentImage = ImageColorsViewController.images.first!
70 |
71 | var constraints = [NSLayoutConstraint]()
72 |
73 | for (index, imageView) in imageViews.enumerated() {
74 | constraints += [
75 | imageView.topAnchor.constraint(equalTo: scrollView.topAnchor),
76 | imageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
77 | imageView.heightAnchor.constraint(equalTo: scrollView.heightAnchor),
78 | ]
79 | if index == 0 {
80 | constraints.append(imageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor))
81 | } else {
82 | let previousImageView = imageViews[index - 1]
83 | constraints.append(imageView.leadingAnchor.constraint(equalTo: previousImageView.trailingAnchor))
84 | }
85 |
86 | if index == imageViews.count - 1 {
87 | constraints.append(scrollView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor))
88 | }
89 | }
90 |
91 | NSLayoutConstraint.activate(constraints)
92 | pageControl.numberOfPages = imageViews.count
93 | }
94 |
95 | override func viewDidLayoutSubviews() {
96 | super.viewDidLayoutSubviews()
97 |
98 | scrollView.contentSize = CGSize(width: scrollView.bounds.width * CGFloat(ImageColorsViewController.images.count), height: scrollView.bounds.height)
99 | }
100 |
101 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
102 | guard let colorDetailViewController = segue.destination as? ColorDetailViewController,
103 | let selectedIndexPath = tableView.indexPathForSelectedRow,
104 | let section = DominantColorsTableViewSection(rawValue: selectedIndexPath.section) else {
105 | fatalError("Failed to get requirements for segue.")
106 | }
107 |
108 | var color: UIColor
109 | switch section {
110 | case .dominantColor:
111 | color = dominantColors[selectedIndexPath.row].color
112 | case .averageColor:
113 | color = averageColor
114 | }
115 |
116 | colorDetailViewController.color = color
117 | tableView.deselectRow(at: selectedIndexPath, animated: true)
118 | }
119 |
120 | }
121 |
122 | extension ImageColorsViewController: UITableViewDataSource {
123 |
124 | enum DominantColorsTableViewSection: Int, CaseIterable {
125 | case dominantColor = 0
126 | case averageColor = 1
127 | }
128 |
129 | func numberOfSections(in tableView: UITableView) -> Int {
130 | return DominantColorsTableViewSection.allCases.count
131 | }
132 |
133 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
134 | guard let section = DominantColorsTableViewSection(rawValue: section) else {
135 | fatalError("Could not map section to `DominantColorsTableViewSection` enum")
136 | }
137 |
138 | switch section {
139 | case .dominantColor:
140 | return dominantColors.count
141 | case .averageColor:
142 | return 1
143 | }
144 | }
145 |
146 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
147 | guard let section = DominantColorsTableViewSection(rawValue: indexPath.section) else {
148 | fatalError("Could not map section to `DominantColorsTableViewSection` enum")
149 | }
150 |
151 | let cell = UITableViewCell()
152 |
153 | switch section {
154 | case .dominantColor:
155 | let colorFrequency = dominantColors[indexPath.row]
156 | cell.backgroundColor = colorFrequency.color
157 | cell.textLabel?.text = "\(colorFrequency.frequency)"
158 | case .averageColor:
159 | cell.backgroundColor = averageColor
160 | }
161 | return cell
162 | }
163 |
164 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
165 | guard let section = DominantColorsTableViewSection(rawValue: section) else {
166 | fatalError("Could not map section to `DominantColorsTableViewSection` enum")
167 | }
168 |
169 | switch section {
170 | case .dominantColor:
171 | return "Dominant Colors"
172 | case .averageColor:
173 | return "Average Color"
174 | }
175 | }
176 |
177 | }
178 |
179 | extension ImageColorsViewController: UITableViewDelegate {
180 |
181 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
182 | performSegue(withIdentifier: "toColorDetail", sender: nil)
183 | }
184 |
185 | }
186 |
187 | extension ImageColorsViewController: UIScrollViewDelegate {
188 |
189 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
190 | guard !(scrollView is UITableView) else { return }
191 | let numberOfPages = imageViews.count
192 | let currentPage = Int(scrollView.contentOffset.x / (scrollView.contentSize.width / CGFloat(numberOfPages)))
193 | guard let currentImage = imageViews[currentPage].image else {
194 | fatalError("Could not find image.")
195 | }
196 |
197 | self.currentImage = currentImage
198 | pageControl.currentPage = currentPage
199 | }
200 |
201 | }
202 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 |
54 | UISupportedInterfaceOrientations~ipad
55 |
56 | UIInterfaceOrientationPortrait
57 | UIInterfaceOrientationPortraitUpsideDown
58 | UIInterfaceOrientationLandscapeLeft
59 | UIInterfaceOrientationLandscapeRight
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/PaletteViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PaletteViewController.swift
3 | // ColorKitSampleApp
4 | //
5 | // Created by Boris Emorine on 8/26/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ColorKit
11 |
12 | class PaletteViewController: UIViewController {
13 |
14 | private struct Album {
15 | let image: UIImage
16 | let name: String
17 | let artist: String
18 | }
19 |
20 | @IBOutlet weak var titleLabel: UILabel!
21 | @IBOutlet weak var detailLabel: UILabel!
22 | @IBOutlet weak var imageView: UIImageView!
23 |
24 | private let albums = [
25 | Album(image: #imageLiteral(resourceName: "Album_cover_1"), name: "My Beautiful Dark Twisted Fantasy", artist: "Kanye West"),
26 | Album(image: #imageLiteral(resourceName: "Album_cover_2"), name: "Abbey Road", artist: "The Beatles"),
27 | Album(image: #imageLiteral(resourceName: "Album_cover_3"), name: "Hotel California", artist: "Eagles"),
28 | Album(image: #imageLiteral(resourceName: "Album_cover_4"), name: "Never Mind the Bollocks", artist: "Sex Pistols"),
29 | Album(image: #imageLiteral(resourceName: "Album_cover_5"), name: "The Dark Side of the Moon", artist: "Pink Floyd"),
30 | Album(image: #imageLiteral(resourceName: "Album_cover_6"), name: "Tommy", artist: "The Who"),
31 | Album(image: #imageLiteral(resourceName: "Album_cover_7"), name: "Pet Sounds", artist: "The Beach Boys"),
32 | Album(image: #imageLiteral(resourceName: "Album_cover_8"), name: "Modern Sounds", artist: "Ray Charles"),
33 | Album(image: #imageLiteral(resourceName: "Album_cover_9"), name: "Tougher than Leather", artist: "Run DMC")
34 | ]
35 |
36 | override func viewDidLoad() {
37 | super.viewDidLoad()
38 |
39 | imageView.layer.borderWidth = 5
40 | imageView.layer.borderColor = UIColor.black.cgColor
41 |
42 | resetView()
43 | }
44 |
45 | private func resetView() {
46 | guard let album = albums.randomElement() else {
47 | fatalError("Could not get album")
48 | }
49 |
50 | imageView.image = album.image
51 |
52 | let colors = try! album.image.dominantColors()
53 | guard let palette = ColorPalette(orderedColors: colors, ignoreContrastRatio: true) else {
54 | fatalError("Could not create palette")
55 | }
56 |
57 | view.backgroundColor = palette.background
58 |
59 | titleLabel.text = album.name
60 | titleLabel.textColor = palette.primary
61 |
62 | detailLabel.text = album.artist
63 | detailLabel.textColor = palette.secondary
64 | }
65 | @IBAction func handleTapRefresh(_ sender: Any) {
66 | resetView()
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitSampleApp/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // ColorKitSampleApp
4 | //
5 | // Created by Boris Emorine on 5/31/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/AverageColorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AverageColorTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 5/15/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class AverageColorTests: XCTestCase {
13 |
14 | static let tolerance: CGFloat = 0.5
15 |
16 | /// It should compute a green average color for a green image.
17 | func testGreenImage() throws {
18 | let bundle = Bundle(for: type(of: self))
19 | let image = UIImage(named: "Green_Square.jpg", in: bundle, compatibleWith: nil)!
20 | let averageColor = try image.averageColor()
21 |
22 | let distance = averageColor.difference(from: UIColor.green)
23 | XCTAssertLessThan(distance.associatedValue, AverageColorTests.tolerance)
24 | }
25 |
26 | /// It should compute a purple average color for a purple image.
27 | func testPurpleImage() throws {
28 | let bundle = Bundle(for: type(of: self))
29 | let image = UIImage(named: "Purple_Square.jpg", in: bundle, compatibleWith: nil)!
30 | let averageColor = try image.averageColor()
31 |
32 | let expectedPurple = UIColor(red: 208.0 / 255.0, green: 0.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0)
33 | let distance = averageColor.difference(from: expectedPurple)
34 | XCTAssertLessThan(distance.associatedValue, AverageColorTests.tolerance)
35 | }
36 |
37 | /// It should compute a gray average color for a black & white image.
38 | func testBlackWhiteImage() throws {
39 | let bundle = Bundle(for: type(of: self))
40 | let image = UIImage(named: "Black_White_Square.jpg", in: bundle, compatibleWith: nil)!
41 | let averageColor = try image.averageColor()
42 |
43 | let expectedGray = UIColor(red: 188.0 / 255.0, green: 188.0 / 255.0, blue: 188.0 / 255.0, alpha: 1.0)
44 | let distance = averageColor.difference(from: expectedGray)
45 | XCTAssertLessThan(distance.associatedValue, AverageColorTests.tolerance)
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/CGFloatExtensionsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGFloatExtensionsTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 2/26/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class CGFloatExtensionsTests: XCTestCase {
13 |
14 | func testRoundedWithPrecision10() {
15 | let sut: CGFloat = 100.39999999
16 | let roundedSut = sut.rounded(.toNearestOrEven, precision: 10)
17 | XCTAssertEqual(roundedSut, 100.4)
18 | }
19 |
20 | func testRoundedWithPrecision100() {
21 | let sut: CGFloat = 100.39999999
22 | let roundedSut = sut.rounded(.toNearestOrEven, precision: 100)
23 | XCTAssertEqual(roundedSut, 100.40)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/CGSizeExtensionsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGSizeExtensionsTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 5/30/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class CGSizeExtensionsTests: XCTestCase {
13 |
14 | /// A simple test with hard coded values where the target size is smaller than the original size.
15 | func testSimpleSmaller() {
16 | let originalSize = CGSize(width: 100, height: 100)
17 | let targetSize = originalSize.transformToFit(in: 100)
18 |
19 | let expectedSize = CGSize(width: 10, height: 10)
20 | XCTAssertEqual(targetSize, expectedSize)
21 | }
22 |
23 | /// A simple test with hard coded values where the target size is greater than the original size.
24 | func testSimpleGreater() {
25 | let originalSize = CGSize(width: 10, height: 10)
26 | let targetSize = originalSize.transformToFit(in: 10_000)
27 |
28 | let expectedSize = CGSize(width: 100, height: 100)
29 | XCTAssertEqual(targetSize, expectedSize)
30 | }
31 |
32 | /// It should return a target size with the expected area and keeping the same size ratio, when the target area is smaller than the original area.
33 | func testSmaller() {
34 | let originalSize = CGSize(width: 1024, height: 800)
35 | let targetArea: CGFloat = originalSize.area / CGFloat.random(in: 1...4)
36 | let targetSize = originalSize.transformToFit(in: targetArea)
37 |
38 | XCTAssertEqual(originalSize.width / originalSize.height, targetSize.width / targetSize.height, accuracy: 0.01)
39 | XCTAssertEqual(targetArea, targetSize.width * targetSize.height, accuracy: 0.01)
40 | }
41 |
42 | /// It should return a target size with the expected area and keeping the same size ratio, when the target area is greater than the original area.
43 | func testGreater() {
44 | let originalSize = CGSize(width: 1024, height: 800)
45 | let targetArea: CGFloat = originalSize.area * CGFloat.random(in: 1...4)
46 | let targetSize = originalSize.transformToFit(in: targetArea)
47 |
48 | XCTAssertEqual(originalSize.width / originalSize.height, targetSize.width / targetSize.height, accuracy: 0.01)
49 | XCTAssertEqual(targetArea, targetSize.width * targetSize.height, accuracy: 0.01)
50 | }
51 |
52 | /// It should return a target size with the expected area and keeping the same size ratio.
53 | func testRandom() {
54 | let originalSize = CGSize(width: CGFloat.random(in: 0...100000), height: CGFloat.random(in: 0...100000))
55 | let targetArea: CGFloat = originalSize.area * CGFloat.random(in: 0...2)
56 | let targetSize = originalSize.transformToFit(in: targetArea)
57 |
58 | XCTAssertEqual(originalSize.width / originalSize.height, targetSize.width / targetSize.height, accuracy: 0.01)
59 | XCTAssertEqual(targetArea, targetSize.width * targetSize.height, accuracy: 0.01)
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/CMYKTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CMYKTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 6/20/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class CMYKTests: XCTestCase {
13 |
14 | func testGreen() {
15 | let color = UIColor.green
16 |
17 | XCTAssertEqual(color.cyan, 1.0)
18 | XCTAssertEqual(color.magenta, 0.0)
19 | XCTAssertEqual(color.yellow, 1.0)
20 | XCTAssertEqual(color.key, 0.0)
21 | }
22 |
23 | func testBlue() {
24 | let color = UIColor.blue
25 |
26 | XCTAssertEqual(color.cyan, 1.0)
27 | XCTAssertEqual(color.magenta, 1.0)
28 | XCTAssertEqual(color.yellow, 0.0)
29 | XCTAssertEqual(color.key, 0.0)
30 | }
31 |
32 | func testWhite() {
33 | let color = UIColor.white
34 |
35 | XCTAssertEqual(color.cyan, 0.0)
36 | XCTAssertEqual(color.magenta, 0.0)
37 | XCTAssertEqual(color.yellow, 0.0)
38 | XCTAssertEqual(color.key, 0.0)
39 | }
40 |
41 | func testArbitrary() {
42 | let color = UIColor(red: 153.0 / 255.0, green: 71.0 / 255.0, blue: 206.0 / 255.0, alpha: 1.0)
43 |
44 | XCTAssertEqual(color.cyan, 0.26, accuracy: 0.01)
45 | XCTAssertEqual(color.magenta, 0.66, accuracy: 0.01)
46 | XCTAssertEqual(color.yellow, 0.0)
47 | XCTAssertEqual(color.key, 0.19, accuracy: 0.01)
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/ColorKitTests-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 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/ComparisonTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ComparisonTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 2/24/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class ComparisonTests: XCTestCase {
13 |
14 | // MARK: - Euclidean
15 |
16 | func testWhiteWhiteEuclidean() {
17 | let color1 = UIColor.white
18 | let color2 = UIColor.white
19 |
20 | let difference = color1.difference(from: color2, using: .euclidean).associatedValue
21 | XCTAssertEqual(difference, 0)
22 |
23 | let reversedDifference = color2.difference(from: color1, using: .euclidean).associatedValue
24 | XCTAssertEqual(reversedDifference, difference)
25 | }
26 |
27 | func testPurplePurpleEuclidean() {
28 | let color1 = UIColor.purple
29 | let color2 = UIColor.purple
30 |
31 | let difference = color1.difference(from: color2, using: .euclidean).associatedValue
32 | XCTAssertEqual(difference, 0)
33 |
34 | let reversedDifference = color2.difference(from: color1, using: .euclidean).associatedValue
35 | XCTAssertEqual(reversedDifference, difference)
36 | }
37 |
38 | func testWhiteBlackEuclidean() {
39 | let color1 = UIColor.white
40 | let color2 = UIColor.black
41 |
42 | let difference = color1.difference(from: color2, using: .euclidean).associatedValue
43 | XCTAssertEqual(difference, 441.67)
44 |
45 | let reversedDifference = color2.difference(from: color1, using: .euclidean).associatedValue
46 | XCTAssertEqual(reversedDifference, difference)
47 | }
48 |
49 | func testRandomEuclidean() {
50 | let color1 = UIColor(red: 76.5 / 255.0, green: 127.5 / 255.0, blue: 178.5 / 255.0, alpha: 1.0)
51 | let color2 = UIColor(red: 127.5 / 255.0, green: 25.5 / 255.0, blue: 51.0 / 255.0, alpha: 1.0)
52 |
53 | let difference = color1.difference(from: color2, using: .euclidean).associatedValue
54 | XCTAssertEqual(difference, 171.06)
55 |
56 | let reversedDifference = color2.difference(from: color1, using: .euclidean).associatedValue
57 | XCTAssertEqual(reversedDifference, difference)
58 | }
59 |
60 | func testCloseEuclidean() {
61 | let color1 = UIColor(red: 196.0 / 255.0, green: 199.0 / 255.0, blue: 46.0 / 255.0, alpha: 1.0)
62 | let color2 = UIColor(red: 171.0 / 255.0, green: 173.0 / 255.0, blue: 50.0 / 255.0, alpha: 1.0)
63 |
64 | let difference = color1.difference(from: color2, using: .euclidean).associatedValue
65 | XCTAssertEqual(difference, 36.29)
66 |
67 | let reversedDifference = color2.difference(from: color1, using: .euclidean).associatedValue
68 | XCTAssertEqual(reversedDifference, difference)
69 | }
70 |
71 | // MARK: - CIE76
72 |
73 | func testWhiteWhiteCIE76() {
74 | let color1 = UIColor.white
75 | let color2 = UIColor.white
76 |
77 | let difference = color1.difference(from: color2, using: .CIE76).associatedValue
78 | XCTAssertEqual(difference, 0)
79 |
80 | let reversedDifference = color2.difference(from: color1, using: .CIE76).associatedValue
81 | XCTAssertEqual(reversedDifference, difference)
82 | }
83 |
84 | func testPurplePurpleCIE76() {
85 | let color1 = UIColor.purple
86 | let color2 = UIColor.purple
87 |
88 | let difference = color1.difference(from: color2, using: .CIE76).associatedValue
89 | XCTAssertEqual(difference, 0)
90 |
91 | let reversedDifference = color2.difference(from: color1, using: .CIE76).associatedValue
92 | XCTAssertEqual(reversedDifference, difference)
93 | }
94 |
95 | func testWhiteBlackCIE76() {
96 | let color1 = UIColor.white
97 | let color2 = UIColor.black
98 |
99 | let difference = color1.difference(from: color2, using: .CIE76).associatedValue
100 | XCTAssertEqual(difference, 100.0)
101 |
102 | let reversedDifference = color2.difference(from: color1, using: .CIE76).associatedValue
103 | XCTAssertEqual(reversedDifference, difference)
104 | }
105 |
106 | func testRandomCIE76() {
107 | let color1 = UIColor(red: 76.5 / 255.0, green: 127.5 / 255.0, blue: 178.5 / 255.0, alpha: 1.0)
108 | let color2 = UIColor(red: 127.5 / 255.0, green: 25.5 / 255.0, blue: 51.0 / 255.0, alpha: 1.0)
109 |
110 | let difference = color1.difference(from: color2, using: .CIE76).associatedValue
111 | XCTAssertEqual(difference, 67.55)
112 |
113 | let reversedDifference = color2.difference(from: color1, using: .CIE76).associatedValue
114 | XCTAssertEqual(reversedDifference, difference)
115 | }
116 |
117 | func testCloseCIE76() {
118 | let color1 = UIColor(red: 196.0 / 255.0, green: 199.0 / 255.0, blue: 46.0 / 255.0, alpha: 1.0)
119 | let color2 = UIColor(red: 171.0 / 255.0, green: 173.0 / 255.0, blue: 50.0 / 255.0, alpha: 1.0)
120 |
121 | let difference = color1.difference(from: color2, using: .CIE76).associatedValue
122 | XCTAssertEqual(difference, 14.25)
123 |
124 | let reversedDifference = color2.difference(from: color1, using: .CIE76).associatedValue
125 | XCTAssertEqual(reversedDifference, difference)
126 | }
127 |
128 | // MARK: - CIE94
129 |
130 | func testWhiteWhiteCIE94() {
131 | let color1 = UIColor.white
132 | let color2 = UIColor.white
133 |
134 | let difference = color1.difference(from: color2, using: .CIE94).associatedValue
135 | XCTAssertEqual(difference, 0)
136 |
137 | let reversedDifference = color2.difference(from: color1, using: .CIE94).associatedValue
138 | XCTAssertEqual(reversedDifference, difference)
139 | }
140 |
141 | func testPurplePurpleCIE94() {
142 | let color1 = UIColor.purple
143 | let color2 = UIColor.purple
144 |
145 | let difference = color1.difference(from: color2, using: .CIE94).associatedValue
146 | XCTAssertEqual(difference, 0)
147 |
148 | let reversedDifference = color2.difference(from: color1, using: .CIE94).associatedValue
149 | XCTAssertEqual(reversedDifference, difference)
150 | }
151 |
152 | func testWhiteBlackCIE94() {
153 | let color1 = UIColor.white
154 | let color2 = UIColor.black
155 |
156 | let difference = color1.difference(from: color2, using: .CIE94).associatedValue
157 | XCTAssertEqual(difference, 100.0)
158 |
159 | let reversedDifference = color2.difference(from: color1, using: .CIE94).associatedValue
160 | XCTAssertEqual(reversedDifference, difference)
161 | }
162 |
163 | func testRandomCIE94() {
164 | let color1 = UIColor(red: 76.5 / 255.0, green: 127.5 / 255.0, blue: 178.5 / 255.0, alpha: 1.0)
165 | let color2 = UIColor(red: 127.5 / 255.0, green: 25.5 / 255.0, blue: 51.0 / 255.0, alpha: 1.0)
166 |
167 | let difference = color1.difference(from: color2, using: .CIE94).associatedValue
168 | XCTAssertEqual(difference, 48.31)
169 |
170 | let reversedDifference = color2.difference(from: color1, using: .CIE94).associatedValue
171 | XCTAssertEqual(reversedDifference, 43.99)
172 | }
173 |
174 | func testCloseCIE94() {
175 | let color1 = UIColor(red: 196.0 / 255.0, green: 199.0 / 255.0, blue: 46.0 / 255.0, alpha: 1.0)
176 | let color2 = UIColor(red: 171.0 / 255.0, green: 173.0 / 255.0, blue: 50.0 / 255.0, alpha: 1.0)
177 |
178 | let difference = color1.difference(from: color2, using: .CIE94).associatedValue
179 | XCTAssertEqual(difference, 9.5)
180 |
181 | let reversedDifference = color2.difference(from: color1, using: .CIE94).associatedValue
182 | XCTAssertEqual(reversedDifference, 9.6)
183 | }
184 |
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/ComplementaryColorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ComplementaryColorTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 3/18/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ColorKit
11 |
12 | class ComplementaryColorTests: XCTestCase {
13 |
14 | func testBlack() {
15 | let black = UIColor.black
16 | let complementaryColor = black.complementaryColor
17 | XCTAssertEqual(complementaryColor, UIColor(red: 1, green: 1, blue: 1, alpha: 1.0))
18 | }
19 |
20 | func testWhite() {
21 | let white = UIColor.white
22 | let complementaryColor = white.complementaryColor
23 | XCTAssertEqual(complementaryColor, UIColor(red: 0, green: 0, blue: 0, alpha: 1.0))
24 | }
25 |
26 | func testBlue() {
27 | let blue = UIColor.blue
28 | let complementaryColor = blue.complementaryColor
29 | XCTAssertEqual(complementaryColor, UIColor(red: 255.0 / 255.0, green: 255.0 / 255.0, blue: 0, alpha: 1.0))
30 | }
31 |
32 | func testYellow() {
33 | let yellow = UIColor(red: 255.0 / 255.0, green: 255.0 / 255.0, blue: 0, alpha: 1.0)
34 | let complementaryColor = yellow.complementaryColor
35 | XCTAssertEqual(complementaryColor, UIColor.blue)
36 | }
37 |
38 | func testRed() {
39 | let red = UIColor.red
40 | let complementaryColor = red.complementaryColor
41 | XCTAssertEqual(complementaryColor, UIColor(red: 0.0 / 255.0, green: 255.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0))
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/ContrastRatioTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContrastRatioTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 3/13/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class ContrastRatioTests: XCTestCase {
13 |
14 | func testBlackWhite() {
15 | let color = UIColor.white
16 | let backgroundColor = UIColor.black
17 | let contrastRatioResult = color.contrastRatio(with: backgroundColor)
18 | XCTAssertEqual(contrastRatioResult.associatedValue, 21.0)
19 | }
20 |
21 | func testWhiteBlack() {
22 | let color = UIColor.black
23 | let backgroundColor = UIColor.white
24 | let contrastRatioResult = color.contrastRatio(with: backgroundColor)
25 | XCTAssertEqual(contrastRatioResult.associatedValue, 21.0)
26 | }
27 |
28 | func testOrangeOrangeClose() {
29 | let color = UIColor(red: 243.0 / 255.0, green: 120.0 / 255.0, blue: 9.0 / 255.0, alpha: 1.0)
30 | let backgroundColor = UIColor(red: 222.0 / 255.0, green: 100.0 / 255.0, blue: 10.0 / 255.0, alpha: 1.0)
31 | let contrastRatioResult = color.contrastRatio(with: backgroundColor)
32 | XCTAssertEqual(contrastRatioResult.associatedValue, 1.26)
33 | }
34 |
35 | func testOrangeOrange() {
36 | let color = UIColor(red: 243.0 / 255.0, green: 120.0 / 255.0, blue: 9.0 / 255.0, alpha: 1.0)
37 | let backgroundColor = UIColor(red: 243.0 / 255.0, green: 120.0 / 255.0, blue: 9.0 / 255.0, alpha: 1.0)
38 | let contrastRatioResult = color.contrastRatio(with: backgroundColor)
39 | XCTAssertEqual(contrastRatioResult.associatedValue, 1.0)
40 | }
41 |
42 | func testGreenPurple() {
43 | let green = UIColor(red: 0.0 / 255.0, green: 255.0 / 255.0, blue: 0.0 / 255.0, alpha: 1.0)
44 | let blue = UIColor(red: 0.0 / 255.0, green: 0.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0)
45 | let contrastRatioResult = green.contrastRatio(with: blue)
46 | XCTAssertEqual(contrastRatioResult.associatedValue, 6.27)
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/DominantColorQualityTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DominantColorQualityTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 5/30/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class DominantColorQualityTests: XCTestCase {
13 |
14 | /// It should return the exact same size (original size) if the quality is set to best.
15 | func testBestQuality() {
16 | let quality = UIImage.DominantColorQuality.best
17 | let originalSize = CGSize(width: CGFloat.random(in: 0...10000), height: CGFloat.random(in: 0...10000))
18 | let targetSize = quality.targetSize(for: originalSize)
19 |
20 | XCTAssertEqual(targetSize, originalSize)
21 | }
22 |
23 | /// It should return the exact same size (original size) if the original size is smaller than the size we're trying to reach.
24 | func testLowerArea() {
25 | let quality = UIImage.DominantColorQuality.fair
26 | let originalSize = CGSize(width: 1, height: 1)
27 | let targetSize = quality.targetSize(for: originalSize)
28 |
29 | XCTAssertEqual(targetSize, originalSize)
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/DominantColorsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DominantColorsTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 5/19/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class DominantColorsTests: XCTestCase {
13 |
14 | func testGreenImage() throws {
15 | let bundle = Bundle(for: type(of: self))
16 | let image = UIImage(named: "Green_Square.jpg", in: bundle, compatibleWith: nil)!
17 | let dominantColors = try image.dominantColorFrequencies(with: .best)
18 |
19 | XCTAssertEqual(dominantColors.count, 1)
20 | guard let distance = dominantColors.first?.color.difference(from: UIColor.green) else {
21 | XCTFail("Could not get distance from dominant color.")
22 | return
23 | }
24 | XCTAssertLessThan(distance.associatedValue, AverageColorTests.tolerance)
25 | XCTAssertEqual(dominantColors.first?.frequency, 1.0)
26 | }
27 |
28 | func testBlackWhiteImage() throws {
29 | let bundle = Bundle(for: type(of: self))
30 | let image = UIImage(named: "Black_White_Square.jpg", in: bundle, compatibleWith: nil)!
31 | let colorFrequencies = try image.dominantColorFrequencies(with: .best)
32 | let dominantColors = colorFrequencies.map({ $0.color })
33 |
34 | XCTAssertEqual(dominantColors.count, 2)
35 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 0, blue: 0, alpha: 1)))
36 | XCTAssertTrue(dominantColors.contains(UIColor(red: 1, green: 1, blue: 1, alpha: 1)))
37 | verifySorted(colorsFrequencies: colorFrequencies)
38 |
39 | XCTAssertEqual(colorFrequencies.first?.frequency, 0.5)
40 | XCTAssertEqual(colorFrequencies[1].frequency, 0.5)
41 | }
42 |
43 | func testRedBlueGreenImage() throws {
44 | let bundle = Bundle(for: type(of: self))
45 | let image = UIImage(named: "Red_Green_Blue.png", in: bundle, compatibleWith: nil)!
46 | let colorFrequencies = try image.dominantColorFrequencies(with: .best)
47 | let dominantColors = colorFrequencies.map({ $0.color })
48 |
49 | XCTAssertEqual(dominantColors.count, 3)
50 | XCTAssertTrue(dominantColors.contains(UIColor(red: 1, green: 0, blue: 0, alpha: 1)))
51 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 1, blue: 0, alpha: 1)))
52 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 0, blue: 1, alpha: 1)))
53 | verifySorted(colorsFrequencies: colorFrequencies)
54 | }
55 |
56 | func testRedBlueGreenBlack() throws {
57 | let bundle = Bundle(for: type(of: self))
58 | let image = UIImage(named: "Red_Green_Blue_Black_Mini.png", in: bundle, compatibleWith: nil)!
59 | let colorFrequencies = try image.dominantColorFrequencies(with: .best)
60 | let dominantColors = colorFrequencies.map({ $0.color })
61 |
62 | XCTAssertEqual(dominantColors.count, 4)
63 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 0, blue: 0, alpha: 1)))
64 | XCTAssertTrue(dominantColors.contains(UIColor(red: 1, green: 0, blue: 0, alpha: 1)))
65 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 1, blue: 0, alpha: 1)))
66 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 0, blue: 1, alpha: 1)))
67 | verifySorted(colorsFrequencies: colorFrequencies)
68 | }
69 |
70 | func testRedBlueGreenRandom() throws {
71 | let bundle = Bundle(for: type(of: self))
72 | let image = UIImage(named: "Red_Green_Blue_Random_Mini.png", in: bundle, compatibleWith: nil)!
73 | let colorFrequencies = try image.dominantColorFrequencies(with: .best)
74 | let dominantColors = colorFrequencies.map({ $0.color })
75 |
76 | XCTAssertTrue(dominantColors.contains(UIColor(red: 1, green: 0, blue: 0, alpha: 1)))
77 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 1, blue: 0, alpha: 1)))
78 | XCTAssertTrue(dominantColors.contains(UIColor(red: 0, green: 0, blue: 1, alpha: 1)))
79 | verifySorted(colorsFrequencies: colorFrequencies)
80 | }
81 |
82 | func verifySorted(colorsFrequencies: [ColorFrequency]) {
83 | var previousCount: CGFloat?
84 |
85 | colorsFrequencies.forEach { (colorFrequency) in
86 | guard let oldCount = previousCount else {
87 | previousCount = colorFrequency.frequency
88 | return
89 | }
90 |
91 | if oldCount < colorFrequency.frequency {
92 | XCTFail("The order of the color frenquecy is not correct.")
93 | }
94 |
95 | previousCount = colorFrequency.frequency
96 | }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/HexTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HexTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 2/27/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class HexTests: XCTestCase {
13 |
14 | private let blackHex = "#000000"
15 | private let whiteHex = "#ffffff"
16 | private let redHex = "#ff0000"
17 | private let darkGreen = "#32a852"
18 | private let lightGreen = "#43ff64d9"
19 |
20 | // Init
21 |
22 | func testInitBlack() {
23 | let color = UIColor(hex: blackHex)!
24 | XCTAssertEqual(color.red, 0)
25 | XCTAssertEqual(color.green, 0)
26 | XCTAssertEqual(color.blue, 0)
27 | XCTAssertEqual(color.alpha, 1)
28 | }
29 |
30 | func testInitWhite() {
31 | let color = UIColor(hex: whiteHex)!
32 | XCTAssertEqual(color.red, 1)
33 | XCTAssertEqual(color.green, 1)
34 | XCTAssertEqual(color.blue, 1)
35 | XCTAssertEqual(color.alpha, 1)
36 | }
37 |
38 | func testInitRed() {
39 | let color = UIColor(hex: redHex)!
40 | XCTAssertEqual(color.red, 255.0 / 255.0)
41 | XCTAssertEqual(color.green, 0.0 / 255.0)
42 | XCTAssertEqual(color.blue, 0.0 / 255.0)
43 | XCTAssertEqual(color.alpha, 1)
44 | }
45 |
46 | func testInitDarkGreen() {
47 | let color = UIColor(hex: darkGreen)!
48 | XCTAssertEqual(color.red, 50.0 / 255.0)
49 | XCTAssertEqual(color.green, 168.0 / 255.0)
50 | XCTAssertEqual(color.blue, 82.0 / 255.0)
51 | XCTAssertEqual(color.alpha, 1)
52 | }
53 |
54 | func testInitLightGreen() {
55 | let color = UIColor(hex: lightGreen)!
56 | XCTAssertEqual(color.red, 67.0 / 255.0)
57 | XCTAssertEqual(color.green, 255.0 / 255.0)
58 | XCTAssertEqual(color.blue, 100.0 / 255.0)
59 | XCTAssertEqual(color.alpha, 0.85, accuracy: 0.001)
60 | }
61 |
62 | // hex
63 |
64 | func testHexBlack() {
65 | let color = UIColor.black
66 | XCTAssertEqual(color.hex, blackHex)
67 | }
68 |
69 | func testHexWhite() {
70 | let color = UIColor.white
71 | XCTAssertEqual(color.hex, whiteHex)
72 | }
73 |
74 | func testHexRed() {
75 | let color = UIColor.red
76 | XCTAssertEqual(color.hex, redHex)
77 | }
78 |
79 | func testHexDarkGreen() {
80 | let color = UIColor(red: 50.0 / 255.0, green: 168.0 / 255.0, blue: 82.0 / 255.0, alpha: 1.0)
81 | XCTAssertEqual(color.hex, darkGreen)
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/LabTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 2/26/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class LabTests: XCTestCase {
12 |
13 | func testGreen() {
14 | let color = UIColor.green
15 |
16 | XCTAssertEqual(color.L, 87.74)
17 | XCTAssertEqual(color.a, -86.18)
18 | XCTAssertEqual(color.b, 83.18)
19 | }
20 |
21 | func testWhite() {
22 | let color = UIColor.white
23 |
24 | XCTAssertEqual(color.L, 100.0)
25 | XCTAssertEqual(color.a, 0.01)
26 | XCTAssertEqual(color.b, -0.01)
27 | }
28 |
29 | func testArbitrary() {
30 | let color = UIColor(red: 129.0 / 255.0, green: 200.0 / 255.0, blue: 10.0 / 255.0, alpha: 1.0)
31 |
32 | XCTAssertEqual(color.L, 73.55)
33 | XCTAssertEqual(color.a, -46.45)
34 | XCTAssertEqual(color.b, 72.04)
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/NameTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NameTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 12/9/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ColorKit
11 |
12 | class NameTests: XCTestCase {
13 |
14 | func testPrimaryExact() {
15 | let color = UIColor.blue
16 | XCTAssertEqual(color.name(), "blue")
17 | }
18 |
19 | func testSecondaryExact() {
20 | let color = UIColor.purple
21 | XCTAssertEqual(color.name(), "violet")
22 | }
23 |
24 | func testTertiaryExact() {
25 | let color = UIColor(red: 0.5, green: 1.0, blue: 0.0, alpha: 1.0)
26 | XCTAssertEqual(color.name(), "chartreuse")
27 | }
28 |
29 | func testClose() {
30 | let color = UIColor(red: 0.9, green: 0.0, blue: 0.0, alpha: 1.0)
31 | XCTAssertEqual(color.name(), "red")
32 | }
33 |
34 | func testBlack() {
35 | let color = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
36 | XCTAssertEqual(color.name(), "black")
37 | }
38 |
39 | func testWhite() {
40 | let color = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
41 | XCTAssertEqual(color.name(), "white")
42 | }
43 |
44 | func testGray() {
45 | let color = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0)
46 | XCTAssertEqual(color.name(), "gray")
47 | }
48 |
49 | func testDarkGray() {
50 | let color = UIColor(red: 0.3, green: 0.3, blue: 0.3, alpha: 1.0)
51 | XCTAssertEqual(color.name(), "gray")
52 | }
53 |
54 | func testLightGray() {
55 | let color = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1.0)
56 | XCTAssertEqual(color.name(), "gray")
57 | }
58 |
59 | func testRandom() {
60 | let color = UIColor.random()
61 | XCTAssertNotNil(color.name())
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/PaletteTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PaletteTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 7/6/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class PaletteTests: XCTestCase {
13 |
14 | // MARK: - Colors
15 |
16 | func testPaletteNoColors() {
17 | XCTAssertNil(ColorPalette(colors: []))
18 | }
19 |
20 | func testPaletteOneColor() {
21 | XCTAssertNil(ColorPalette(colors: [.green]))
22 | }
23 |
24 | func testPaletteSameColors() {
25 | XCTAssertNil(ColorPalette(colors: [.green, .green, .green, .green]))
26 | }
27 |
28 | func testPaletteBlackWhiteColors() {
29 | let colorPalette = ColorPalette(colors: [.black, .white])
30 | XCTAssertEqual(colorPalette?.background, .black)
31 | XCTAssertEqual(colorPalette?.primary, .white)
32 | XCTAssertNil(colorPalette?.secondary)
33 | }
34 |
35 | func testPaletteBlackWhiteColorsBright() {
36 | let colorPalette = ColorPalette(colors: [.black, .white], darkBackground: false)
37 | XCTAssertEqual(colorPalette?.background, .white)
38 | XCTAssertEqual(colorPalette?.primary, .black)
39 | XCTAssertNil(colorPalette?.secondary)
40 | }
41 |
42 | func testCloseColors() {
43 | XCTAssertNil(ColorPalette(colors: [.blue, UIColor(red: 0, green: 0, blue: 0.8, alpha: 1.0)]))
44 | }
45 |
46 | func testRealUseCase() {
47 | let darkBlue = UIColor(red: 0.0 / 255.0, green: 120.0 / 255.0, blue: 190.0 / 255.0, alpha: 1.0)
48 | let brightBlue = UIColor(red: 110.0 / 255.0, green: 178.0 / 255.0, blue: 200.0 / 255.0, alpha: 1.0)
49 | let orange = UIColor(red: 203.0 / 255.0, green: 179.0 / 255.0, blue: 121.0 / 255.0, alpha: 1.0)
50 | let colorPalette = ColorPalette(colors: [darkBlue, brightBlue, orange], ignoreContrastRatio: true)
51 | XCTAssertEqual(colorPalette?.background, darkBlue)
52 | XCTAssertEqual(colorPalette?.primary, orange)
53 | XCTAssertEqual(colorPalette?.secondary, brightBlue)
54 | }
55 |
56 | func testRealUseCase2() {
57 | let red = UIColor(red: 255.0 / 255.0, green: 21.0 / 255.0, blue: 13.0 / 255.0, alpha: 1.0)
58 | let darkBlue = UIColor(red: 76.0 / 255.0, green: 101.0 / 255.0, blue: 122.0 / 255.0, alpha: 1.0)
59 | let white = UIColor.white
60 | let colorPalette = ColorPalette(colors: [red, darkBlue, white], darkBackground: false)
61 | XCTAssertEqual(colorPalette?.background, white)
62 | XCTAssertEqual(colorPalette?.primary, darkBlue)
63 | XCTAssertEqual(colorPalette?.secondary, red)
64 | }
65 |
66 | // MARK: - Ordered Colors
67 |
68 | func testPaletteNoOrderedColors() {
69 | XCTAssertNil(ColorPalette(orderedColors: []))
70 | }
71 |
72 | func testPaletteOneOrderedColor() {
73 | XCTAssertNil(ColorPalette(orderedColors: [.green]))
74 | }
75 |
76 | func testPaletteSameOrderedColors() {
77 | XCTAssertNil(ColorPalette(orderedColors: [.green, .green, .green, .green]))
78 | }
79 |
80 | func testPaletteBlackWhiteOrderedColors() {
81 | let colorPalette = ColorPalette(orderedColors: [.black, .white])
82 | XCTAssertEqual(colorPalette?.background, .black)
83 | XCTAssertEqual(colorPalette?.primary, .white)
84 | XCTAssertNil(colorPalette?.secondary)
85 | }
86 |
87 | func testPaletteWhiteBlackOrderedColorsBright() {
88 | let colorPalette = ColorPalette(orderedColors: [.white, .black], darkBackground: false)
89 | XCTAssertEqual(colorPalette?.background, .white)
90 | XCTAssertEqual(colorPalette?.primary, .black)
91 | XCTAssertNil(colorPalette?.secondary)
92 | }
93 |
94 | func testPaletteBlackWhiteOrderedColorsBright() {
95 | let colorPalette = ColorPalette(orderedColors: [.black, .white], darkBackground: false)
96 | XCTAssertEqual(colorPalette?.background, .black)
97 | XCTAssertEqual(colorPalette?.primary, .white)
98 | XCTAssertNil(colorPalette?.secondary)
99 | }
100 |
101 | func testCloseOrderedColors() {
102 | XCTAssertNil(ColorPalette(orderedColors: [.blue, UIColor(red: 0, green: 0, blue: 0.8, alpha: 1.0)]))
103 | }
104 |
105 | func testRealUseCaseOrdered() {
106 | let darkBlue = UIColor(red: 0.0 / 255.0, green: 120.0 / 255.0, blue: 190.0 / 255.0, alpha: 1.0)
107 | let brightBlue = UIColor(red: 110.0 / 255.0, green: 178.0 / 255.0, blue: 200.0 / 255.0, alpha: 1.0)
108 | let orange = UIColor(red: 203.0 / 255.0, green: 179.0 / 255.0, blue: 121.0 / 255.0, alpha: 1.0)
109 | let colorPalette = ColorPalette(orderedColors: [darkBlue, brightBlue, orange], ignoreContrastRatio: true)
110 | XCTAssertEqual(colorPalette?.background, darkBlue)
111 | XCTAssertEqual(colorPalette?.primary, brightBlue)
112 | XCTAssertEqual(colorPalette?.secondary, orange)
113 | }
114 |
115 | func testRealUseCase2Ordered() {
116 | let red = UIColor(red: 255.0 / 255.0, green: 21.0 / 255.0, blue: 13.0 / 255.0, alpha: 1.0)
117 | let darkBlue = UIColor(red: 76.0 / 255.0, green: 101.0 / 255.0, blue: 122.0 / 255.0, alpha: 1.0)
118 | let white = UIColor.white
119 | let colorPalette = ColorPalette(orderedColors: [red, darkBlue, white], darkBackground: false)
120 | XCTAssertEqual(colorPalette?.background, red)
121 | XCTAssertEqual(colorPalette?.primary, white)
122 | XCTAssertNil(colorPalette?.secondary)
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/RGBTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RGBTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 2/24/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class RGBTests: XCTestCase {
13 |
14 | func testRed() {
15 | let red = UIColor.red
16 | XCTAssertEqual(red.red, 1.0)
17 | XCTAssertEqual(red.green, 0.0)
18 | XCTAssertEqual(red.blue, 0.0)
19 | XCTAssertEqual(red.alpha, 1.0)
20 | }
21 |
22 | func testGreen() {
23 | let green = UIColor.green
24 | XCTAssertEqual(green.red, 0.0)
25 | XCTAssertEqual(green.green, 1.0)
26 | XCTAssertEqual(green.blue, 0.0)
27 | XCTAssertEqual(green.alpha, 1.0)
28 | }
29 |
30 | func testBlue() {
31 | let blue = UIColor.blue
32 | XCTAssertEqual(blue.red, 0.0)
33 | XCTAssertEqual(blue.green, 0.0)
34 | XCTAssertEqual(blue.blue, 1.0)
35 | XCTAssertEqual(blue.alpha, 1.0)
36 | }
37 |
38 | func testWhite() {
39 | let blue = UIColor.white
40 | XCTAssertEqual(blue.red, 1.0)
41 | XCTAssertEqual(blue.green, 1.0)
42 | XCTAssertEqual(blue.blue, 1.0)
43 | XCTAssertEqual(blue.alpha, 1.0)
44 | }
45 |
46 | func testBlack() {
47 | let blue = UIColor.black
48 | XCTAssertEqual(blue.red, 0.0)
49 | XCTAssertEqual(blue.green, 0.0)
50 | XCTAssertEqual(blue.blue, 0.0)
51 | XCTAssertEqual(blue.alpha, 1.0)
52 | }
53 |
54 | func testGray() {
55 | let blue = UIColor.gray
56 | XCTAssertEqual(blue.red, 0.5)
57 | XCTAssertEqual(blue.green, 0.5)
58 | XCTAssertEqual(blue.blue, 0.5)
59 | XCTAssertEqual(blue.alpha, 1.0)
60 | }
61 |
62 | func testPurple() {
63 | let blue = UIColor.purple
64 | XCTAssertEqual(blue.red, 0.5)
65 | XCTAssertEqual(blue.green, 0.0)
66 | XCTAssertEqual(blue.blue, 0.5)
67 | XCTAssertEqual(blue.alpha, 1.0)
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/RelativeLuminanceTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RelativeLuminanceTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 3/13/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class RelativeLuminanceTests: XCTestCase {
13 |
14 | func testWhite() {
15 | let color = UIColor.white
16 | XCTAssertEqual(color.relativeLuminance, 1.0)
17 | }
18 |
19 | func testBlack() {
20 | let color = UIColor.black
21 | XCTAssertEqual(color.relativeLuminance, 0.0)
22 | }
23 |
24 | func testOrange() {
25 | let color = UIColor(red: 98.0 / 255.0, green: 44.0 / 255.0, blue: 8.0 / 255.0, alpha: 1.0)
26 | XCTAssertEqual(color.relativeLuminance, 0.044)
27 | }
28 |
29 | func testPurple() {
30 | let color = UIColor(red: 120 / 255.0, green: 90.0 / 255.0, blue: 200.0 / 255.0, alpha: 1.0)
31 | XCTAssertEqual(color.relativeLuminance, 0.155)
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Black_White_Square.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Black_White_Square.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Blue_Green_Square.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Blue_Green_Square.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Blue_Square_1x1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Blue_Square_1x1.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Green_Square.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Green_Square.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Purple_Square.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Purple_Square.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Red_Green_Blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Red_Green_Blue.png
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Red_Green_Blue_Black_Mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Red_Green_Blue_Black_Mini.png
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Red_Green_Blue_Random.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Red_Green_Blue_Random.png
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Red_Green_Blue_Random_Mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Red_Green_Blue_Random_Mini.png
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Test_Image_1.Jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Test_Image_1.Jpeg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Test_Image_2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Test_Image_2.jpeg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/Resources/Test_Image_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boris-Em/ColorKit/6e4375a6126eac0a29893c607ae318bdbe33310c/ColorKit/ColorKitTests/Resources/Test_Image_3.jpg
--------------------------------------------------------------------------------
/ColorKit/ColorKitTests/XYZTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XYZTests.swift
3 | // ColorKitTests
4 | //
5 | // Created by Boris Emorine on 2/24/20.
6 | // Copyright © 2020 BorisEmorine. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ColorKit
11 |
12 | class XYZTests: XCTestCase {
13 |
14 | func testGreen() {
15 | let color = UIColor.green
16 |
17 | XCTAssertEqual(color.X, 35.76)
18 | XCTAssertEqual(color.Y, 71.52)
19 | XCTAssertEqual(color.Z, 11.92)
20 | }
21 |
22 | func testWhite() {
23 | let color = UIColor.white
24 |
25 | XCTAssertEqual(color.X, 95.05)
26 | XCTAssertEqual(color.Y, 100.0)
27 | XCTAssertEqual(color.Z, 108.9)
28 | }
29 |
30 | func testArbitrary() {
31 | let color = UIColor(red: 129.0 / 255.0, green: 200.0 / 255.0, blue: 10.0 / 255.0, alpha: 1.0)
32 |
33 | XCTAssertEqual(color.X, 29.76)
34 | XCTAssertEqual(color.Y, 46.0)
35 | XCTAssertEqual(color.Z, 7.6)
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Boris Emorine
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "ColorKit",
8 | platforms: [
9 | .iOS(.v13),
10 | ],
11 | products: [
12 | .library(
13 | name: "ColorKit",
14 | targets: ["ColorKit"]),
15 | ],
16 | targets: [
17 | .target(
18 | name: "ColorKit",
19 | path: "ColorKit/ColorKit"),
20 | .testTarget(
21 | name: "ColorKitTests",
22 | dependencies: ["ColorKit"],
23 | path: "ColorKit/ColorKitTests"),
24 | ],
25 | swiftLanguageVersions: [SwiftVersion.v5]
26 | )
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ColorKit
2 |
3 |
4 |
5 | **ColorKit** is your companion to work with colors on iOS.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | - [Features](#features)
20 | - [Installation](#installation)
21 | - [Sample Project](#sample-project)
22 | - [Contributing](#contributing)
23 | - [License](#license)
24 |
25 |
26 |
27 | ## Features
28 |
29 | ### Dominant Colors
30 | **ColorKit** makes it easy to find the dominant colors of an image. It returns a color palette of the most common colors on the image.
31 |
32 | ```swift
33 | let dominantColors = try image.dominantColors()
34 | ```
35 |
36 |
37 |
38 |
39 |
40 | By default, **ColorKit** uses an iterative process to determine the dominant colors of an image. But it also supports doing so via a [k-mean clustering algorithm](https://en.wikipedia.org/wiki/K-means_clustering). Choose whichever is more appropriate for your use case.
41 |
42 | ---
43 |
44 | ### Color Palette
45 | **ColorKit** lets you generate color palettes from a collection of colors. It will automatically ensure that the best colors are picked based on a few configurable parameters like contrast ratio.
46 | This feature is particularly powerful when combined with the dominant color calculation.
47 |
48 | ```swift
49 | let colors = try image.dominantColors()
50 | let palette = ColorPalette(orderedColors: colors, ignoreContrastRatio: true)
51 | ```
52 | The following examples use the palette to dynamically match the color of the text and background to the album covers.
53 |
54 |
55 |
56 |
57 |
58 | ---
59 |
60 | ### Average Color
61 |
62 | To compute the average color of an image, simply call the `averageColor` function on a `UIImage` instance.
63 | ```swift
64 | let averageColor = try image.averageColor()
65 | ```
66 |
67 | ---
68 |
69 | ### Color Difference (DeltaE)
70 |
71 | Perceptual color difference / comparaison is a common problem of color science.
72 | It simply consists of calculating how different two colors look from each other, to the human eye. This is commonly referenced as the DeltaE.
73 |
74 | **ColorKit** makes it a breaze to compare two colors.
75 |
76 | ```swift
77 | let colorDifference = UIColor.green.difference(from: .white) // 120.34
78 | ```
79 |
80 | While this may seem trivial, simply using the RGB color model often yields non-accurate results for human perception.
81 | This is because RGB is not perceptually uniform.
82 |
83 | Here is an example highlighting the limitations of using the RGB color model to compare colors.
84 |
85 |
86 |
87 |
88 |
89 | As you can see, the difference between the two greens (left) is considered greater than the difference between the pink and gray colors (right). In other words, the pink and gray are considered to look more similar than the two greens by the algorithm.
90 | This obviously does not match the expectation of the human eye.
91 |
92 | Thankfully, **ColorKit** provides algorithms that make it possible to compare colors just like the human eye would: **CIE76**, **CIE94** and **CIEDE2000**.
93 |
94 | ```swift
95 | let colorDifference = UIColor.green.difference(from: .white, using: .CIE94)
96 | ```
97 |
98 | Here is the same example as above, using the **CIE94** algorithm.
99 |
100 |
101 |
102 |
103 |
104 | The **CIE94** algorithm successfuly realizes that the two greens (left) look closer from each other than the pink and gray (right) do.
105 |
106 | More information about color difference can be found [here](https://en.wikipedia.org/wiki/Color_difference).
107 |
108 | ---
109 |
110 | ### Contrast Ratio
111 |
112 | To calculate the contrast ratio between two colors, simply use the `contrastRatio` function.
113 | ```swift
114 | let contrastRatio = UIColor.green.contrastRatio(with: UIColor.white)
115 | ```
116 | The contrast ratio is particularly important when displaying text.
117 | To ensure that it's readable by everyone, **ColorKit** makes it easy for you to follow the accessibility guidelines set by [WCAG 2](https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0#qr-visual-audio-contrast-contrast).
118 |
119 | ---
120 |
121 | ### Color Space Conversions
122 |
123 | **ColorKit** assists you when translating a color from a color space to another.
124 | They're simply supported as extensions on `UIColor`.
125 | **CIELAB**, **XYZ** and **CMYK** are supported.
126 |
127 | ---
128 |
129 | ### More
130 |
131 | There is a lot more that **ColorKit** is capable of.
132 | Here is a short list of examples:
133 | - Working with Hex color codes
134 | ```swift
135 | let hexValue = UIColor.green.hex
136 | let color = UIColor(hex: "eb4034")
137 | ```
138 | - Generating random colors
139 | ```swift
140 | let randomColor = UIColor.random()
141 | ```
142 | - Calculating the relative luminance of a color
143 | ```swift
144 | let relativeLuminance = UIColor.green.relativeLuminance
145 | ```
146 | - Generating complementary colors
147 | ```swift
148 | let complementaryColor = UIColor.green.complementaryColor
149 | ```
150 |
151 |
152 |
153 | ## Installation
154 |
155 | ### Swift Package Manager
156 |
157 | The [Swift Package Manager](https://swift.org/package-manager/) is the easiest way to install and manage **ColorKit** as a dependecy.
158 | Simply add **ColorKit** to your dependencies in your `Package.swift` file:
159 | ```swift
160 | dependencies: [
161 | .package(url: "https://github.com/Boris-Em/ColorKit.git")
162 | ]
163 | ```
164 |
165 | Alternatively, you can also use XCode to add **ColorKit** to your existing project, by using `File > Swift Packages > Add Package Dependency...`.
166 |
167 | ### Manually
168 |
169 | **ColorKit** can also be added to your project manually. Download the **ColorKit** project from Github, then drag and drop the folder `ColorKit/ColorKit` into your XCode project.
170 |
171 |
172 |
173 | ## Sample Project
174 |
175 | Use the iOS sample project included in this repository to find comprehensive examples of the different features of **ColorKit**.
176 |
177 |
178 |
179 | ## Contributing
180 |
181 | Contributions to **ColorKit** are always welcome!
182 | For bugs and feature requests, open an [issue](https://github.com/Boris-Em/ColorKit/issues/new).
183 | To contribute to the code base, simply submit a [pull request](https://github.com/Boris-Em/ColorKit/pulls).
184 |
185 |
186 |
187 | ## License
188 |
189 | See the [License](https://github.com/Boris-Em/ColorKit/blob/master/LICENSE). You are free to make changes and use this in either personal or commercial projects. Attribution is not required, but highly appreciated. A little "Thanks!" (or something to that affect) is always welcome. If you use **ColorKit** in one of your projects, please let us know!
190 |
--------------------------------------------------------------------------------