1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
 * // Copyright 2024 (c) the Radzivon Bartoshyk. All rights reserved.
 * //
 * // Use of this source code is governed by a BSD-style
 * // license that can be found in the LICENSE file.
 */
use crate::{Oklab, Rgb, TransferFunction};
use erydanos::{eatan2f, ehypotf, Cosine, Sine};

/// Represents *Oklch* colorspace
#[derive(Copy, Clone, PartialOrd, PartialEq)]
pub struct Oklch {
    /// Lightness
    pub l: f32,
    /// Chroma
    pub c: f32,
    /// Hue
    pub h: f32,
}

impl Oklch {
    /// Creates new instance
    #[inline]
    pub fn new(l: f32, c: f32, h: f32) -> Oklch {
        Oklch { l, c, h }
    }

    /// Converts *Rgb* into *Oklch*
    ///
    /// # Arguments
    /// `transfer_function` - Transfer function into linear colorspace and its inverse
    #[inline]
    pub fn from_rgb(rgb: Rgb<u8>, transfer_function: TransferFunction) -> Oklch {
        let oklab = rgb.to_oklab(transfer_function);
        Oklch::from_oklab(oklab)
    }

    /// Converts *Oklch* into *Rgb*
    ///
    /// # Arguments
    /// `transfer_function` - Transfer function into linear colorspace and its inverse
    #[inline]
    pub fn to_rgb(&self, transfer_function: TransferFunction) -> Rgb<u8> {
        let oklab = self.to_oklab();
        oklab.to_rgb(transfer_function)
    }

    /// Converts *Oklab* to *Oklch*
    #[inline]
    pub fn from_oklab(oklab: Oklab) -> Oklch {
        let chroma = ehypotf(oklab.b, oklab.a);
        let hue = eatan2f(oklab.b, oklab.a);
        Oklch::new(oklab.l, chroma, hue)
    }

    /// Converts *Oklch* to *Oklab*
    #[inline]
    pub fn to_oklab(&self) -> Oklab {
        let l = self.l;
        let a = self.c * self.h.ecos();
        let b = self.c * self.h.esin();
        Oklab::new(l, a, b)
    }
}