Skip to content

Commit 4bc264e

Browse files
committed
[ADD] CIE XYZ Color Space
1 parent 27ed125 commit 4bc264e

File tree

4 files changed

+153
-21
lines changed

4 files changed

+153
-21
lines changed

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change log
22

3+
## Version 3.0.1
4+
5+
- [ADD] CIE XYZ Color Space
6+
- `toXYZAComponents()` method
7+
38
## [Version 3.0.0](https://github.com/yannickl/DynamicColor/releases/tag/3.0.0)
49
*Released on 2016-06-14.*
510

Diff for: Examples/DynamicColorExample.xcodeproj/project.pbxproj

+24-21
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
CE5D64751D33F81B005DEE4E /* DynamicColor+XYZTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5D64741D33F81B005DEE4E /* DynamicColor+XYZTests.swift */; };
11+
CE5D64761D341105005DEE4E /* DynamicColor+XYZTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5D64741D33F81B005DEE4E /* DynamicColor+XYZTests.swift */; };
12+
CE5D64771D341198005DEE4E /* DynamicColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECBCDA71B2B6EEB0047E731 /* DynamicColorTests.swift */; };
13+
CE5D64781D34119A005DEE4E /* DynamicColor+HSLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86431D29875E00C5A670 /* DynamicColor+HSLTests.swift */; };
14+
CE5D64791D34119C005DEE4E /* DynamicColor+RGBATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86441D29875E00C5A670 /* DynamicColor+RGBATests.swift */; };
1015
CE8B86451D29875E00C5A670 /* DynamicColor+HSLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86431D29875E00C5A670 /* DynamicColor+HSLTests.swift */; };
1116
CE8B86461D29875E00C5A670 /* DynamicColor+RGBATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86441D29875E00C5A670 /* DynamicColor+RGBATests.swift */; };
1217
CE8B86481D29884400C5A670 /* XCTTestCaseTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86471D29884400C5A670 /* XCTTestCaseTemplate.swift */; };
1318
CE8B864A1D29885800C5A670 /* XCTTestCaseTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86491D29885800C5A670 /* XCTTestCaseTemplate.swift */; };
14-
CE8B864F1D29887E00C5A670 /* DynamicColor+HSLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B864C1D29887E00C5A670 /* DynamicColor+HSLTests.swift */; };
15-
CE8B86501D29887E00C5A670 /* DynamicColor+RGBATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B864D1D29887E00C5A670 /* DynamicColor+RGBATests.swift */; };
16-
CE8B86511D29887E00C5A670 /* DynamicColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B864E1D29887E00C5A670 /* DynamicColorTests.swift */; };
19+
CE8B86551D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */; };
20+
CE8B86561D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */; };
21+
CE8B86571D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */; };
22+
CE8B86581D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */; };
23+
CE8B86591D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */; };
1724
CEAF67871CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAF67861CA2D22E008DC3A2 /* DynamicColor+Deriving.swift */; };
1825
CEAF67881CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAF67861CA2D22E008DC3A2 /* DynamicColor+Deriving.swift */; };
1926
CEAF67891CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAF67861CA2D22E008DC3A2 /* DynamicColor+Deriving.swift */; };
@@ -91,13 +98,12 @@
9198
/* End PBXCopyFilesBuildPhase section */
9299

