yagii 0.1.3

Yet Another Github style Identicon Implementation
// Copyright (c) 2018 Sadaie Matsudaira (sadaie)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! HSL color space support.

use image::Rgb;

const ONE_HALF: f32 = 1.0 / 2.0;
const ONE_THIRD: f32 = 1.0 / 3.0;
const TWO_THIRD: f32 = 2.0 / 3.0;
const ONE_SIXTH: f32 = 1.0 / 6.0;

const fn convert_color_component(value: f32) -> u8 {
    (value * 255.0 + 0.5) as u8
}

const fn convert_color_components(red: f32, green: f32, blue: f32) -> [u8; 3] {
    [
        convert_color_component(red),
        convert_color_component(green),
        convert_color_component(blue),
    ]
}

fn hue_to_rgb(a: f32, b: f32, hue: f32) -> f32 {
    let hue = if hue < 0.0 {
        hue + 1.0
    } else if hue > 1.0 {
        hue - 1.0
    } else {
        hue
    };

    if hue < ONE_SIXTH {
        a + (b - a) * 6.0 * hue
    } else if hue < ONE_HALF {
        b
    } else if hue < TWO_THIRD {
        a + (b - a) * (TWO_THIRD - hue) * 6.0
    } else {
        a
    }
}

pub(crate) fn convert_hsl_to_rgb(hue: f32, saturation: f32, lightness: f32) -> Rgb<u8> {
    let hue = hue / 360.0;
    let saturation = saturation / 100.0;
    let lightness = lightness / 100.0;

    let b = if lightness <= 0.5 {
        lightness * (saturation + 1.0)
    } else {
        lightness + saturation - lightness * saturation
    };
    let a = lightness * 2.0 - b;

    let red = hue_to_rgb(a, b, hue + ONE_THIRD);
    let green = hue_to_rgb(a, b, hue);
    let blue = hue_to_rgb(a, b, hue - ONE_THIRD);

    Rgb {
        data: convert_color_components(red, green, blue),
    }
}

#[test]
fn test_convert_hsl_to_rgb_black() {
    let rgb = convert_hsl_to_rgb(0.0, 0.0, 0.0);
    assert_eq!(rgb.data, [0, 0, 0]);
}

#[test]
fn test_convert_hsl_to_rgb_white() {
    let rgb = convert_hsl_to_rgb(0.0, 0.0, 100.0);
    assert_eq!(rgb.data, [255, 255, 255]);
}

#[test]
fn test_convert_hsl_to_rgb_red() {
    let rgb = convert_hsl_to_rgb(0.0, 100.0, 50.0);
    assert_eq!(rgb.data, [255, 0, 0]);
}

#[test]
fn test_convert_hsl_to_rgb_green() {
    let rgb = convert_hsl_to_rgb(120.0, 100.0, 50.0);
    assert_eq!(rgb.data, [0, 255, 0]);
}

#[test]
fn test_convert_hsl_to_rgb_blue() {
    let rgb = convert_hsl_to_rgb(240.0, 100.0, 50.0);
    assert_eq!(rgb.data, [0, 0, 255]);
}