Getting hue from UIColor yields wrong result - swift

I'm doing the following in order to retrieve the hue from a UIColor():
let rgbColour = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
var hue: CGFloat = 0
var saturation: CGFloat = 0
var brightness: CGFloat = 0
var alpha: CGFloat = 0
rgbColour.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
println("\(hue),\(saturation),\(brightness)")
Output:
1.0,1.0,1.0
According to this link, I'm meant to be getting 0.0,1.0,1.0 for RGB (red) 1.0,0.0,0.0.
Am I doing something wrong?

First of all the range of the red/green/blue components in UIColor is 0.0 .. 1.0,
not 0.0 .. 255.0, so you probably want
let rgbColour = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
But even then you get the output 1.0,1.0,1.0 and this is correct.
The hue component ranges from 0.0 to 1.0, which corresponds to the angle from 0º to 360º
in a color wheel (see for example HSL and HSV).
Therefore hue = 0.0 and hue = 1.0 describe an identical color.
If you need to normalize the hue component to the half-open interval
0.0 <= hue < 1.0 then you could do that with
hue = fmod(hue, 1.0)

To build on #Martin R's answer:
If you wanted to use HSB, you need to:
Divide the hue value by 360
Use decimals for the Saturation and Brightness values
So, say for example that Sketch is telling you the colour values in HSB are: Hue: 20, Saturation: 72 and Brightness: 96
In Xcode, create the colour as follows:
let myAwesomeColour = UIColor(hue: 20/360, saturation: 0.72, brightness: 0.96, alpha: 1.0)
Whether you use RGB or HSB is a matter of preference. The results are the same as far as Xcode is concerned, they both translate to a UIColor.

Related

How to convert HSV(HSB) to range 0...1

I get HSB as 29, 90, 100.
How to convert it to the range 0...1?
UIColor is initialized only in this range, so I have a question.
let red: CGFloat = 1
let green: CGFloat = 0.5372
let blue: CGFloat = 0.0941
let hueOut = 29
let satOut = 90
let brightnessOut = 100
let color = UIColor(red: red, green: green, blue: blue, alpha: 1.0)
///r 1,0 g 0,537 b 0,094 a 1,0
let color2 = UIColor(hue: hueOut, saturation: satOut, brightness: brightnessOut, alpha: 1.0)
///r -9,0 g 0,0 b -3,0 a 1,0
Looks like your hue range is 0...360 and your saturation and brightness are 0...100. You just need to convert your integer to double and divide by 360 or 100:
let color2 = UIColor(hue: Double(hueOut)/360, saturation: Double(satOut)/100, brightness: Double(brightnessOut)/100, alpha: 1.0)
This will result in r 1.0 g 0.535 b 0.1 a 1.0

Type 'NSColor' has no member 'black'

