1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use super::{f32_bound, ImageRef, ImageRefMut};
6use rgb::RGBA8;
7use usvg::ApproxZeroUlps;
8
9/// Performs an arithmetic composition.
10///
11/// - `src1` and `src2` image pixels should have a **premultiplied alpha**.
12/// - `dest` image pixels will have a **premultiplied alpha**.
13///
14/// # Panics
15///
16/// When `src1`, `src2` and `dest` have different sizes.
17pub fn arithmetic(
18 k1: f32,
19 k2: f32,
20 k3: f32,
21 k4: f32,
22 src1: ImageRef,
23 src2: ImageRef,
24 dest: ImageRefMut,
25) {
26 assert!(src1.width == src2.width && src1.width == dest.width);
27 assert!(src1.height == src2.height && src1.height == dest.height);
28
29 let calc = |i1, i2, max| {
30 let i1 = i1 as f32 / 255.0;
31 let i2 = i2 as f32 / 255.0;
32 let result = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
33 f32_bound(0.0, result, max)
34 };
35
36 let mut i = 0;
37 for (c1, c2) in src1.data.iter().zip(src2.data.iter()) {
38 let a = calc(c1.a, c2.a, 1.0);
39 if a.approx_zero_ulps(4) {
40 i += 1;
41 continue;
42 }
43
44 let r = (calc(c1.r, c2.r, a) * 255.0) as u8;
45 let g = (calc(c1.g, c2.g, a) * 255.0) as u8;
46 let b = (calc(c1.b, c2.b, a) * 255.0) as u8;
47 let a = (a * 255.0) as u8;
48
49 dest.data[i] = RGBA8 { r, g, b, a };
50
51 i += 1;
52 }
53}
54