6

I came up with the following solution, but would like to know if someone has a cleaner approach to it (tested it in Xcode-Playground):

let colors = CGColorGetComponents( UIColor.greenColor().CGColor )
let hexCol:String = NSString(format: "#%02x%02x%02x", Int(colors[0] * 255.0), Int(colors[1] * 255.0), Int(colors[2] * 255.0))

resulting in #00ff00

where UIColor.greenColor() is an example for any UIColor.

edit: Taken from Leonardo's Answer, i felt like refactoring it a bit (all of his tests still apply).

extension UIColor {
    typealias RGBComponents = (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
    typealias HSBComponents = (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)

    var rgbComponents:RGBComponents {
        var c:RGBComponents = (0,0,0,0)

        if getRed(&c.red, green: &c.green, blue: &c.blue, alpha: &c.alpha) {
            return c
        }

        return (0,0,0,0)
    }

    var cssRGBA:String {
        return String(format: "rgba(%d,%d,%d, %.02f)", Int(rgbComponents.red * 255), Int(rgbComponents.green * 255), Int(rgbComponents.blue * 255), Float(rgbComponents.alpha))
    }
    var hexRGB:String {
        return String(format: "#%02x%02x%02x", Int(rgbComponents.red * 255), Int(rgbComponents.green * 255), Int(rgbComponents.blue * 255))
    }
    var hexRGBA:String {
        return String(format: "#%02x%02x%02x%02x", Int(rgbComponents.red * 255), Int(rgbComponents.green * 255), Int(rgbComponents.blue * 255), Int(rgbComponents.alpha * 255) )
    }

    var hsbComponents:HSBComponents {
        var c:HSBComponents = (0,0,0,0)

        if getHue(&c.hue, saturation: &c.saturation, brightness: &c.brightness, alpha: &c.alpha) {
            return c
        }

        return (0,0,0,0)
    }
}

let v1 = UIColor.redColor().rgbComponents.red
let v2 = UIColor.redColor().cssRGBA
let v3 = UIColor.redColor().hexRGBA
let v4test = UIColor.RGBComponents(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
BananaAcid
  • 3,221
  • 35
  • 38
  • 1
    possible duplicate of [How to convert UIColor to HEX and display in NSLog](http://stackoverflow.com/questions/26341008/how-to-convert-uicolor-to-hex-and-display-in-nslog) – Fogmeister Feb 24 '15 at 13:22
  • The answer given in that thread (which, btw, is given in Objective-C) has the same problem as the code in this question: CGColorGetComponents() does not necessarily return an array of RGBA components. For a grayscale color, it returns an array with only one gray component (and the code crashes). – Martin R Feb 24 '15 at 13:38
  • @LeonardoSavioDabus: I *assume* that `getRed(_: green: blue: alpha:)` fails if the UIColor has been created from a pattern image. It *might* also fail if the UIColor was created from an CIColor using other color spaces, such as CMYK. I did not test it. – Martin R Feb 24 '15 at 13:59
  • You mean HSB which works. I think there is no CMYK property. – Leo Dabus Feb 24 '15 at 14:02
  • what is the crux with CIColor and alike? – BananaAcid Feb 24 '15 at 14:06
  • @BananaAcid also added a way to extract hue, sat and brightness from the colors – Leo Dabus Feb 24 '15 at 22:53
  • @BananaAcid you should add your own answer instead of editing your question. – Leo Dabus Mar 13 '15 at 22:49
  • @Leonardo i actually wanted to add it as a comment, since you answered it and i only modified it. But somehow couldn't, except as "answering your own question" thing - just didn't feel right – BananaAcid Mar 16 '15 at 02:06

1 Answers1

16

Xcode 8.2 • Swift 3.0.2

Getting Red, Green, Blue and Alpha components from a UIColor:

extension UIColor {
    var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
        if getRed(&r, green: &g, blue: &b, alpha: &a) { 
            return (r,g,b,a)
        }
        return (0, 0, 0, 0)
    }

    // hue, saturation, brightness and alpha components from UIColor**
    var hsba: (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) {
        var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
        if getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
            return (hue, saturation, brightness, alpha)
        }
        return (0,0,0,0)
    }

    var htmlRGB: String {
        let rgbaCache = rgba
        return String(format: "#%02x%02x%02x", Int(round(rgbaCache.red * 255)), Int(round(rgbaCache.green * 255)), Int(round(rgbaCache.blue * 255)))
    }

    var htmlRGBA: String {
        let rgbaCache = rgba
        return String(format: "#%02x%02x%02x%02x", Int(round(rgbaCache.red * 255)), Int(round(rgbaCache.green * 255)), Int(round(rgbaCache.blue * 255)), Int(round(rgbaCache.alpha * 255)) )
    }
}

Testing it:

HTML Colors

let myWhiteWebColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1).htmlRGBA      // #ffffffff
let myGreyWebColor = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1).htmlRGBA // #7f7f7fff
let myBlackWebColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1).htmlRGBA      // #000000ff
let myRedWebColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1).htmlRGBA        // #ff0000ff
let myGreenWebColor = UIColor(red: 0, green: 1, blue: 0, alpha: 1).htmlRGBA      // #00ff00ff
let myBlueWebColor = UIColor(red: 0, green: 0, blue: 1, alpha: 1).htmlRGBA       // #0000ffff

