Return Lighter Color from Skcolor Using Hsl Lightness Factor

Return lighter color from SKColor using HSL lightness factor

Xcode 8.2.1 • Swift 3.0.2

extension UIColor {
convenience init(hue: CGFloat, saturation: CGFloat, lightness: CGFloat, alpha: CGFloat = 1) {
let offset = saturation * (lightness < 0.5 ? lightness : 1 - lightness)
let brightness = lightness + offset
let saturation = lightness > 0 ? 2 * offset / brightness : 0
self.init(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
}
var lighter: UIColor? {
return applying(lightness: 1.25)
}
func applying(lightness value: CGFloat) -> UIColor? {
guard let hsl = hsl else { return nil }
return UIColor(hue: hsl.hue, saturation: hsl.saturation, lightness: hsl.lightness * value, alpha: hsl.alpha)
}
var hsl: (hue: CGFloat, saturation: CGFloat, lightness: CGFloat, alpha: CGFloat)? {
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0, hue: CGFloat = 0
guard
getRed(&red, green: &green, blue: &blue, alpha: &alpha),
getHue(&hue, saturation: nil, brightness: nil, alpha: nil)
else { return nil }
let upper = max(red, green, blue)
let lower = min(red, green, blue)
let range = upper - lower
let lightness = (upper + lower) / 2
let saturation = range == 0 ? 0 : range / (lightness < 0.5 ? lightness * 2 : 2 - lightness * 2)
return (hue, saturation, lightness, alpha)
}
}

let purple = UIColor(red: 160/255, green: 118/255, blue: 200/255, alpha: 1)
let lighter = purple.lighter

Get Slightly Lighter and Darker Color from UIColor

- (UIColor *)lighterColorForColor:(UIColor *)c
{
CGFloat r, g, b, a;
if ([c getRed:&r green:&g blue:&b alpha:&a])
return [UIColor colorWithRed:MIN(r + 0.2, 1.0)
green:MIN(g + 0.2, 1.0)
blue:MIN(b + 0.2, 1.0)
alpha:a];
return nil;
}

- (UIColor *)darkerColorForColor:(UIColor *)c
{
CGFloat r, g, b, a;
if ([c getRed:&r green:&g blue:&b alpha:&a])
return [UIColor colorWithRed:MAX(r - 0.2, 0.0)
green:MAX(g - 0.2, 0.0)
blue:MAX(b - 0.2, 0.0)
alpha:a];
return nil;
}

Use it like this:

UIColor *baseColor = // however you obtain your color
UIColor *lighterColor = [self lighterColorForColor:baseColor];
UIColor *darkerColor = [self darkerColorForColor:baseColor];

EDIT: as @Anchu Chimala pointed out, for maximum flexibility, these methods should be implemented as an UIColor category. Also, from @Riley's idea, it may be a better idea to make the color proprtionally darker or lighter instead of adding or subtracting constant values. As @jrturton pointed out, it's not necessary to manipulate the RGB components; it's better to modify the brightness property itself. All in all:

@implementation UIColor (LightAndDark)

- (UIColor *)lighterColor
{
CGFloat h, s, b, a;
if ([self getHue:&h saturation:&s brightness:&b alpha:&a])
return [UIColor colorWithHue:h
saturation:s
brightness:MIN(b * 1.3, 1.0)
alpha:a];
return nil;
}

- (UIColor *)darkerColor
{
CGFloat h, s, b, a;
if ([self getHue:&h saturation:&s brightness:&b alpha:&a])
return [UIColor colorWithHue:h
saturation:s
brightness:b * 0.75
alpha:a];
return nil;
}
@end

Given a hex for a color, how can I make that color lighter and darker?]

import UIKit

extension StringProtocol {
subscript(range: Range<Int>) -> SubSequence {
let start = self.index(startIndex, offsetBy: range.lowerBound, limitedBy: endIndex) ?? endIndex
return self[start..<(self.index(start, offsetBy: range.count, limitedBy: endIndex) ?? endIndex)]
}
var hexaCGFloat: CGFloat { .init(strtoul(String(self), nil, 16)) }
}

extension UIColor {
var rgb: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? {
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
guard getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
return nil
}
return (red, green, blue, alpha)
}
var hsb: (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)? {
var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
guard getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) else {
return nil
}
return (hue, saturation, brightness, alpha)
}
var hsl: (hue: CGFloat, saturation: CGFloat, lightness: CGFloat, alpha: CGFloat)? {
guard let rgb = rgb, let hsb = hsb else { return nil }
let maximum = max(rgb.red, rgb.green, rgb.blue)
let minimum = min(rgb.red, rgb.green, rgb.blue)
let range = maximum - minimum
let lightness = (maximum + minimum) / 2.0
let saturation = range == 0 ? 0 : range / { return lightness < 0.5 ? lightness * 2 : 2 - (lightness * 2) }()
return (hsb.hue, saturation, lightness, hsb.alpha)
}
convenience init(hue: CGFloat, saturation: CGFloat, lightness: CGFloat , alpha: CGFloat) {
var saturation = saturation
let lightness = lightness * 2
saturation *= lightness <= 1 ? lightness : 2 - lightness
self.init(hue: hue,
saturation: lightness == 0 ? 0 : (2 * saturation) / (lightness + saturation),
brightness: (lightness+saturation)/2,
alpha: 1)
}
convenience init(hexa: String, alpha: Double) {
self.init(red: hexa[0..<2].hexaCGFloat / 255,
green: hexa[2..<4].hexaCGFloat / 255,
blue: hexa[4..<6].hexaCGFloat / 255,
alpha: .init(alpha))
}
}

