Search code examples
iosswiftuicolor

How do I convert a UIColor to a 3/4/6/8 digits hexadecimal string in Swift?


How do I convert a UIColor to a hexadecimal string of 3/4/6/8 digits in Swift?

How do I get a spectific one? for example, get "#0000FFFF" by calling UIColor.blue.eightDigitsString

Please See this:

5.2. The RGB hexadecimal notations: #RRGGBB

The CSS hex color notation allows a color to be specified by giving the channels as hexadecimal numbers, which is similar to how colors are often written directly in computer code. It’s also shorter than writing the same color out in rgb() notation.

The syntax of a is a <hash-token> token whose value consists of 3, 4, 6, or 8 hexadecimal digits. In other words, a hex color is written as a hash character, "#", followed by some number of digits 0-9 or letters a-f (the case of the letters doesn’t matter - #00ff00 is identical to #00FF00).

The number of hex digits given determines how to decode the hex notation into an RGB color:

6 digits
The first pair of digits, interpreted as a hexadecimal number, specifies the red channel of the color, where 00 represents the minimum value and ff (255 in decimal) represents the maximum. The next pair of digits, interpreted in the same way, specifies the green channel, and the last pair specifies the blue. The alpha channel of the color is fully opaque. In other words, #00ff00 represents the same color as rgb(0 255 0) (a lime green).

8 digits
The first 6 digits are interpreted identically to the 6-digit notation. The last pair of digits, interpreted as a hexadecimal number, specifies the alpha channel of the color, where 00 represents a fully transparent color and ff represent a fully opaque color. In other words, #0000ffcc represents the same color as rgb(0 0 100% / 80%) (a slightly-transparent blue).

3 digits
This is a shorter variant of the 6-digit notation. The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. The next two digits represent the green and blue channels, respectively, in the same way. The alpha channel of the color is fully opaque. This syntax is often explained by saying that it’s identical to a 6-digit notation obtained by "duplicating" all of the digits. For example, the notation #123 specifies the same color as the notation #112233. This method of specifying a color has lower "resolution" than the 6-digit notation; there are only 4096 possible colors expressible in the 3-digit hex syntax, as opposed to approximately 17 million in 6-digit hex syntax.

4 digits
This is a shorter variant of the 8-digit notation, "expanded" in the same way as the 3-digit notation is. The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. The next three digits represent the green, blue, and alpha channels, respectively.

Now I already know how to convert a UIColor object to a 6-digits hex string. But I'm not sure how to convert it to a 3-digits/4-digits/8-digits hex string and what should be noticed.

guard let components = cgColor.components, components.count >= 3 else {
    return nil
}
let r = Float(components[0])
let g = Float(components[1])
let b = Float(components[2])
var a = Float(1.0)
if components.count >= 4 {
    a = Float(components[3])
}
if alpha {
    // rrggbbaa mode
    // is there any difference between rrggbbaa and aarrggbb?
    return String(format: "%02lX%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255), lroundf(a * 255))
} else {
    // rrggbb mode
    return String(format: "%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255))
}

NOTE: it's UIColor to string, not string to UIColor


Solution

  • Here's an extension for UIColor that can provide hexStrings in many formats including 3, 4, 6, and 8 digit forms:

    extension UIColor {
        enum HexFormat {
            case RGB
            case ARGB
            case RGBA
            case RRGGBB
            case AARRGGBB
            case RRGGBBAA
        }
    
        enum HexDigits {
            case d3, d4, d6, d8
        }
    
        func hexString(_ format: HexFormat = .RRGGBBAA) -> String {
            let maxi = [.RGB, .ARGB, .RGBA].contains(format) ? 16 : 256
    
            func toI(_ f: CGFloat) -> Int {
                return min(maxi - 1, Int(CGFloat(maxi) * f))
            }
    
            var r: CGFloat = 0
            var g: CGFloat = 0
            var b: CGFloat = 0
            var a: CGFloat = 0
    
            self.getRed(&r, green: &g, blue: &b, alpha: &a)
    
            let ri = toI(r)
            let gi = toI(g)
            let bi = toI(b)
            let ai = toI(a)
    
            switch format {
            case .RGB:       return String(format: "#%X%X%X", ri, gi, bi)
            case .ARGB:      return String(format: "#%X%X%X%X", ai, ri, gi, bi)
            case .RGBA:      return String(format: "#%X%X%X%X", ri, gi, bi, ai)
            case .RRGGBB:    return String(format: "#%02X%02X%02X", ri, gi, bi)
            case .AARRGGBB:  return String(format: "#%02X%02X%02X%02X", ai, ri, gi, bi)
            case .RRGGBBAA:  return String(format: "#%02X%02X%02X%02X", ri, gi, bi, ai)
            }
        }
    
        func hexString(_ digits: HexDigits) -> String {
            switch digits {
            case .d3: return hexString(.RGB)
            case .d4: return hexString(.RGBA)
            case .d6: return hexString(.RRGGBB)
            case .d8: return hexString(.RRGGBBAA)
            }
        }
    }
    

    Examples

    print(UIColor.red.hexString(.d3))  // #F00
    print(UIColor.red.hexString(.d4))  // #F00F
    print(UIColor.red.hexString(.d6))  // #FF0000
    print(UIColor.red.hexString(.d8))  // #FF0000FF
    
    print(UIColor.green.hexString(.RGB))  // #0F0
    print(UIColor.green.hexString(.ARGB))  // #F0F0
    print(UIColor.green.hexString(.RGBA))  // #0F0F
    print(UIColor.green.hexString(.RRGGBB))  // #00FF00
    print(UIColor.green.hexString(.AARRGGBB))  // #FF00FF00
    print(UIColor.green.hexString(.RRGGBBAA))  // #00FF00FF
    
    print(UIColor(red: 0.25, green: 0.5, blue: 0.75, alpha: 0.3333).hexString()) // #4080c055