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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! kolor implements conversions between color spaces which use 3-component vectors.
//!
//! kolor is intended for use in games or other interactive visual applications,
//! where it can help implement correct color management and wide color gamut rendering.
//!
//! # Named color spaces
//! Named color space definitions can be found in [spaces]. Some notable color spaces and models:
//!
//! - sRGB / linear sRGB / BT.709
//! - BT.2020
//! - ACEScg
//! - ACES2065-1
//! - Oklab
//! - CIE LAB / Lch / Luv / xyY / uvV
//! - HSL / HSV / HSI
//! - ICtCp
//!
//! You can also construct custom [ColorSpace]s
//! from a combination of primaries, whitepoint and transform function.
//!
//! # Design
//! kolor aims to supports all color spaces and color models which use 3-component vectors,
//! such as RGB, LAB, XYZ, HSL and more.
//!
//! In the spirit of keeping things simple, kolor uses a single type, [Color], to represent
//! a color in any supported color space.
//!
//! kolor can programmatically generate an efficient conversion between any two color spaces
//! by using the CIE XYZ color space as a "connecting space", meaning all supported color spaces
//! only need to support a conversion to a reference color space that is a linear
//! transform of the CIE XYZ color space.
//!
//! Transformations between linear color spaces can be implemented with a 3x3 matrix, and
//! since 3x3 matrices are composable, these matrices can be pre-composed and applied to a color
//! with a single multiply.
//!
//! kolor recognizes that users may want to perform conversions on colors stored in types defined
//! by the user. [ColorConversion] represents a conversion between two color spaces
//! and is intended to be compatible with 3-component vectors in many math libraries.
//!
//! kolor defines conversions from a source [ColorSpace] to a destination [ColorSpace] as three parts:
//! - if the source color space is non-linear,
//!     apply the inverse of its transform function to convert to the non-linear color space's reference
//!     color space (which is always linear)
//! - a linear 3x3 transformation matrix from the source to the destination linear color space
//! - if the destination color space is a non-linear color space,
//!     apply its transform function
//!
//! A "non-linear transform function" means any function that cannot be expressed as a linear transformation
//! of the CIE XYZ color space. Examples include the sRGB logarithmic gamma compensation function,
//! the Oklab transform function, and the HSL/HSV hexagonal/circular transform.
//!
//! For non-linear color spaces, many transform functions are supported
//! to convert between popular spaces, but for GPU contexts, these implementations clearly can't be used directly.
//! To implement data-driven conversions, you can read the required operations for transforming between spaces
//! from a [ColorConversion] value and run these as appropriate.
//! Feel free to port the implementations in [details::transform] to your shaders or other code.
//!
//!
//! ### Gamut-agnostic transforms
//! Some color models like CIELAB or HSL are intended to provide an alternate view of
//! some linear color spaces, and need a reference color space to provide information like
//! which white point or RGB primaries to use.
//! To construct these color spaces, refer to associated methods on [ColorSpace] and use an appropriate
//! reference color space.
//!
//!
//! # Details
//! kolor can calculate 3x3 conversion matrices between any linear color space
//! defined by RGB primaries and a white point. kolor offers APIs for performing
//! conversions directly, and for extracting the 3x3 matrix to use in a different context,
//! for example on a GPU.
//!
//! ### Generating conversion matrices between RGB color spaces
//! [LinearColorConversion][details::conversion::LinearColorConversion] can be used
//! to generate conversion matrices "offline",
//! in which case you probably want to use the `f64` feature for better precision.
//! The precision of the derived matrices won't be perfect, but probably good enough for games.
//!
//! Conversions between all combinations of built-in primaries and whitepoints color spaces
//! are bundled with kolor as constants with the `color-matrices` feature, which is enabled by default.
//! When a [ColorConversion] without a bundled pre-calculated conversion matrix is created,
//! it is calculated on-demand, meaning the creation will be a bit slower to create than
//! if there is a constant matrix available.
//!
//! ### Chromatic Adaptation Transformation (CAT)
//! kolor implements CAT in [details::cat] and supports the LMS cone spaces defined
//! in [LMSConeSpace][details::cat::LMSConeSpace]. Chromatic Adaptation Transformation means converting
//! a linear RGB color space from one reference [WhitePoint][details::color::WhitePoint] to another.
//!
//! Use [ColorSpace::with_whitepoint] to change [WhitePoint][details::color::WhitePoint] for a color space.
//!
//! ### XYZ-RGB conversions
//! All supported RGB color spaces use the CIE XYZ color space as its reference color space.
//! Functions in [details::xyz] can be used to create conversion matrices to/from an RGB color space
//! given a set of primaries and a white point.
//!
//! # no_std and glam support
//! kolor is using by default `std` and `glam`, but both can be disabled separately or together with the
//! folowing features:
//!
//! | |`std`|`no_std`|
//! |-|-|-|
//! |`glam`|`std-glam`|`libm-glam`|
//! |no `glam`|`std`|`libm`|
//!

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "f64")]
pub type FType = f64;

#[cfg(not(feature = "f64"))]
pub type FType = f32;

pub use details::math::{Mat3, Vec3};

/// Create a `Mat3` from a `[FType; 9]`. The order of components is column-major.
#[cfg(not(feature = "glam"))]
#[macro_export]
macro_rules! const_mat3 {
    ($ftypex9:expr) => {
        Mat3::from_cols_array_const($ftypex9)
    };
}

#[cfg(not(feature = "f64"))]
pub(crate) use core::f32::consts::PI;
#[cfg(not(feature = "f64"))]
pub(crate) use core::f32::consts::TAU;
#[cfg(feature = "f64")]
pub(crate) use core::f64::consts::PI;
#[cfg(feature = "f64")]
pub(crate) use core::f64::consts::TAU;

pub mod details {
    pub mod cat;
    pub mod color;
    pub mod conversion;
    #[allow(clippy::excessive_precision)]
    #[cfg(feature = "color-matrices")]
    pub mod generated_matrices;
    pub mod math;
    #[allow(clippy::excessive_precision)]
    #[allow(non_snake_case)]
    #[allow(clippy::many_single_char_names)]
    pub mod transform;
    pub mod xyz;
}
#[doc(inline)]
pub use details::color::color_spaces as spaces;
#[doc(inline)]
pub use details::color::{Color, ColorSpace};
#[doc(inline)]
pub use details::conversion::ColorConversion;