CNHexColor.swift
3.81 KB
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
//
// CNHexColor.swift
// metaCode
//
// Created by daojian on 2023/5/31.
//
import Foundation
#if os(iOS) || os(watchOS) || os(tvOS)
import UIKit
public typealias HexColor = UIColor
#else
import Cocoa
public typealias HexColor = NSColor
#endif
public extension HexColor {
typealias Hex = String
convenience init?(_ hex: Hex, alpha: CGFloat? = nil) {
guard let hexType = Type(from: hex), let components = hexType.components() else {
return nil
}
#if os(iOS) || os(watchOS) || os(tvOS)
self.init(red: components.red, green: components.green, blue: components.blue, alpha: alpha ?? components.alpha)
#else
self.init(calibratedRed: components.red, green: components.green, blue: components.blue, alpha: alpha ?? components.alpha)
#endif
}
/// The string hex value representation of the current color
var hex: Hex {
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0, rgb: Int
getRed(&r, green: &g, blue: &b, alpha: &a)
if a == 1 { // no alpha value set, we are returning the short version
rgb = (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0
return String(format: "#%06x", rgb)
} else {
rgb = (Int)(r*255)<<24 | (Int)(g*255)<<16 | (Int)(b*255)<<8 | (Int)(a*255)<<0
return String(format: "#%08x", rgb)
}
}
private enum `Type` {
case RGBshort(rgb: Hex)
case RGBshortAlpha(rgba: Hex)
case RGB(rgb: Hex)
case RGBA(rgba: Hex)
init?(from hex: Hex) {
var hexString = hex
hexString.removeHashIfNecessary()
guard let t = Type.transform(hex: hexString) else {
return nil
}
self = t
}
static func transform(hex string: Hex) -> Type? {
switch string.count {
case 3:
return .RGBshort(rgb: string)
case 4:
return .RGBshortAlpha(rgba: string)
case 6:
return .RGB(rgb: string)
case 8:
return .RGBA(rgba: string)
default:
return nil
}
}
var value: Hex {
switch self {
case .RGBshort(let rgb):
return rgb
case .RGBshortAlpha(let rgba):
return rgba
case .RGB(let rgb):
return rgb
case .RGBA(let rgba):
return rgba
}
}
typealias rgbComponents = (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
func components() -> rgbComponents? {
var hexValue: UInt32 = 0
guard Scanner(string: value).scanHexInt32(&hexValue) else {
return nil
}
let r, g, b, a, divisor: CGFloat
switch self {
case .RGBshort(_):
divisor = 15
r = CGFloat((hexValue & 0xF00) >> 8) / divisor
g = CGFloat((hexValue & 0x0F0) >> 4) / divisor
b = CGFloat( hexValue & 0x00F) / divisor
a = 1
case .RGBshortAlpha(_):
divisor = 15
r = CGFloat((hexValue & 0xF000) >> 12) / divisor
g = CGFloat((hexValue & 0x0F00) >> 8) / divisor
b = CGFloat((hexValue & 0x00F0) >> 4) / divisor
a = CGFloat( hexValue & 0x000F) / divisor
case .RGB(_):
divisor = 255
r = CGFloat((hexValue & 0xFF0000) >> 16) / divisor
g = CGFloat((hexValue & 0x00FF00) >> 8) / divisor
b = CGFloat( hexValue & 0x0000FF) / divisor
a = 1
case .RGBA(_):
divisor = 255
r = CGFloat((hexValue & 0xFF000000) >> 24) / divisor
g = CGFloat((hexValue & 0x00FF0000) >> 16) / divisor
b = CGFloat((hexValue & 0x0000FF00) >> 8) / divisor
a = CGFloat( hexValue & 0x000000FF) / divisor
}
return (red: r, green: g, blue: b, alpha: a)
}
}
}
private extension String {
mutating func removeHashIfNecessary() {
if hasPrefix("#") {
self = replacingOccurrences(of: "#", with: "")
}
}
}