// // UIColor.swift // VDS // // Created by Matt Bruce on 7/22/22. // import Foundation import UIKit import VDSCoreTokens extension UIColor { //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- /// Convenience to get a grayscale UIColor where the same value is used for red, green, and blue /// - Parameters: /// - rgb: red, green, and blue /// - alpha: alphay /// - Returns: UIColor that will be grayscale public class func grayscale(rgb: Int, alpha: CGFloat = 1.0) -> UIColor { let grayscale = CGFloat(rgb) / 255.0 return UIColor(red: grayscale, green: grayscale, blue: grayscale, alpha: alpha) } /// Convenience to get an 8-Bit UIColor based on RGB values /// - Parameters: /// - red: Value for Red /// - green: Value for Green /// - blue: Value for Blue /// - alpha: Value for Alpha /// - Returns: UIColor for the values above public class func color8Bits(red: Int, green: Int, blue: Int, alpha: CGFloat = 1.0) -> UIColor { return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: alpha) } /// Convenience to get an UIColor based on RGB values /// - Parameters: /// - red: Value for Red /// - green: Value for Green /// - blue: Value for Blue /// - alpha: Value for Alpha /// - Returns: UIColor for the values above public class func color8Bits(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat = 1.0) -> UIColor { return UIColor(red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha: alpha) } /// Gets UIColor via an 8 digit hex string. /// - Parameters: /// - hex: HexCode string /// - Returns: UIColor for the values above public class func getColorBy(hex: String) -> UIColor { var hexint: UInt64 = 0 let scanner = Scanner(string: hex) scanner.charactersToBeSkipped = CharacterSet(charactersIn: "#") scanner.scanHexInt64(&hexint) return UIColor(red: (CGFloat((hexint & 0xFF0000) >> 16)) / 255, green: (CGFloat((hexint & 0xFF00) >> 8)) / 255, blue: (CGFloat(hexint & 0xFF)) / 255, alpha: 1) } /// Gets UIColor via an 8 digit hex string that includes transparency. /// - Parameters: /// - hex: HexCode string /// - Returns: UIColor for the values above public class func getColorWithTransparencyBy(hex: String) -> UIColor { var hexint: UInt64 = 0 let scanner = Scanner(string: hex) scanner.charactersToBeSkipped = CharacterSet(charactersIn: "#") scanner.scanHexInt64(&hexint) return UIColor(red: (CGFloat((hexint & 0xFF000000) >> 24)) / 255, green: (CGFloat((hexint & 0xFF0000) >> 16)) / 255, blue: (CGFloat((hexint & 0xFF00) >> 8)) / 255, alpha: (CGFloat(hexint & 0xFF)) / 255) } /// Generates a gradient color for the color passed in /// - Parameter color: Primary color for the gradient /// - Returns: UIColor that is gradient public class func gradientColor(_ color: UIColor?) -> UIColor { var h: CGFloat = 0 var s: CGFloat = 0 var b: CGFloat = 0 var a: CGFloat = 0 if color?.getHue(&h, saturation: &s, brightness: &b, alpha: &a) ?? false { return UIColor(hue: h, saturation: max(s - 0.17, 0.0), brightness: min(b - 0.03, 1.0), alpha: a) } return .white } /// Gets the hex code value for a UIColor /// - Parameter color: UIColor intended to retrieve its hex value /// - Returns: Hex Code public class func hexString(for color: UIColor) -> String? { guard let components = color.cgColor.components else { return nil } let numberOfComponents = color.cgColor.numberOfComponents if numberOfComponents >= 3 { // RGB color space let r = Int(CGFloat(components[0]) * 255) let g = Int(CGFloat(components[1]) * 255) let b = Int(CGFloat(components[2]) * 255) // If alpha of color is less than 1.0 then alpha hex is relevant. if color.cgColor.numberOfComponents == 4 && components[3] < 1.0 { let a = Int(CGFloat(components[3]) * 255) return String(format: "%02X%02X%02X%02X", r, g, b, a) } return String(format: "%02X%02X%02X", r, g, b) } else if numberOfComponents == 2 { // Monochromatic color space let value = Int(CGFloat(components[0]) * 255) // If alpha of color is less than 1.0 then alpha hex is relevant. if components[1] < 1.0 { let alpha = Int(CGFloat(components[1]) * 255) return String(format: "%02X%02X%02X%02X", value, value, value, alpha) } return String(format: "%02X%02X%02X", value, value, value) } return nil } /// Gets the hex code value for the current UIColor /// - Returns: Hex Code string public var hexString: String? { guard let components = cgColor.components else { return nil } let numberOfComponents = cgColor.numberOfComponents if numberOfComponents >= 3 { // RGB color space let r = Int(CGFloat(components[0]) * 255) let g = Int(CGFloat(components[1]) * 255) let b = Int(CGFloat(components[2]) * 255) // If alpha of color is less than 1.0 then alpha hex is relevant. if cgColor.numberOfComponents == 4 && components[3] < 1.0 { let a = Int(CGFloat(components[3]) * 255) return String(format: "%02X%02X%02X%02X", r, g, b, a) } return String(format: "%02X%02X%02X", r, g, b) } else if numberOfComponents == 2 { // Monochromatic color space let value = Int(CGFloat(components[0]) * 255) // If alpha of color is less than 1.0 then alpha hex is relevant. if components[1] < 1.0 { let alpha = Int(CGFloat(components[1]) * 255) return String(format: "%02X%02X%02X%02X", value, value, value, alpha) } return String(format: "%02X%02X%02X", value, value, value) } return nil } /// Initialize a UIColor with a HexCode string /// - Parameter hexString: HexCode string to convert to a UIColor public convenience init(hexString: String) { let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int = UInt64() Scanner(string: hex).scanHexInt64(&int) let a, r, g, b: UInt64 switch hex.count { case 3: // RGB (12-bit) (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) case 6: // RGB (24-bit) (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) case 8: // ARGB (32-bit) (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) default: (a, r, g, b) = (255, 0, 0, 0) } self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) } internal func isDark() -> Bool { var white: CGFloat = 0 var alpha: CGFloat = 0 if getWhite(&white, alpha: &alpha) { return white < 0.5 } return false } }