1#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
9#![allow(clippy::wrong_self_convention)]
12
13#[cfg(feature = "cint")]
14mod cint_impl;
15
16mod color32;
17pub use color32::*;
18
19mod hsva_gamma;
20pub use hsva_gamma::*;
21
22mod hsva;
23pub use hsva::*;
24
25#[cfg(feature = "color-hex")]
26mod hex_color_macro;
27#[cfg(feature = "color-hex")]
28#[doc(hidden)]
29pub use color_hex;
30
31mod rgba;
32pub use rgba::*;
33
34mod hex_color_runtime;
35pub use hex_color_runtime::*;
36
37impl From<Color32> for Rgba {
41 fn from(srgba: Color32) -> Self {
42 Self([
43 linear_f32_from_gamma_u8(srgba.0[0]),
44 linear_f32_from_gamma_u8(srgba.0[1]),
45 linear_f32_from_gamma_u8(srgba.0[2]),
46 linear_f32_from_linear_u8(srgba.0[3]),
47 ])
48 }
49}
50
51impl From<Rgba> for Color32 {
52 fn from(rgba: Rgba) -> Self {
53 Self([
54 gamma_u8_from_linear_f32(rgba.0[0]),
55 gamma_u8_from_linear_f32(rgba.0[1]),
56 gamma_u8_from_linear_f32(rgba.0[2]),
57 linear_u8_from_linear_f32(rgba.0[3]),
58 ])
59 }
60}
61
62pub fn linear_f32_from_gamma_u8(s: u8) -> f32 {
64 if s <= 10 {
65 s as f32 / 3294.6
66 } else {
67 ((s as f32 + 14.025) / 269.025).powf(2.4)
68 }
69}
70
71#[inline(always)]
74pub fn linear_f32_from_linear_u8(a: u8) -> f32 {
75 a as f32 / 255.0
76}
77
78pub fn gamma_u8_from_linear_f32(l: f32) -> u8 {
81 if l <= 0.0 {
82 0
83 } else if l <= 0.0031308 {
84 fast_round(3294.6 * l)
85 } else if l <= 1.0 {
86 fast_round(269.025 * l.powf(1.0 / 2.4) - 14.025)
87 } else {
88 255
89 }
90}
91
92#[inline(always)]
95pub fn linear_u8_from_linear_f32(a: f32) -> u8 {
96 fast_round(a * 255.0)
97}
98
99fn fast_round(r: f32) -> u8 {
100 (r + 0.5) as _ }
102
103#[test]
104pub fn test_srgba_conversion() {
105 for b in 0..=255 {
106 let l = linear_f32_from_gamma_u8(b);
107 assert!(0.0 <= l && l <= 1.0);
108 assert_eq!(gamma_u8_from_linear_f32(l), b);
109 }
110}
111
112pub fn linear_from_gamma(gamma: f32) -> f32 {
115 if gamma < 0.0 {
116 -linear_from_gamma(-gamma)
117 } else if gamma <= 0.04045 {
118 gamma / 12.92
119 } else {
120 ((gamma + 0.055) / 1.055).powf(2.4)
121 }
122}
123
124pub fn gamma_from_linear(linear: f32) -> f32 {
127 if linear < 0.0 {
128 -gamma_from_linear(-linear)
129 } else if linear <= 0.0031308 {
130 12.92 * linear
131 } else {
132 1.055 * linear.powf(1.0 / 2.4) - 0.055
133 }
134}
135
136pub fn tint_color_towards(color: Color32, target: Color32) -> Color32 {
141 let [mut r, mut g, mut b, mut a] = color.to_array();
142
143 if a == 0 {
144 r /= 2;
145 g /= 2;
146 b /= 2;
147 } else if a < 170 {
148 let div = (2 * 255 / a as i32) as u8;
151 r = r / 2 + target.r() / div;
152 g = g / 2 + target.g() / div;
153 b = b / 2 + target.b() / div;
154 a /= 2;
155 } else {
156 r = r / 2 + target.r() / 2;
157 g = g / 2 + target.g() / 2;
158 b = b / 2 + target.b() / 2;
159 }
160 Color32::from_rgba_premultiplied(r, g, b, a)
161}