resvg/filter/
color_matrix.rs1use super::{ImageRefMut, f32_bound};
5use rgb::RGBA8;
6use usvg::filter::ColorMatrixKind as ColorMatrix;
7
8pub fn apply(matrix: &ColorMatrix, src: ImageRefMut) {
12 match matrix {
13 ColorMatrix::Matrix(m) => {
14 for pixel in src.data {
15 let (r, g, b, a) = to_normalized_components(*pixel);
16
17 let new_r = r * m[0] + g * m[1] + b * m[2] + a * m[3] + m[4];
18 let new_g = r * m[5] + g * m[6] + b * m[7] + a * m[8] + m[9];
19 let new_b = r * m[10] + g * m[11] + b * m[12] + a * m[13] + m[14];
20 let new_a = r * m[15] + g * m[16] + b * m[17] + a * m[18] + m[19];
21
22 pixel.r = from_normalized(new_r);
23 pixel.g = from_normalized(new_g);
24 pixel.b = from_normalized(new_b);
25 pixel.a = from_normalized(new_a);
26 }
27 }
28 ColorMatrix::Saturate(v) => {
29 let v = v.get().max(0.0);
30 let m = [
31 0.213 + 0.787 * v,
32 0.715 - 0.715 * v,
33 0.072 - 0.072 * v,
34 0.213 - 0.213 * v,
35 0.715 + 0.285 * v,
36 0.072 - 0.072 * v,
37 0.213 - 0.213 * v,
38 0.715 - 0.715 * v,
39 0.072 + 0.928 * v,
40 ];
41
42 for pixel in src.data {
43 let (r, g, b, _) = to_normalized_components(*pixel);
44
45 let new_r = r * m[0] + g * m[1] + b * m[2];
46 let new_g = r * m[3] + g * m[4] + b * m[5];
47 let new_b = r * m[6] + g * m[7] + b * m[8];
48
49 pixel.r = from_normalized(new_r);
50 pixel.g = from_normalized(new_g);
51 pixel.b = from_normalized(new_b);
52 }
53 }
54 ColorMatrix::HueRotate(angle) => {
55 let angle = angle.to_radians();
56 let a1 = angle.cos();
57 let a2 = angle.sin();
58 let m = [
59 0.213 + 0.787 * a1 - 0.213 * a2,
60 0.715 - 0.715 * a1 - 0.715 * a2,
61 0.072 - 0.072 * a1 + 0.928 * a2,
62 0.213 - 0.213 * a1 + 0.143 * a2,
63 0.715 + 0.285 * a1 + 0.140 * a2,
64 0.072 - 0.072 * a1 - 0.283 * a2,
65 0.213 - 0.213 * a1 - 0.787 * a2,
66 0.715 - 0.715 * a1 + 0.715 * a2,
67 0.072 + 0.928 * a1 + 0.072 * a2,
68 ];
69
70 for pixel in src.data {
71 let (r, g, b, _) = to_normalized_components(*pixel);
72
73 let new_r = r * m[0] + g * m[1] + b * m[2];
74 let new_g = r * m[3] + g * m[4] + b * m[5];
75 let new_b = r * m[6] + g * m[7] + b * m[8];
76
77 pixel.r = from_normalized(new_r);
78 pixel.g = from_normalized(new_g);
79 pixel.b = from_normalized(new_b);
80 }
81 }
82 ColorMatrix::LuminanceToAlpha => {
83 for pixel in src.data {
84 let (r, g, b, _) = to_normalized_components(*pixel);
85
86 let new_a = r * 0.2125 + g * 0.7154 + b * 0.0721;
87
88 pixel.r = 0;
89 pixel.g = 0;
90 pixel.b = 0;
91 pixel.a = from_normalized(new_a);
92 }
93 }
94 }
95}
96
97#[inline]
98fn to_normalized_components(pixel: RGBA8) -> (f32, f32, f32, f32) {
99 (
100 pixel.r as f32 / 255.0,
101 pixel.g as f32 / 255.0,
102 pixel.b as f32 / 255.0,
103 pixel.a as f32 / 255.0,
104 )
105}
106
107#[inline]
108fn from_normalized(c: f32) -> u8 {
109 (f32_bound(0.0, c, 1.0) * 255.0) as u8
110}