I'm working with Swift and SceneKit in Xcode 9.2. I've been applying color to geometry with NSColor, but all of a sudden (gradually) most of my colors get the type NSColor has no member .colorname. Like my game compiled and ran just fine, and then on the next compile, I got an error with .cyan. I changed it to .black and it ran. Then another color got an error, and then most of the colors got an error.
Here's an example:
node.geometry?.firstMaterial?.diffuse.contents = NSColor.black
the options that I have left are:
.blue, .green, .int, .rawValue, .red, .yellow.
What happened to all the colors?
EDIT: I cleaned up the project, it all compiles without warnings but I still only have 4 colors and they all render gray. I printed out the nodes diffuse colors to console and they read correct.
I've also imported Cocoa framework.
EDIT: I FOUND MY MISTAKE.
I accidentally replaced the name of an enum with NSColor while doing a find and replace. That's why SKColor worked, because it was a new name.
I am so embarrassed.
You could use:
node.geometry?.firstMaterial?.diffuse.contents = NSColor(srgbRed: 0, green: 0, blue: 0, alpha: 1.0)
In this way you create a color with your own RGBs values, so in this way you can get the color black. The last parameter, alpha, is the value of opacity and it needs to be 100 in order to see the color
In your case the better way is to use this syntax:
NSColor(calibratedRed: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
In iOS you should use the syntax like this:
cube.firstMaterial?.diffuse.contents = UIColor(red: 0.3, green: 0.45, blue: 0.75, alpha: 1.0)
In macOS the syntax is like this:
sphere.firstMaterial?.reflective.contents = NSColor(calibratedRed: 99.0, green: 0.0, blue: 0.0, alpha: 1.0)
Remember, the alpha (aka opacity), specified as a value from 0.0-1.0. Alpha values below 0 are interpreted as 0.0, and values above 1.0 are interpreted as 1.0.
And, of course, you can specify the colorspace explicitly (like sRGB):
init(srgbRed: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)

Find hue, saturation, brightness and alpha of a UIColor

I have a red object:
red_object = UIColor.red.cgColor
I would like to get the hue saturation brightness and alpha parameters of this 'red' so I can recode my red &object using more specific parameters.
This exercise would be a once off but I need these parameters.
I have tried cgColor.components but I don't think this is the right function:
red_test = UIColor.red.cgColor
let output = red_test.components
print(output) = Optional([1.0, 0.0, 0.0, 1.0])
but if I run the following
let circlePathT = UIBezierPath(arcCenter: CGPoint(x: x_mid,y: y_mid), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
let red_object = CAShapeLayer()
red_object.fillColor = UIColor(hue: 1, saturation: 0, brightness: 0, alpha: 1).cgColor
I get a black circle, not red.
More specifically I am expecting
red_object.fillColor = UIColor(hue: 1, saturation: 0, brightness: 0, alpha: 1).cgColor
to equal
red_test = UIColor.red.cgColor
but it isn't
Why you're getting the "wrong" component values
You'll find that the components of a CGColor is the values of the components in the color's color space. Since there is no hue-saturation-brighness-alpha color space model, these won't be the color's hue saturation, or brightness.
Instead, you're likely to find either red-green-blue-alpha values for colors in an RGB color space model (like UIColor.red) or white-alpha values for colors in a monochrome color space model (like UIColor.gray).
UIColor.red.cgColor.components // [1.0, 0.0, 0.0, 1.0]
UIColor.red.cgColor.colorSpace?.name. // kCGColorSpaceExtendedSRGB
UIColor.gray.cgColor.components // [0.5, 1.0]
UIColor.gray.cgColor.colorSpace?.name // kCGColorSpaceExtendedGray
Looking at the component values for red (1, 0, 0, 1) it makes sense that these wouldn't be hue, saturation, brightness, and alpha — since any color with a 0 brightness would be completely black, and any color with 0 saturation would be fully desaturated.
Instead, we would expect both the brightness and saturation of red to be 100%, like how they appear in the color picker:
How to get the hue, saturation, brightness, and alpha of a color
If you want to get the hue, saturation, brightness, and alpha of a color — no matter the color space it is in — you'd use getHue(_:saturation:brightness:alpha:) and pass four mutable pointers to CGFloat values:
var hue : CGFloat = 0
var saturation : CGFloat = 0
var brightness : CGFloat = 0
var alpha : CGFloat = 0
let couldBeConverted = UIColor.red.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
if couldBeConverted {
// The color is in a compatible color space, and the variables
// `hue`, `saturation`, `brightness`, and `alpha` have been
// changed to contain these values.
}
Note that this method is on UIColor. If you have a CGColor reference then you'll have to create a UIColor to read its HSBA components:
UIColor(cgColor: yourCGColor)

How to guarantee that an NSColor has enough saturation?

I need to guarantee that a color has enough saturation.
I made this extension to NSColor but my tests give me weird values: tempColor always seems to have lots of saturation.
So basically my function always returns self?
Where's my mistake?
I've also tried without converting to NSCalibratedRGBColorSpace but that didn't help and the input color can be of different type anyway.
extension NSColor {
func withMinimumSaturation(minimumSaturation: CGFloat) -> NSColor {
// color could be hue/rgb/other so we convert to rgb
if var tempColor = self.colorUsingColorSpaceName(NSCalibratedRGBColorSpace) {
// prepare the values
var hue: CGFloat = 0.0
var saturation: CGFloat = 0.0
var brightness: CGFloat = 0.0
var alpha: CGFloat = 0.0
// populate the values
tempColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
// if color is not enough saturated
if saturation < minimumSaturation {
// return same color with more saturation
return NSColor(calibratedHue: hue, saturation: minimumSaturation, brightness: brightness, alpha: alpha)
}
}
// if detection fails, return same color
return self
}
}
Usage:
let source = myColorFromAListOfColors // NSColor
let guaranteed = source.withMinimumSaturation(0.15)
EDIT: actually it works. I've accepted Aaron's answer because it helped me understand the situation (I was comparing the colors with their redComponents and they were often similar).
Your method seems fine.
For colors with very low saturation, it returns a different color:
If I increase the minimum saturation from 0.15 to something more significant, like 0.45, the change is more significant:
So, this method works as I expect it would. I'm guessing you just need to tweak that 0.15 input to get the results you want.
It may help you to log the old and new saturations for debugging:
if saturation < minimumSaturation {
// return same color with more saturation
println("New saturation: \(minimumSaturation)")
return NSColor(calibratedHue: hue, saturation: minimumSaturation, brightness: brightness, alpha: alpha)
} else {
println("Discarding saturation: \(saturation)")
}

How to update SKLabelNode color after the node is initiated?

I have SKLabelNode in my Swift-code. I need to change the Label's color during SKAction. Simply:
override func didMoveToView(view: SKView) {
...
var color = UIColor(red: CGFloat(1.0), green: CGFloat(0.0), blue: CGFloat(0.0), alpha: CGFloat(0.0))
myLabel.fontColor = color
...
}
Doesn't work. I still have to somehow update the node but how? I'm noobie to Swift and Sprite Kit.
Do you need it to be in an SKAction? If not, simply use this:
myLabel.fontColor = SKColor.blueColor()
Substitute blueColor with whichever color you want, or use the generic method where 'float here' is a fraction of 255 (such as 50.0f/255.0f).
myLabel.fontColor = SKColor(red: floatHere, green: floatHere, blue: floatHere, alpha: floatFrom0To1Here)
In case you do need to set the color through an SKAction, you can use this method:
myLabel.runAction(SKAction.colorizeWithColor(UIColor.blueColor(), colorBlendFactor: 1, duration: 1))
I had a similar problem a few weeks ago.
Try changing your color variable to the following:
var color = UIColor(red: 1.0 / 255, green: 0.0 / 255, blue: 0.0 / 255, alpha: 0.0)