1// Copyright 2020 the Resvg Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use super::{f32_bound, ImageRef, ImageRefMut};
5use rgb::RGBA8;
6use usvg::ApproxZeroUlps;
7
8/// Performs an arithmetic composition.
9///
10/// - `src1` and `src2` image pixels should have a **premultiplied alpha**.
11/// - `dest` image pixels will have a **premultiplied alpha**.
12///
13/// # Panics
14///
15/// When `src1`, `src2` and `dest` have different sizes.
16pub fn arithmetic(
17 k1: f32,
18 k2: f32,
19 k3: f32,
20 k4: f32,
21 src1: ImageRef,
22 src2: ImageRef,
23 dest: ImageRefMut,
24) {
25 assert!(src1.width == src2.width && src1.width == dest.width);
26 assert!(src1.height == src2.height && src1.height == dest.height);
27
28 let calc = |i1, i2, max| {
29 let i1 = i1 as f32 / 255.0;
30 let i2 = i2 as f32 / 255.0;
31 let result = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
32 f32_bound(0.0, result, max)
33 };
34
35 let mut i = 0;
36 for (c1, c2) in src1.data.iter().zip(src2.data.iter()) {
37 let a = calc(c1.a, c2.a, 1.0);
38 if a.approx_zero_ulps(4) {
39 i += 1;
40 continue;
41 }
42
43 let r = (calc(c1.r, c2.r, a) * 255.0) as u8;
44 let g = (calc(c1.g, c2.g, a) * 255.0) as u8;
45 let b = (calc(c1.b, c2.b, a) * 255.0) as u8;
46 let a = (a * 255.0) as u8;
47
48 dest.data[i] = RGBA8 { r, g, b, a };
49
50 i += 1;
51 }
52}
53