Search code examples
iosswiftcolorsswiftuiuicolor

Swift | Use HSL color space instead of standard HSB/HSV


I am currently working on an HSL color picker, which needs the HSL color space.

But from what I have found, both UIColor and Color can only be initialized with brightness, instead of lightness which is what I need.

Is there a way to use the HSL color space instead of the default HSB/HSV one?

Say, what is the best practice to convert from HSB to HSL?

Thank you!


Solution

  • You could simply create an HSL color space initializer.

    Note: The formula inside the //From HSL TO HSB --------- part is taken from https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_HSV

    Here goes the Implementation:

    With UIColor

    import UIKit 
    
    extension UIColor {
        convenience init(hue: CGFloat, saturation: CGFloat, lightness: CGFloat, alpha: CGFloat) {
            precondition(0...1 ~= hue &&
                         0...1 ~= saturation &&
                         0...1 ~= lightness &&
                         0...1 ~= alpha, "input range is out of range 0...1")
            
            //From HSL TO HSB ---------
            var newSaturation: CGFloat = 0.0
            
            let brightness = lightness + saturation * min(lightness, 1-lightness)
            
            if brightness == 0 { newSaturation = 0.0 }
            else {
                newSaturation = 2 * (1 - lightness / brightness)
            }
            //---------
            
            self.init(hue: hue, saturation: newSaturation, brightness: brightness, alpha: alpha)
        }
    }
    

    With Color

    import SwiftUI
    
    extension Color {
        init(hue: Double, saturation: Double, lightness: Double, opacity: Double) {
            precondition(0...1 ~= hue &&
                         0...1 ~= saturation &&
                         0...1 ~= lightness &&
                         0...1 ~= opacity, "input range is out of range 0...1")
            
            //From HSL TO HSB ---------
            var newSaturation: Double = 0.0
            
            let brightness = lightness + saturation * min(lightness, 1-lightness)
            
            if brightness == 0 { newSaturation = 0.0 }
            else {
                newSaturation = 2 * (1 - lightness / brightness)
            }
            //---------
            
            self.init(hue: hue, saturation: newSaturation, brightness: brightness, opacity: opacity)
        }
    }