| 1 | // Copyright 2020 the Resvg Authors |
| 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
| 3 | |
| 4 | use super::{f32_bound, ImageRef, ImageRefMut}; |
| 5 | use rgb::RGBA8; |
| 6 | use 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. |
| 16 | pub 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 | |