How to get RGB components from Color in SwiftUI How to get RGB components from Color in SwiftUI swift swift

How to get RGB components from Color in SwiftUI


iOS 14 / macOS 10.16

There is a new initializer that takes a Color and returns a UIColor for iOS or NSColor for macOS now. With the help of those you can implement the following extensions:

iOS / macOS

import SwiftUI#if canImport(UIKit)import UIKit#elseif canImport(AppKit)import AppKit#endifextension Color {    var components: (red: CGFloat, green: CGFloat, blue: CGFloat, opacity: CGFloat) {        #if canImport(UIKit)        typealias NativeColor = UIColor        #elseif canImport(AppKit)        typealias NativeColor = NSColor        #endif        var r: CGFloat = 0        var g: CGFloat = 0        var b: CGFloat = 0        var o: CGFloat = 0        guard NativeColor(self).getRed(&r, green: &g, blue: &b, alpha: &o) else {            // You can handle the failure here as you want            return (0, 0, 0, 0)        }        return (r, g, b, o)    }}

Usage

Color.red.components.red // 0.9999999403953552 // <- SwiftUI Colors are not pure!


Waiting for an API I've abused CustomStringConvertible protocol for the simple rgba case where the color description format is #rrggbbaa

debugPrint(Color.red)debugPrint(Color(red: 1.0, green: 0.0, blue: 0.0))debugPrint(Color(red: 1.0, green: 0.3, blue: 0.0))debugPrint(Color(.sRGB, red: 1.0, green: 0.0, blue: 0.5, opacity: 0.3))debugPrint(Color(hue: 1.0, saturation: 0.0, brightness: 1.0))debugPrint(Color(.displayP3, red: 1.0, green: 0.0, blue: 0.0, opacity: 1.0).description)red#FF0000FF#FF4C00FF#FF00804D#FFFFFFFF"DisplayP3(red: 1.0, green: 0.0, blue: 0.0, opacity: 1.0)"

as you can see, things like Color.red just dump "red" but if you are working with simple RGB colors generated by code (ie from a color picker) then this is not too bad

extension SwiftUI.Color {    var redComponent: Double? {        let val = description        guard val.hasPrefix("#") else { return nil }        let r1 = val.index(val.startIndex, offsetBy: 1)        let r2 = val.index(val.startIndex, offsetBy: 2)        return Double(Int(val[r1...r2], radix: 16)!) / 255.0    }    var greenComponent: Double? {        let val = description        guard val.hasPrefix("#") else { return nil }        let g1 = val.index(val.startIndex, offsetBy: 3)        let g2 = val.index(val.startIndex, offsetBy: 4)        return Double(Int(val[g1...g2], radix: 16)!) / 255.0    }    var blueComponent: Double? {        let val = description        guard val.hasPrefix("#") else { return nil }        let b1 = val.index(val.startIndex, offsetBy: 5)        let b2 = val.index(val.startIndex, offsetBy: 6)        return Double(Int(val[b1...b2], radix: 16)!) / 255.0    }    var opacityComponent: Double? {        let val = description        guard val.hasPrefix("#") else { return nil }        let b1 = val.index(val.startIndex, offsetBy: 7)        let b2 = val.index(val.startIndex, offsetBy: 8)        return Double(Int(val[b1...b2], radix: 16)!) / 255.0    }}


You can use UIColor and transform the UIColor to Color after.Code:

extension UIColor {    func hexValue() -> String {        let values = self.cgColor.components        var outputR: Int = 0        var outputG: Int = 0        var outputB: Int = 0        var outputA: Int = 1        switch values!.count {            case 1:                outputR = Int(values![0] * 255)                outputG = Int(values![0] * 255)                outputB = Int(values![0] * 255)                outputA = 1            case 2:                outputR = Int(values![0] * 255)                outputG = Int(values![0] * 255)                outputB = Int(values![0] * 255)                outputA = Int(values![1] * 255)            case 3:                outputR = Int(values![0] * 255)                outputG = Int(values![1] * 255)                outputB = Int(values![2] * 255)                outputA = 1            case 4:                outputR = Int(values![0] * 255)                outputG = Int(values![1] * 255)                outputB = Int(values![2] * 255)                outputA = Int(values![3] * 255)            default:                break        }        return "#" + String(format:"%02X", outputR) + String(format:"%02X", outputG) + String(format:"%02X", outputB) + String(format:"%02X", outputA)    }}