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 | |
5 | use super::{f32_bound, ImageRef, ImageRefMut}; |
6 | use rgb::RGBA8; |
7 | use 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. |
17 | pub 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 | |