material_color_utilities/
blend.rs1use crate::{
2 hct::{Cam16, Hct},
3 utils,
4};
5
6pub fn harmonize(design_color: u32, source_color: u32) -> u32 {
10 let from_hct = Hct::from_int(design_color);
11 let to_hct = Hct::from_int(source_color);
12 let difference_degrees = utils::math::difference_degrees(from_hct.hue(), to_hct.hue());
13 let rotation_degrees = f64::min(difference_degrees * 0.5, 15.0);
14 let output_hue = utils::math::sanitize_degrees(
15 from_hct.hue()
16 + rotation_degrees * utils::math::rotation_direction(from_hct.hue(), to_hct.hue()),
17 );
18 Hct::from(output_hue, from_hct.chroma(), from_hct.tone()).to_int()
19}
20
21pub fn hct_hue(from: u32, to: u32, amount: f64) -> u32 {
24 let ucs = cam16_ucs(from, to, amount);
25 let ucs_cam = Cam16::from_int(ucs);
26 let from_cam = Cam16::from_int(from);
27 let blended = Hct::from(
28 ucs_cam.hue(),
29 from_cam.chroma(),
30 utils::color::lstar_from_argb(from),
31 );
32 blended.to_int()
33}
34
35pub fn cam16_ucs(from: u32, to: u32, amount: f64) -> u32 {
37 let from_cam = Cam16::from_int(from);
38 let to_cam = Cam16::from_int(to);
39 let from_j = from_cam.jstar();
40 let from_a = from_cam.astar();
41 let from_b = from_cam.bstar();
42 let to_j = to_cam.j();
43 let to_a = to_cam.astar();
44 let to_b = to_cam.bstar();
45 let jstar = from_j + (to_j - from_j) * amount;
46 let astar = from_a + (to_a - from_a) * amount;
47 let bstar = from_b + (to_b - from_b) * amount;
48 Cam16::from_ucs(jstar, astar, bstar).to_int()
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 const RED: u32 = 0xffff0000;
56 const BLUE: u32 = 0xff0000ff;
57 const GREEN: u32 = 0xff00ff00;
58 const YELLOW: u32 = 0xffffff00;
59
60 #[test]
61 fn harmonize_red_to_blue() {
62 let answer = harmonize(RED, BLUE);
63 assert_eq!(answer, 0xfffb0057);
64 }
65
66 #[test]
67 fn harmonize_red_to_green() {
68 let answer = harmonize(RED, GREEN);
69 assert_eq!(answer, 0xffd85600);
70 }
71
72 #[test]
73 fn harmonize_red_to_yellow() {
74 let answer = harmonize(RED, YELLOW);
75 assert_eq!(answer, 0xffd85600);
76 }
77
78 #[test]
79 fn harmonize_blue_to_green() {
80 let answer = harmonize(BLUE, GREEN);
81 assert_eq!(answer, 0xff0047a3);
82 }
83
84 #[test]
85 fn harmonize_blue_to_red() {
86 let answer = harmonize(BLUE, RED);
87 assert_eq!(answer, 0xff5700dc);
88 }
89
90 #[test]
91 fn harmonize_blue_to_yellow() {
92 let answer = harmonize(BLUE, YELLOW);
93 assert_eq!(answer, 0xff0047a3);
94 }
95
96 #[test]
97 fn harmonize_green_to_blue() {
98 let answer = harmonize(GREEN, BLUE);
99 assert_eq!(answer, 0xff00fc94);
100 }
101
102 #[test]
103 fn harmonize_green_to_red() {
104 let answer = harmonize(GREEN, RED);
105 assert_eq!(answer, 0xffb1f000);
106 }
107
108 #[test]
109 fn harmonize_green_to_yellow() {
110 let answer = harmonize(GREEN, YELLOW);
111 assert_eq!(answer, 0xffb1f000);
112 }
113
114 #[test]
115 fn harmonize_yellow_to_blue() {
116 let answer = harmonize(YELLOW, BLUE);
117 assert_eq!(answer, 0xffebffba);
118 }
119
120 #[test]
121 fn harmonize_yellow_to_green() {
122 let answer = harmonize(YELLOW, GREEN);
123 assert_eq!(answer, 0xffebffba);
124 }
125
126 #[test]
127 fn harmonize_yellow_to_red() {
128 let answer = harmonize(YELLOW, RED);
129 assert_eq!(answer, 0xfffff6e3);
130 }
131}