resvg/filter/
displacement_map.rs

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::{ImageRef, ImageRefMut};
6use usvg::filter::{ColorChannel, DisplacementMap};
7
8/// Applies a displacement map.
9///
10/// - `map` pixels should have a **unpremultiplied alpha**.
11/// - `src` pixels can have any alpha method.
12///
13/// `sx` and `sy` indicate canvas scale.
14///
15/// # Panics
16///
17/// When `src`, `map` and `dest` have different sizes.
18pub fn apply(
19    fe: &DisplacementMap,
20    sx: f32,
21    sy: f32,
22    src: ImageRef,
23    map: ImageRef,
24    dest: ImageRefMut,
25) {
26    assert!(src.width == map.width && src.width == dest.width);
27    assert!(src.height == map.height && src.height == dest.height);
28
29    let w = src.width as i32;
30    let h = src.height as i32;
31
32    let mut x: u32 = 0;
33    let mut y: u32 = 0;
34    for pixel in map.data.iter() {
35        let calc_offset = |channel| {
36            let c = match channel {
37                ColorChannel::B => pixel.b,
38                ColorChannel::G => pixel.g,
39                ColorChannel::R => pixel.r,
40                ColorChannel::A => pixel.a,
41            };
42
43            c as f32 / 255.0 - 0.5
44        };
45
46        let dx = calc_offset(fe.x_channel_selector());
47        let dy = calc_offset(fe.y_channel_selector());
48        let ox = (x as f32 + dx * sx * fe.scale()).round() as i32;
49        let oy = (y as f32 + dy * sy * fe.scale()).round() as i32;
50
51        // TODO: we should use some kind of anti-aliasing when offset is on a pixel border
52
53        if x < w as u32 && y < h as u32 && ox >= 0 && ox < w && oy >= 0 && oy < h {
54            let idx = (oy * w + ox) as usize;
55            let idx1 = (y * w as u32 + x) as usize;
56            dest.data[idx1] = src.data[idx];
57        }
58
59        x += 1;
60        if x == src.width {
61            x = 0;
62            y += 1;
63        }
64    }
65}