colorutils_rs/
routines.rs

1/*
2 * // Copyright 2024 (c) the Radzivon Bartoshyk. All rights reserved.
3 * //
4 * // Use of this source code is governed by a BSD-style
5 * // license that can be found in the LICENSE file.
6 */
7
8#[macro_export]
9macro_rules! color_dodge {
10    ($base: expr, $other: expr) => {{
11        if $other == 1.0 {
12            $other
13        } else {
14            ($base / (1.0 - $other)).min(1.)
15        }
16    }};
17}
18
19#[macro_export]
20macro_rules! color_linear_burn {
21    ($base: expr, $other: expr) => {{
22        ($base + $other - 1.).max(0.)
23    }};
24}
25
26#[macro_export]
27macro_rules! color_burn {
28    ($base: expr, $other: expr) => {{
29        if $other == 0.0 {
30            $other
31        } else {
32            (1.0 - ((1.0 - $base) / $other)).max(0.)
33        }
34    }};
35}
36
37#[macro_export]
38macro_rules! color_darken {
39    ($base: expr, $other: expr) => {{
40        $base.min($other)
41    }};
42}
43
44#[macro_export]
45macro_rules! color_lighten {
46    ($base: expr, $other: expr) => {{
47        $base.max($other)
48    }};
49}
50
51#[macro_export]
52macro_rules! color_screen {
53    ($base: expr, $other: expr) => {{
54        $base + $other - $base * $other
55    }};
56}
57
58#[macro_export]
59macro_rules! color_add {
60    ($base: expr, $other: expr) => {{
61        ($base + $other).min(1.)
62    }};
63}
64
65#[macro_export]
66macro_rules! color_linear_light {
67    ($base: expr, $other: expr) => {{
68        if $other < 0.5 {
69            color_linear_burn!($base, (2.0 * $other))
70        } else {
71            color_add!($base, (2.0 * ($other - 0.5)))
72        }
73    }};
74}
75
76#[macro_export]
77macro_rules! color_vivid_light {
78    ($base: expr, $other: expr) => {{
79        if $other < 0.5 {
80            color_burn!($base, (2.0 * $other))
81        } else {
82            color_dodge!($base, (2.0 * ($other - 0.5)))
83        }
84    }};
85}
86
87#[macro_export]
88macro_rules! color_pin_light {
89    ($base: expr, $other: expr) => {{
90        if $other < 0.5 {
91            color_darken!($base, (2.0 * $other))
92        } else {
93            color_lighten!($base, (2.0 * ($other - 0.5)))
94        }
95    }};
96}
97
98#[macro_export]
99macro_rules! color_hard_mix {
100    ($base: expr, $other: expr) => {{
101        if color_vivid_light!($base, $other) < 0.5 {
102            0.
103        } else {
104            1.
105        }
106    }};
107}
108
109#[macro_export]
110macro_rules! color_reflect {
111    ($base: expr, $other: expr) => {{
112        if $other == 1.0 {
113            $other
114        } else {
115            ($base * $base / (1.0 - $other)).min(1.)
116        }
117    }};
118}
119
120#[macro_export]
121macro_rules! color_difference {
122    ($base: expr, $other: expr) => {{
123        ($base - $other).abs()
124    }};
125}
126
127#[macro_export]
128macro_rules! pdf_lum {
129    ($base: expr) => {{
130        0.3 * $base.r + 0.59 * $base.g + 0.11 * $base.g
131    }};
132}
133
134#[macro_export]
135macro_rules! clip_color {
136    ($base: expr) => {{
137        let l = pdf_lum!($base);
138        let n = $base.r.min($base.g).min($base.b);
139        let x = $base.r.max($base.g).max($base.b);
140        let (mut r, mut g, mut b) = ($base.r, $base.g, $base.b);
141        if n < 0.0 {
142            let recip = 1. / (l - n);
143            r = l + (((r - l) * l) * recip);
144            g = l + (((g - l) * l) * recip);
145            b = l + (((b - l) * l) * recip);
146        }
147        if x > 1.0 {
148            let recip = 1. / (x - l);
149            r = l + (((r - l) * (1. - l)) * recip);
150            g = l + (((g - l) * (1. - l)) * recip);
151            b = l + (((b - l) * (1. - l)) * recip);
152        }
153        (r, g, b)
154    }};
155}
156
157#[macro_export]
158macro_rules! color_hard_light {
159    ($base: expr, $other: expr) => {{
160        if $base <= 0.5 {
161            2. * $base * $other
162        } else {
163            1. - 2. * (1. - $base) * (1. - $other)
164        }
165    }};
166}
167
168#[macro_export]
169macro_rules! color_soft_light_weight {
170    ($x: expr) => {{
171        if ($x <= 0.25) {
172            ((16. * $x - 12.) * $x + 4.) * $x
173        } else {
174            $x.sqrt()
175        }
176    }};
177}
178
179#[macro_export]
180macro_rules! color_soft_light {
181    ($base: expr, $other: expr) => {{
182        if ($base <= 0.5) {
183            $other - (1. - 2. * $base) * $other * (1. - $other)
184        } else {
185            $other + (2.0 * $base - 1.) * (color_soft_light_weight!($other) - $other)
186        }
187    }};
188}
189
190#[macro_export]
191macro_rules! color_exclusion {
192    ($base: expr, $other: expr) => {{
193        $base + $other - 2. * $base * $other
194    }};
195}
196
197#[macro_export]
198macro_rules! adjust_saturation {
199    ($store: expr, $saturation: expr) => {{
200        let c1 = 0.213 + 0.787 * $saturation;
201        let c2 = 0.715 - 0.715 * $saturation;
202        let c3 = 0.072 - 0.072 * $saturation;
203
204        let c4 = 0.213 - 0.213 * $saturation;
205        let c5 = 0.715 + 0.285 * $saturation;
206        let c6 = 0.072 - 0.072 * $saturation;
207
208        let c7 = 0.213 - 0.213 * $saturation;
209        let c8 = 0.715 - 0.715 * $saturation;
210        let c9 = 0.072 + 0.928 * $saturation;
211        let r1 = $store.r * c1 + $store.g * c2 + $store.b * c3;
212        let g1 = $store.r * c4 + $store.g * c5 + $store.b * c6;
213        let b1 = $store.r * c7 + $store.g * c8 + $store.b * c9;
214        (r1, g1, b1)
215    }};
216}
217
218#[inline]
219pub(crate) fn op_color_dodge(a: f32, b: f32) -> f32 {
220    if b == 1.0 {
221        b
222    } else {
223        (a / (1.0 - b)).min(1.)
224    }
225}
226
227#[inline]
228pub(crate) fn op_screen(a: f32, b: f32) -> f32 {
229    color_screen!(a, b)
230}
231
232#[inline]
233pub(crate) fn op_color_burn(a: f32, b: f32) -> f32 {
234    color_burn!(a, b)
235}
236
237#[inline]
238pub(crate) fn op_darken(a: f32, b: f32) -> f32 {
239    a.min(b)
240}
241
242#[inline]
243pub(crate) fn op_lighten(a: f32, b: f32) -> f32 {
244    a.max(b)
245}
246
247#[inline]
248pub(crate) fn op_linear_burn(a: f32, b: f32) -> f32 {
249    color_linear_burn!(a, b)
250}
251
252#[inline]
253pub(crate) fn op_reflect(a: f32, b: f32) -> f32 {
254    color_reflect!(a, b)
255}
256
257#[inline]
258pub(crate) fn op_overlay(a: f32, b: f32) -> f32 {
259    if b < 0.5 {
260        2.0 * a * b
261    } else {
262        1.0 - 2.0 * (1.0 - a) * (1.0 - b)
263    }
264}
265
266#[inline]
267pub(crate) fn op_difference(a: f32, b: f32) -> f32 {
268    color_difference!(a, b)
269}
270
271#[inline]
272pub(crate) fn op_exclusion(a: f32, b: f32) -> f32 {
273    color_exclusion!(a, b)
274}
275
276#[inline]
277pub(crate) fn op_linear_light(a: f32, b: f32) -> f32 {
278    color_linear_light!(a, b)
279}
280
281#[inline]
282pub(crate) fn op_vivid_light(a: f32, b: f32) -> f32 {
283    color_vivid_light!(a, b)
284}
285
286#[inline]
287pub(crate) fn op_pin_light(a: f32, b: f32) -> f32 {
288    color_pin_light!(a, b)
289}
290
291#[inline]
292pub(crate) fn op_hard_mix(a: f32, b: f32) -> f32 {
293    color_hard_mix!(a, b)
294}
295
296#[inline]
297pub(crate) fn op_hard_light(a: f32, b: f32) -> f32 {
298    color_hard_light!(a, b)
299}
300
301#[inline]
302pub(crate) fn op_soft_light(a: f32, b: f32) -> f32 {
303    color_soft_light!(a, b)
304}