Playground Testing

let color = UIColor(hexa: "5fc9f8", alpha: 1)

if let colorHSL = color.hsl {
let hue = colorHSL.hue
let saturation = colorHSL.saturation
let lightness = colorHSL.lightness
let lighterColor = UIColor(hue: hue,
saturation: saturation,
lightness: min(lightness * 1.3, 1),
alpha: 1)
let darkerColor = UIColor(hue: hue,
saturation: saturation,
lightness: max(lightness * 0.5, 0),
alpha: 1)
print("lighterColor:", lighterColor, "darkerColor:", darkerColor)
}

How to make UIColor softer

A better solution than lowering the alpha (which may cause other things behind it to appear) is to lower the color's saturation.

Here's a UIColor extension that gets the HSB of a color, lowers the saturation, and returns the new color with the same alpha:

extension UIColor {
func softer() -> UIColor {
var h: CGFloat = 0
var s: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
// Change the 0.5 to suit your needs
return UIColor(hue: h, saturation: s * 0.5, brightness: b, alpha: a)
} else {
return self
}
}
}

// Examples:
let orange = UIColor.orange
let softOrange = orange.softer()
let brown = UIColor(red: 0.4392, green: 0.2510, blue: 0.1882, alpha: 1.0)
let softBrown = brown.softer()

Converting from RGB to HSL with Objective C

NSColor is missing in iPhone SDK. You can use this utility to convert from RGB to HSL space and back:

https://github.com/alessani/ColorConverter

C#: Create a lighter/darker color based on a system color]

ControlPaint.Light .Dark .DarkDark, etc.

Color lightRed = ControlPaint.Light( Color.Red );

Determine font color based on background color

I encountered similar problem. I had to find a good method of selecting contrastive font color to display text labels on colorscales/heatmaps. It had to be universal method and generated color had to be "good looking", which means that simple generating complementary color was not good solution - sometimes it generated strange, very intensive colors that were hard to watch and read.

After long hours of testing and trying to solve this problem, I found out that the best solution is to select white font for "dark" colors, and black font for "bright" colors.

Here's an example of function I am using in C#:

Color ContrastColor(Color color)
{
int d = 0;

// Counting the perceptive luminance - human eye favors green color...
double luminance = (0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255;

if (luminance > 0.5)
d = 0; // bright colors - black font
else
d = 255; // dark colors - white font

return Color.FromArgb(d, d, d);
}

This was tested for many various colorscales (rainbow, grayscale, heat, ice, and many others) and is the only "universal" method I found out.

Edit

Changed the formula of counting a to "perceptive luminance" - it really looks better! Already implemented it in my software, looks great.

Edit 2
@WebSeed provided a great working example of this algorithm: http://codepen.io/WebSeed/full/pvgqEq/

Change from RGB to HSB on iPhone?

It just takes a little bit of math. The following code is just the important parts of the custom class I created for conversion. The "HSBColor" class stores just the hue, saturation, and brightness and I provide functions to get the components of it or a UIColor if I need to actually use it for something in the system.

Note: This code will not work as is unless you define an HSBColor class with hue, brightness, and saturation properties.

+(void)max:(int*)max andMin:(int*)min ofArray:(float[])array
{
*min=0;
*max=0;
for(int i=1; i<3; i++)
{
if(array[i] > array[*max])
*max=i;
if(array[i] < array[*min])
*min=i;
}
}

+(HSBColor*)colorWithRed:(float)red Green:(float)green Blue:(float)blue
{
HSBColor* toReturn = [[[HSBColor alloc] init] autorelease];

float colorArray[3];
colorArray[0] = red;
colorArray[1] = green;
colorArray[2] = blue;
//NSLog(@"RGB: %f %f %f",colorArray[0],colorArray[1],colorArray[2]);
int max;
int min;
[self max:&max andMin:&min ofArray:colorArray];

if(max==min)
{
toReturn.hue=0;
toReturn.saturation=0;
toReturn.brightness=colorArray[0];
}
else
{
toReturn.brightness=colorArray[max];

toReturn.saturation=(colorArray[max]-colorArray[min])/(colorArray[max]);

if(max==0) // Red
toReturn.hue = (colorArray[1]-colorArray[2])/(colorArray[max]-colorArray[min])*60/360;
else if(max==1) // Green
toReturn.hue = (2.0 + (colorArray[2]-colorArray[0])/(colorArray[max]-colorArray[min]))*60/360;
else // Blue
toReturn.hue = (4.0 + (colorArray[0]-colorArray[1])/(colorArray[max]-colorArray[min]))*60/360;
}
return toReturn;
}

+(HSBColor*)colorWithSystemColor:(UIColor*)color
{

const CGFloat* components = CGColorGetComponents(color.CGColor);

return [self colorWithRed:components[0] Green:components[1] Blue:components[2]];
}


Related Topics



Leave a reply



Submit