93100
/* Begin PBXFileReference section */
101+
CE5D64741D33F81B005DEE4E /* DynamicColor+XYZTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "DynamicColor+XYZTests.swift"; path = "../../Tests/DynamicColor+XYZTests.swift"; sourceTree = "<group>"; };
94102
CE8B86431D29875E00C5A670 /* DynamicColor+HSLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "DynamicColor+HSLTests.swift"; path = "../../Tests/DynamicColor+HSLTests.swift"; sourceTree = "<group>"; };
95103
CE8B86441D29875E00C5A670 /* DynamicColor+RGBATests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "DynamicColor+RGBATests.swift"; path = "../../Tests/DynamicColor+RGBATests.swift"; sourceTree = "<group>"; };
96104
CE8B86471D29884400C5A670 /* XCTTestCaseTemplate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTTestCaseTemplate.swift; sourceTree = "<group>"; };
97105
CE8B86491D29885800C5A670 /* XCTTestCaseTemplate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTTestCaseTemplate.swift; sourceTree = "<group>"; };
98-
CE8B864C1D29887E00C5A670 /* DynamicColor+HSLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DynamicColor+HSLTests.swift"; sourceTree = "<group>"; };
99-
CE8B864D1D29887E00C5A670 /* DynamicColor+RGBATests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DynamicColor+RGBATests.swift"; sourceTree = "<group>"; };
100-
CE8B864E1D29887E00C5A670 /* DynamicColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicColorTests.swift; sourceTree = "<group>"; };
106+
CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DynamicColor+XYZ.swift"; sourceTree = "<group>"; };
101107
CEAF67861CA2D22E008DC3A2 /* DynamicColor+Deriving.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DynamicColor+Deriving.swift"; sourceTree = "<group>"; };
102108
CEAF678C1CA2D342008DC3A2 /* DynamicColor+RGBA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DynamicColor+RGBA.swift"; sourceTree = "<group>"; };
103109
CECBCD811B2B6C5E0047E731 /* DynamicColor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DynamicColor.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -166,17 +172,6 @@
166172
/* End PBXFrameworksBuildPhase section */
167173