let myColorBlack = UIColor.black.htmlRGBA              // #000000ff
let myLghtGrayColor = UIColor.lightGray.htmlRGBA       // #aaaaaaff
let myDarkGrayColor = UIColor.darkGray.htmlRGBA        // #555555ff

let myRedHueWebColor = UIColor(hue: 1, saturation: 1, brightness: 1, alpha: 1).htmlRGBA  //ff0000ff

RGB Components

UIColor.red.rgba        // (1.0, 0.0, 0.0, 1.0)
UIColor.red.rgba.red    // 1
UIColor.red.rgba.green  // 0
UIColor.red.rgba.blue   // 0
UIColor.red.rgba.alpha  // 1

UIColor.green.rgba       // (0.0, 1.0, 0.0, 1.0)
UIColor.green.rgba.red   // 0
UIColor.green.rgba.green // 1
UIColor.green.rgba.blue  // 0
UIColor.green.rgba.alpha // 1

UIColor.blue.rgba        // (0.0, 0.0, 1.0, 1.0)
UIColor.blue.rgba.red    // 0
UIColor.blue.rgba.green  // 0
UIColor.blue.rgba.blue   // 1
UIColor.blue.rgba.alpha  // 1

Hue Components

UIColor.red.hsba               // (0.0, 1.0, 1.0, 1.0)
UIColor.red.hsba.hue           // 1
UIColor.red.hsba.saturation    // 1
UIColor.red.hsba.brightness    // 1
UIColor.red.hsba.alpha         // 1

UIColor.green.hsba             // (0.333333333333333, 1.0, 1.0, 1.0)
UIColor.green.hsba.hue         // 0.3333333333333333
UIColor.green.hsba.saturation  // 1
UIColor.green.hsba.brightness  // 1
UIColor.green.hsba.alpha       // 1

UIColor.blue.hsba              // (0.666666666666667, 1.0, 1.0, 1.0)
UIColor.blue.hsba.hue          // 0.666666666666667
UIColor.blue.hsba.saturation   // 1.0
UIColor.blue.hsba.brightness   // 1.0
UIColor.blue.hsba.alpha        // 1.0

UIColor.clear.hsba       // (.0 0, .1 0, .2 0, .3 0)

UIColor.blue.htmlRGB     //"#0000ff"
UIColor.blue.htmlRGBA    //"#0000ffff"
Tomáš Kafka
  • 4,405
  • 6
  • 39
  • 52
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    I agree that `getRed(_: green: blue: alpha:)` is better than `CGColorGetComponents()`. But note that this method returns a boolean and can fail. – Suggestion: use `String(format: "#%02x%02x%02x", ...)` instead of *two* custom extensions just for formatting. – Martin R Feb 24 '15 at 13:53
  • @Martin R I can also use getHue but it already works with UIColors generated with the Hue input – Leo Dabus Feb 24 '15 at 14:07
  • 1
    HSB color are no problem, and it seems that CMYK colors are not available on iOS (you *can* create CMYK colors on OS X). So the only case where getRed(...) fails would be for `UIColor(patternImage: someImage)`. – Martin R Feb 24 '15 at 14:16
  • The extension is done. CMYK OSX doesn't matter because it uses NSColor. – Leo Dabus Feb 24 '15 at 17:54
  • Added also a way to extract hue components. In case of failure it just returns clearColor (0,0,0,0) for hsb and rgb components as well – Leo Dabus Feb 24 '15 at 22:50
  • 1
    Looks great so far, but I think, it would be more appealing, if you would remove the `String` and `Int` extensions, as Matin R suggests (like in my question post above) – BananaAcid Feb 25 '15 at 13:38
  • looks great, just found a minor thing to probably fix: http://www.w3.org/TR/css3-color/#rgba-color "Unlike RGB values, there is no hexadecimal notation for an RGBA value" .. only IE officially supports Hex-RGBA so `htmlRGBaColor` should probably output something like `rgba(255,255,255,1)` – BananaAcid Mar 05 '15 at 11:23
  • I edited the code to: 1) add rounding (without which `.white` gets converted to `#fefefe` instead of `#ffffff`) and 2) add caching (without which we would be needlessly calling the rgba extraction code multiple times unnecessarily). – Tomáš Kafka Apr 26 '22 at 07:32