Skip to content

Commit

Permalink
feature(color): Add SwiftUI Color support for hex (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcvz authored Jan 2, 2024
1 parent ca8f4a8 commit 928dec9
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 49 deletions.
15 changes: 15 additions & 0 deletions Sources/DSKit/SwiftUI/Color+Hex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Color+Hex.swift
// DSKit
//
// Created by David Chavez on 1/2/24.
//

import SwiftUI

extension Color {
init(hex: String) {
let (r, g, b, a) = hexToRGB(hex: hex)
self.init(.sRGB, red: Double(r), green: Double(g), blue: Double(b), opacity: Double(a))
}
}
59 changes: 12 additions & 47 deletions Sources/DSKit/UIKit/UIColor/UIColor+Hex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,20 @@
import UIKit

extension UIColor {
/// initializes a UIColor from the corresponding 6-digit hexadecimal color code
/// example: UIColor.init(hex: "#0C0C1D")
public convenience init?(hex: String) {
let red, green, blue, alpha: CGFloat

if hex.hasPrefix("#") {
let start = hex.index(hex.startIndex, offsetBy: 1)
let hexColor = String(hex[start...])

if hexColor.count == 8 {
let scanner = Scanner(string: hexColor)
var hexNumber: UInt64 = 0

if scanner.scanHexInt64(&hexNumber) {
red = CGFloat((hexNumber & 0xff000000) >> 24) / 255
green = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
blue = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
alpha = CGFloat(hexNumber & 0x000000ff) / 255

self.init(red: red, green: green, blue: blue, alpha: alpha)
return
}
} else if hexColor.count == 6 {
let scanner = Scanner(string: hexColor)
var hexNumber: UInt64 = 0

if scanner.scanHexInt64(&hexNumber) {
red = CGFloat((hexNumber & 0xff0000) >> 16) / 255
green = CGFloat((hexNumber & 0x00ff00) >> 8) / 255
blue = CGFloat(hexNumber & 0x0000ff) / 255

self.init(red: red, green: green, blue: blue, alpha: 1.0)
return
}
}
}

return nil
convenience init(hex: String) {
let (r, g, b, a) = hexToRGB(hex: hex)
self.init(red: r, green: g, blue: b, alpha: a)
}

var hexValue: String {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0

getRed(&red, green: &green, blue: &blue, alpha: nil)

let rgb: Int = (Int)(red * 255) << 16 | (Int)(green * 255) << 8 | (Int)(blue * 255) << 0

return String(format: "#%06x", rgb)
guard let components = cgColor.components, components.count >= 3 else {
return ""
}
let red = Int(components[0] * 255)
let green = Int(components[1] * 255)
let blue = Int(components[2] * 255)
return String(format: "#%02X%02X%02X", red, green, blue)
}
}
29 changes: 29 additions & 0 deletions Sources/DSKit/Utils/HexToRGB.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// HexToRGB.swift
// DSKit
//
// Created by David Chavez on 11.01.22.
//

import Foundation
import CoreFoundation

internal func hexToRGB(hex: String) -> (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
let hex = hex.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: // RRGGBBAA (32-bit)
(r, g, b, a) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
(a, r, g, b) = (1, 1, 1, 0)
}

return (CGFloat(r)/255, CGFloat(g)/255, CGFloat(b)/255, CGFloat(a)/255)
}
3 changes: 2 additions & 1 deletion Tests/DSKitTests/ApplicableTests.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//
// ApplicableTests.swift
//
// DSKit
//
// Created by Fabian Sulzbacher on 29.04.21.
//

import XCTest
@testable import DSKit

Expand Down
35 changes: 35 additions & 0 deletions Tests/DSKitTests/SwiftUI/Color+Hex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Color+Hex.swift
// DSKit
//
// Created by David Chavez on 1/2/24.
//

import XCTest
@testable import DSKit

class HexToRGBTests: XCTestCase {
func testHexToRGB() {
let rgb = hexToRGB(hex: "#0C0C1D")
XCTAssertEqual(rgb.red, 12.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.green, 12.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.blue, 29.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.alpha, 1.0, accuracy: 0.001)
}

func testHexToRGBWithShortForm() {
let rgb = hexToRGB(hex: "#0C1")
XCTAssertEqual(rgb.red, 0.0, accuracy: 0.001)
XCTAssertEqual(rgb.green, 204.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.blue, 17.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.alpha, 1.0, accuracy: 0.001)
}

func testHexToRGBWithAlpha() {
let rgb = hexToRGB(hex: "#0C0C1D80")
XCTAssertEqual(rgb.red, 12.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.green, 12.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.blue, 29.0/255.0, accuracy: 0.001)
XCTAssertEqual(rgb.alpha, 128.0/255.0, accuracy: 0.001)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//
// GradientTests.swift
//
// DSKit
//
// Created by David Chavez on 13.04.21.
//

import XCTest
@testable import DSKit

Expand Down

0 comments on commit 928dec9

Please sign in to comment.