168174
/* Begin PBXGroup section */
169-
CE8B864B1D29887E00C5A670 /* Tests */ = {
170-
isa = PBXGroup;
171-
children = (
172-
CE8B864C1D29887E00C5A670 /* DynamicColor+HSLTests.swift */,
173-
CE8B864D1D29887E00C5A670 /* DynamicColor+RGBATests.swift */,
174-
CE8B864E1D29887E00C5A670 /* DynamicColorTests.swift */,
175-
);
176-
name = Tests;
177-
path = ../../Tests;
178-
sourceTree = "<group>";
179-
};
180175
CECBCD821B2B6C5E0047E731 /* DynamicColorFramework */ = {
181176
isa = PBXGroup;
182177
children = (
@@ -203,6 +198,7 @@
203198
CECBCDA71B2B6EEB0047E731 /* DynamicColorTests.swift */,
204199
CE8B86431D29875E00C5A670 /* DynamicColor+HSLTests.swift */,
205200
CE8B86441D29875E00C5A670 /* DynamicColor+RGBATests.swift */,
201+
CE5D64741D33F81B005DEE4E /* DynamicColor+XYZTests.swift */,
206202
);
207203
path = DynamicColorTests;
208204
sourceTree = "<group>";
@@ -218,7 +214,6 @@
218214
CEE753CB1BF105E3001FF6ED /* OSXTests */ = {
219215
isa = PBXGroup;
220216
children = (
221-
CE8B864B1D29887E00C5A670 /* Tests */,
222217
CE8B86491D29885800C5A670 /* XCTTestCaseTemplate.swift */,
223218
CEE753CE1BF105E3001FF6ED /* Info.plist */,
224219
);
@@ -243,6 +238,7 @@
243238
CEAF67861CA2D22E008DC3A2 /* DynamicColor+Deriving.swift */,
244239
CEF02EEC1D2984CC00D810B9 /* DynamicColor+HSL.swift */,
245240
CEAF678C1CA2D342008DC3A2 /* DynamicColor+RGBA.swift */,
241+
CE8B86541D2991F000C5A670 /* DynamicColor+XYZ.swift */,
246242
CEF85A241C84EA5B00DD1A49 /* HSL.swift */,
247243
);
248244
name = DynamicColor;
@@ -508,6 +504,7 @@
508504
CEF85A251C84EA5B00DD1A49 /* DynamicColor.swift in Sources */,
509505
CEAF678D1CA2D342008DC3A2 /* DynamicColor+RGBA.swift in Sources */,
510506
CEF02EED1D2984CD00D810B9 /* DynamicColor+HSL.swift in Sources */,
507+
CE8B86551D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */,
511508
CEAF67871CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */,
512509
CEF85A261C84EA5B00DD1A49 /* HSL.swift in Sources */,
513510
);
@@ -518,6 +515,7 @@
518515
buildActionMask = 2147483647;
519516
files = (
520517
CE8B86481D29884400C5A670 /* XCTTestCaseTemplate.swift in Sources */,
518+
CE8B86581D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */,
521519
CECBCDA81B2B6EEB0047E731 /* DynamicColorTests.swift in Sources */,
522520
CE8B86461D29875E00C5A670 /* DynamicColor+RGBATests.swift in Sources */,
523521
CEF02EF01D2984CD00D810B9 /* DynamicColor+HSL.swift in Sources */,
@@ -526,6 +524,7 @@
526524
CEAF678A1CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */,
527525
CEAF67901CA2D342008DC3A2 /* DynamicColor+RGBA.swift in Sources */,
528526
CE8B86451D29875E00C5A670 /* DynamicColor+HSLTests.swift in Sources */,
527+
CE5D64751D33F81B005DEE4E /* DynamicColor+XYZTests.swift in Sources */,
529528
);
530529
runOnlyForDeploymentPostprocessing = 0;
531530
};
@@ -534,14 +533,16 @@
534533
buildActionMask = 2147483647;
535534
files = (
536535
CEAF678B1CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */,
536+
CE8B86591D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */,
537537
CEF02EF11D2984CD00D810B9 /* DynamicColor+HSL.swift in Sources */,
538+
CE5D64781D34119A005DEE4E /* DynamicColor+HSLTests.swift in Sources */,
538539
CEF85A2E1C84EA6800DD1A49 /* HSL.swift in Sources */,
539540
CEAF67911CA2D342008DC3A2 /* DynamicColor+RGBA.swift in Sources */,
541+
CE5D64771D341198005DEE4E /* DynamicColorTests.swift in Sources */,
540542
CE8B864A1D29885800C5A670 /* XCTTestCaseTemplate.swift in Sources */,
541-
CE8B86511D29887E00C5A670 /* DynamicColorTests.swift in Sources */,
542-
CE8B86501D29887E00C5A670 /* DynamicColor+RGBATests.swift in Sources */,
543543
CEF85A2D1C84EA6800DD1A49 /* DynamicColor.swift in Sources */,
544-
CE8B864F1D29887E00C5A670 /* DynamicColor+HSLTests.swift in Sources */,
544+
CE5D64761D341105005DEE4E /* DynamicColor+XYZTests.swift in Sources */,
545+
CE5D64791D34119C005DEE4E /* DynamicColor+RGBATests.swift in Sources */,
545546
);
546547
runOnlyForDeploymentPostprocessing = 0;
547548
};
@@ -555,6 +556,7 @@
555556
CEAF678F1CA2D342008DC3A2 /* DynamicColor+RGBA.swift in Sources */,
556557
CEEB28E01BE27401001A74E8 /* ColorCellView.swift in Sources */,
557558
CEAF67891CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */,
559+
CE8B86571D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */,
558560
CEEB28D21BE27340001A74E8 /* AppDelegate.swift in Sources */,
559561
CEF02EEF1D2984CD00D810B9 /* DynamicColor+HSL.swift in Sources */,
560562
);
@@ -570,6 +572,7 @@
570572
CEAF678E1CA2D342008DC3A2 /* DynamicColor+RGBA.swift in Sources */,
571573
CEFBDAE31B1CE38D000E6F30 /* ViewController.swift in Sources */,
572574
CEAF67881CA2D22E008DC3A2 /* DynamicColor+Deriving.swift in Sources */,
575+
CE8B86561D2991F000C5A670 /* DynamicColor+XYZ.swift in Sources */,
573576
CEFBDAE11B1CE38D000E6F30 /* AppDelegate.swift in Sources */,
574577
CEF02EEE1D2984CD00D810B9 /* DynamicColor+HSL.swift in Sources */,
575578
);

