Created
October 7, 2025 04:22
-
-
Save winstondu/a0625acc4c350a89bd7146e385a9a235 to your computer and use it in GitHub Desktop.
Hex extension for Color
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // Color+Hex.swift | |
| // | |
| import SwiftUI | |
| extension Color { | |
| // MARK: - Private Helpers | |
| /// Parses a sanitized 6-digit hex string (RRGGBB) into normalized RGB components. | |
| /// - Parameter hexSanitized: Hex string without leading '#', must be exactly 6 characters. | |
| /// - Returns: Tuple of (red, green, blue) in 0.0...1.0 if parsing succeeds; otherwise nil. | |
| private static func rgbComponents(fromSixDigitHex hexSanitized: String) -> ( | |
| red: Double, green: Double, blue: Double | |
| )? { | |
| guard hexSanitized.count == 6 else { return nil } | |
| var rgb: UInt64 = 0 | |
| guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil } | |
| let red = Double((rgb >> 16) & 0xFF) / 255.0 | |
| let green = Double((rgb >> 8) & 0xFF) / 255.0 | |
| let blue = Double(rgb & 0xFF) / 255.0 | |
| return (red, green, blue) | |
| } | |
| public init?(hex: String) { | |
| var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() | |
| // Remove hash if it exists | |
| if hexSanitized.hasPrefix("#") { | |
| hexSanitized.remove(at: hexSanitized.startIndex) | |
| } | |
| // Support 6-digit (RRGGBB) and 8-digit (RRGGBBAA) hex strings | |
| if hexSanitized.count == 8 { | |
| let alphaHex = String(hexSanitized.suffix(2)) | |
| let rgbHex = String(hexSanitized.prefix(6)) | |
| var alphaInt: UInt64 = 0 | |
| guard Scanner(string: alphaHex).scanHexInt64(&alphaInt) else { return nil } | |
| let alpha = Double(alphaInt) / 255.0 | |
| guard let comps = Color.rgbComponents(fromSixDigitHex: rgbHex) else { return nil } | |
| self.init(.sRGB, red: comps.red, green: comps.green, blue: comps.blue, opacity: alpha) | |
| return | |
| } else if hexSanitized.count == 6 { | |
| guard let comps = Color.rgbComponents(fromSixDigitHex: hexSanitized) else { return nil } | |
| self.init(red: comps.red, green: comps.green, blue: comps.blue) | |
| return | |
| } else { | |
| // Invalid length | |
| return nil | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment