24

i can set uicolor with RGB values:

[UIColor colorWithRed:0.53 green:0.37 blue:0.11 alpha:1.00];

i can set uicolor with hsb values:

[UIColor colorWithHue:0.10 saturation:0.16 brightness:0.13 alpha:1.00];

i also could convert it back to RGB:

CGFloat* colors = CGColorGetComponents(Color1.CGColor);

But how i can get HSB from uicolor?

Horhe Garcia
  • 882
  • 1
  • 13
  • 28
  • 1
    Possible duplicate of http://stackoverflow.com/questions/9142427/uicolor-conversion-from-rgb-to-hsv-set-brightness-to-uicolor http://stackoverflow.com/questions/3017553/converting-from-rgb-to-hsl-with-objective-c http://stackoverflow.com/questions/1050874/how-do-i-convert-rgb-into-hsv-in-cocoa-touch – He Shiming Apr 09 '12 at 10:14

4 Answers4

47

Use the UIColor method: getHue:saturation:brightness:alpha:

From the Apple docs:
"Returns the components that make up the color in the HSB color space."

- (BOOL)getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha

Example:

UIColor *testColor = [UIColor colorWithRed:0.53 green:0.37 blue:0.11 alpha:1.00];

CGFloat hue;
CGFloat saturation;
CGFloat brightness;
CGFloat alpha;
BOOL success = [testColor getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha];
NSLog(@"success: %i hue: %0.2f, saturation: %0.2f, brightness: %0.2f, alpha: %0.2f", success, hue, saturation, brightness, alpha);

NSLog output:

success: 1 hue: 0.10, saturation: 0.79, brightness: 0.53, alpha: 1.00

Here is a corrected version of the method provided by @WhiteTiger:

// Test values
CGFloat red = 0.53;
CGFloat green = 0.37;
CGFloat blue = 0.11;

CGFloat hue = 0;
CGFloat saturation = 0;
CGFloat brightness = 0;

CGFloat minRGB = MIN(red, MIN(green,blue));
CGFloat maxRGB = MAX(red, MAX(green,blue));

if (minRGB==maxRGB) {
    hue = 0;
    saturation = 0;
    brightness = minRGB;
} else {
    CGFloat d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red);
    CGFloat h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5);
    hue = (h - d/(maxRGB - minRGB)) / 6.0;
    saturation = (maxRGB - minRGB)/maxRGB;
    brightness = maxRGB;
}
NSLog(@"hue: %0.2f, saturation: %0.2f, value: %0.2f", hue, saturation, brightness);

NSLog output:

hue: 0.10, saturation: 0.79, value: 0.53

eonil
  • 83,476
  • 81
  • 317
  • 516
zaph
  • 111,848
  • 21
  • 189
  • 228
  • 2
    but this feature is bootable only by 5.0 – WhiteTiger Apr 09 '12 at 11:08
  • Over 75% of iOS users are on 5.0 now and a higher percentage of users who buy and/or update apps. If < 5.0 is a requirement please update your question. – zaph Apr 09 '12 at 11:16
  • you know, but there are cases, such as business where there is' an obligation to remain compatible with previous versions. – WhiteTiger Apr 09 '12 at 11:22
  • Your varient works perfectly, now im working on iOS 5 device, as i understood it wouldnt work on previos versions? if i need iOS do i have to use WhiteTiger's varient? – Horhe Garcia Apr 09 '12 at 19:03
  • 1
    The WhiteTiger variant works on any iOS version, the Apple getHue:saturation:brightness:alpha: variant works on iOS 5+. I added the WhiteTiger variant to my answer only because the early WhiteTiger versions had errors, now corrected. – zaph Apr 09 '12 at 19:11
  • @zaph, thanks for the great answer, but can I change the HSB values based on UISlider changes? – Hemang Jun 07 '16 at 03:23
  • You can possibly find an Xcode extension, [Alcatraz](http://alcatraz.io) is an Xcode extension manager. – zaph Jun 07 '16 at 03:40
28

Here is a nice way of using Swift features (extensions, computed properties and tuples) to do the same thing in just a few lines of code.

extension UIColor {
  var hsba: (h: CGFloat, s: CGFloat, b: CGFloat, a: CGFloat) {
    var hsba: (h: CGFloat, s: CGFloat, b: CGFloat, a: CGFloat) = (0, 0, 0, 0)
    self.getHue(&(hsba.h), saturation: &(hsba.s), brightness: &(hsba.b), alpha: &(hsba.a))
    return hsba
  }
}

Swift 3.2 / 4 minor update

Swift 3.2 / 4 enforced a new warning triggered with the previous code because you were modifying the hsba variable several times within the same call to getHue

Simultaneous accesses to parameter 'hsba', but modification requires exclusive access; consider copying to a local variable.

extension UIColor {
    var hsba: (h: CGFloat, s: CGFloat, b: CGFloat, a: CGFloat) {
        var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
        self.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
        return (h: h, s: s, b: b, a: a)
    }
}
aheze
  • 24,434
  • 8
  • 68
  • 125
apouche
  • 9,703
  • 6
  • 40
  • 45
4

Beware that it is a draft, but you can try this code, if you're lower to version 5.0

...
CGFloat computedH = 0;
CGFloat computedS = 0;
CGFloat computedV = 0;

CGFloat minRGB = MIN(r, MIN(g,b));
CGFloat maxRGB = MAX(r, MAX(g,b));

if (minRGB==maxRGB) {
   computedH = 0;
   computedS = 0;
   computedV = minRGB;
} else {
   double d = (r==minRGB) ? g-b : ((b==minRGB) ? r-g : b-r);
   double h = (r==minRGB) ? 3 : ((b==minRGB) ? 1 : 5);
   computedH = (60*(h - d/(maxRGB - minRGB))) / 360.;
   computedS = ((maxRGB - minRGB)/maxRGB);
   computedV = maxRGB;
}
...
WhiteTiger
  • 1,691
  • 1
  • 18
  • 23
  • Comments: THe line `r=r/255.; g=g/255.; b=b/255.;` is unneeded if the values are already `CGFloat`s. The final `computedV` needs to be divided by 360.0 to obtain a value in the interval 0.0 to 1.0. The `double` types might be better as `CGFloat`. – zaph Apr 09 '12 at 11:29
  • I corrected your conversion routine and added it to my answer with a test case. – zaph Apr 09 '12 at 11:37
  • There are to many divisions by 360, `computedS` and `computedV` are incorrect. Only hue needs to be divided by 360 because it is an angle. – zaph Apr 09 '12 at 11:46
2

Just use the following segment of code and you are done for good with rgba, hsba conversion.

extension UIColor {

/**
 Decomposes UIColor to its RGBA components
 */
var rgbColor: RGBColor {
    get {
        var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return RGBColor(red: red, green: green, blue: blue, alpha: alpha)
    }
}

/**
 Decomposes UIColor to its HSBA components
 */
var hsbColor: HSBColor {
    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
    self.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
    return HSBColor(hue: h, saturation: s, brightness: b, alpha: a)
}

/**
 Holds the CGFloat values of HSBA components of a color
 */
public struct HSBColor {
    var hue: CGFloat
    var saturation: CGFloat
    var brightness: CGFloat
    var alpha: CGFloat

    var uiColor: UIColor {
        get {
            return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
        }
    }
}

/**
 Holds the CGFloat values of RGBA components of a color
 */
public struct RGBColor {
    var red: CGFloat
    var green: CGFloat
    var blue: CGFloat
    var alpha: CGFloat

    var uiColor: UIColor {
        get {
            return UIColor(red: red, green: green, blue: blue, alpha: alpha)
        }
    }
}
}