Diff for: Sources/DynamicColor+XYZ.swift

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* DynamicColor
3+
*
4+
* Copyright 2015-present Yannick Loriot.
5+
* http://yannickloriot.com
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*
25+
*/
26+
27+
#if os(iOS) || os(tvOS) || os(watchOS)
28+
import UIKit
29+
#elseif os(OSX)
30+
import AppKit
31+
#endif
32+
33+
// MARK: CIE XYZ Color Space
34+
35+
public extension DynamicColor {
36+
/**
37+
Returns the XYZA (mix of cone response curves, luminance, quasi-equal to blue stimulation, alpha) components.
38+
39+
Notes that values are between 0.0 and 1.0.
40+
41+
- returns: The XYZA components as a tuple (X, Y, Z, A).
42+
*/
43+
public final func toXYZAComponents() -> (X: CGFloat, Y: CGFloat, Z: CGFloat, A: CGFloat) {
44+
/*
45+
Converts RGB to sRGB.
46+
We're going to use the Reverse Transformation Equation.
47+
http://en.wikipedia.org/wiki/SRGB
48+
*/
49+
let sRGB = { (c: CGFloat) -> CGFloat in
50+
c > 0.04045 ? pow((c + 0.055) / (1 + 0.055), 2.40) : c / 12.92
51+
}
52+
53+
let rgba = toRGBAComponents()
54+
let red = sRGB(rgba.r)
55+
let green = sRGB(rgba.g)
56+
let blue = sRGB(rgba.b)
57+
58+
/*
59+
Converts to XYZ values
60+
Using a matrix multiplication of the linear values
61+
http://upload.wikimedia.org/math/4/3/3/433376fc18cccd887758beffb7e7c625.png
62+
*/
63+
let X = Int((red * 0.4124 + green * 0.3576 + blue * 0.1805) * 100000)
64+
let Y = Int((red * 0.2126 + green * 0.7152 + blue * 0.0722) * 100000)
65+
let Z = Int((red * 0.0193 + green * 0.1192 + blue * 0.9505) * 100000)
66+
67+
return (X: CGFloat(X) / 1000, Y: CGFloat(Y) / 1000, Z: CGFloat(Z) / 1000, A: rgba.a)
68+
}
69+
}

Diff for: Tests/DynamicColor+XYZTests.swift

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* DynamicColor
3+
*
4+
* Copyright 2015-present Yannick Loriot.
5+
* http://yannickloriot.com
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*
25+
*/
26+
27+
import XCTest
28+
29+
class DynamicColorXYZTests: XCTTestCaseTemplate {
30+
func testInitWithXYZAComponents() {
31+
let whiteXYZA = DynamicColor.white().toXYZAComponents()
32+
XCTAssert(whiteXYZA.X == 95.05, "X component should be equal to 95.05 (not \(whiteXYZA.X))")
33+
XCTAssert(whiteXYZA.Y == 100, "Y component should be equal to 100 (not \(whiteXYZA.Y))")
34+
XCTAssert(whiteXYZA.Z == 108.9, "Z component should be equal to 108.9 (not \(whiteXYZA.Z))")
35+
XCTAssert(whiteXYZA.A == 1, "Color alpha component should be equal to 1")
36+
37+
let blackXYZA = DynamicColor.black().toXYZAComponents()
38+
XCTAssert(blackXYZA.X == 0, "X component should be equal to 0 (not \(blackXYZA.X))")
39+
XCTAssert(blackXYZA.Y == 0, "Y component should be equal to 0 (not \(blackXYZA.Y))")
40+
XCTAssert(blackXYZA.Z == 0, "Z component should be equal to 0 (not \(blackXYZA.Z))")
41+
XCTAssert(blackXYZA.A == 1, "Color alpha component should be equal to 1")
42+
43+
let blueXYZA = DynamicColor.blue().toXYZAComponents()
44+
XCTAssert(blueXYZA.X == 18.05, "X component should be equal to 18.05 (not \(blueXYZA.X))")
45+
XCTAssert(blueXYZA.Y == 7.22, "Y component should be equal to 7.22 (not \(blueXYZA.Y))")
46+
XCTAssert(blueXYZA.Z == 95.05, "Z component should be equal to 95.05 (not \(blueXYZA.Z))")
47+
XCTAssert(blueXYZA.A == 1, "Color alpha component should be equal to 1")
48+
49+
let customXYZA = DynamicColor(red: 0.69804, green: 0.74118, blue: 0.20392, alpha: 1).toXYZAComponents()
50+
XCTAssert(customXYZA.X == 37.177, "X component should be equal to 37.177 (not \(customXYZA.X))")
51+
XCTAssert(customXYZA.Y == 46.108, "Y component should be equal to 46.108 (not \(customXYZA.Y))")
52+
XCTAssert(customXYZA.Z == 10.189, "Z component should be equal to 10.189 (not \(customXYZA.Z))")
53+
XCTAssert(customXYZA.A == 1, "Color alpha component should be equal to 1")
54+
}
55+
}

0 commit comments

Comments
 (0)