1use std::f64::consts::PI;
2
3use crate::ResizeAlgorithm;
4
5pub struct Point;
9
10impl ResizeAlgorithm for Point {
11 #[inline(always)]
12 fn support() -> u32 {
13 0
14 }
15
16 #[inline(always)]
17 fn new() -> Self {
18 Self
19 }
20
21 #[inline(always)]
22 fn process(&self, _x: f64) -> f64 {
23 1.0_f64
24 }
25}
26
27pub struct Bilinear;
30
31impl ResizeAlgorithm for Bilinear {
32 #[inline(always)]
33 fn support() -> u32 {
34 1
35 }
36
37 #[inline(always)]
38 fn new() -> Self {
39 Self
40 }
41
42 #[inline(always)]
43 fn process(&self, x: f64) -> f64 {
44 (1.0 - x.abs()).max(0.0)
45 }
46}
47
48pub struct BicubicBSpline {
51 polys: BicubicPolys,
52}
53
54impl ResizeAlgorithm for BicubicBSpline {
55 #[inline(always)]
56 fn support() -> u32 {
57 2
58 }
59
60 #[inline(always)]
61 fn new() -> Self {
62 Self {
63 polys: BicubicPolys::new(1.0, 0.0),
64 }
65 }
66
67 #[inline(always)]
68 fn process(&self, x: f64) -> f64 {
69 self.polys.process(x)
70 }
71}
72
73pub struct BicubicHermite {
76 polys: BicubicPolys,
77}
78
79impl ResizeAlgorithm for BicubicHermite {
80 #[inline(always)]
81 fn support() -> u32 {
82 2
83 }
84
85 #[inline(always)]
86 fn new() -> Self {
87 Self {
88 polys: BicubicPolys::new(0.0, 0.0),
89 }
90 }
91
92 #[inline(always)]
93 fn process(&self, x: f64) -> f64 {
94 self.polys.process(x)
95 }
96}
97
98pub struct BicubicMitchell {
101 polys: BicubicPolys,
102}
103
104impl ResizeAlgorithm for BicubicMitchell {
105 #[inline(always)]
106 fn support() -> u32 {
107 2
108 }
109
110 #[inline(always)]
111 fn new() -> Self {
112 Self {
113 polys: BicubicPolys::new(1.0 / 3.0, 1.0 / 3.0),
114 }
115 }
116
117 #[inline(always)]
118 fn process(&self, x: f64) -> f64 {
119 self.polys.process(x)
120 }
121}
122
123pub struct BicubicCatmullRom {
126 polys: BicubicPolys,
127}
128
129impl ResizeAlgorithm for BicubicCatmullRom {
130 #[inline(always)]
131 fn support() -> u32 {
132 2
133 }
134
135 #[inline(always)]
136 fn new() -> Self {
137 Self {
138 polys: BicubicPolys::new(0.0, 0.5),
139 }
140 }
141
142 #[inline(always)]
143 fn process(&self, x: f64) -> f64 {
144 self.polys.process(x)
145 }
146}
147
148pub struct Lanczos3;
151
152impl ResizeAlgorithm for Lanczos3 {
153 #[inline(always)]
154 fn support() -> u32 {
155 3
156 }
157
158 #[inline(always)]
159 fn new() -> Self {
160 Self
161 }
162
163 #[inline(always)]
164 fn process(&self, x: f64) -> f64 {
165 lanczos_filter(x, 3)
166 }
167}
168
169pub struct Lanczos4;
172
173impl ResizeAlgorithm for Lanczos4 {
174 #[inline(always)]
175 fn support() -> u32 {
176 4
177 }
178
179 #[inline(always)]
180 fn new() -> Self {
181 Self
182 }
183
184 #[inline(always)]
185 fn process(&self, x: f64) -> f64 {
186 lanczos_filter(x, 4)
187 }
188}
189
190pub struct Spline16;
193
194impl ResizeAlgorithm for Spline16 {
195 #[inline(always)]
196 fn support() -> u32 {
197 2
198 }
199
200 #[inline(always)]
201 fn new() -> Self {
202 Self
203 }
204
205 #[inline(always)]
206 fn process(&self, x: f64) -> f64 {
207 let x = x.abs();
208
209 if x < 1.0_f64 {
210 return poly3(x, 1.0, -1.0 / 5.0, -9.0 / 5.0, 1.0);
211 }
212 if x < 2.0_f64 {
213 let x = x - 1.0_f64;
214 return poly3(x, 0.0, -7.0 / 15.0, 4.0 / 5.0, -1.0 / 3.0);
215 }
216 0.0_f64
217 }
218}
219
220pub struct Spline36;
223
224impl ResizeAlgorithm for Spline36 {
225 #[inline(always)]
226 fn support() -> u32 {
227 3
228 }
229
230 #[inline(always)]
231 fn new() -> Self {
232 Self
233 }
234
235 #[inline(always)]
236 fn process(&self, x: f64) -> f64 {
237 let x = x.abs();
238
239 if x < 1.0_f64 {
240 return poly3(x, 1.0, -3.0 / 209.0, -453.0 / 209.0, 13.0 / 11.0);
241 }
242 if x < 2.0_f64 {
243 let x = x - 1.0_f64;
244 return poly3(x, 0.0, -156.0 / 209.0, 270.0 / 209.0, -6.0 / 11.0);
245 }
246 if x < 3.0_f64 {
247 let x = x - 2.0_f64;
248 return poly3(x, 0.0, 26.0 / 209.0, -45.0 / 209.0, 1.0 / 11.0);
249 }
250 0.0_f64
251 }
252}
253
254pub struct Spline64;
257
258impl ResizeAlgorithm for Spline64 {
259 #[inline(always)]
260 fn support() -> u32 {
261 4
262 }
263
264 #[inline(always)]
265 fn new() -> Self {
266 Self
267 }
268
269 #[inline(always)]
270 fn process(&self, x: f64) -> f64 {
271 let x = x.abs();
272
273 if x < 1.0_f64 {
274 return poly3(x, 1.0, -3.0 / 2911.0, -6387.0 / 2911.0, 49.0 / 41.0);
275 }
276 if x < 2.0_f64 {
277 let x = x - 1.0_f64;
278 return poly3(x, 0.0, -2328.0 / 2911.0, 4032.0 / 2911.0, -24.0 / 41.0);
279 }
280 if x < 3.0_f64 {
281 let x = x - 2.0_f64;
282 return poly3(x, 0.0, 582.0 / 2911.0, -1008.0 / 2911.0, 6.0 / 41.0);
283 }
284 if x < 4.0_f64 {
285 let x = x - 3.0_f64;
286 return poly3(x, 0.0, -97.0 / 2911.0, 168.0 / 2911.0, -1.0 / 41.0);
287 }
288 0.0_f64
289 }
290}
291
292#[derive(Clone, Copy)]
293struct BicubicPolys {
294 p0: f64,
295 p2: f64,
296 p3: f64,
297 q0: f64,
298 q1: f64,
299 q2: f64,
300 q3: f64,
301}
302
303impl BicubicPolys {
304 pub fn new(b: f64, c: f64) -> Self {
305 Self {
313 p0: b.mul_add(-2.0, 6.0) / 6.0,
314 p2: c.mul_add(6.0, b.mul_add(12.0, -18.0)) / 6.0,
315 p3: c.mul_add(-6.0, b.mul_add(-9.0, 12.0)) / 6.0,
316 q0: c.mul_add(24.0, b * 8.0) / 6.0,
317 q1: c.mul_add(-48.0, b * -12.0) / 6.0,
318 q2: c.mul_add(30.0, b * 6.0) / 6.0,
319 q3: c.mul_add(-6.0, -b) / 6.0,
320 }
321 }
322
323 #[inline(always)]
324 pub fn process(&self, x: f64) -> f64 {
325 let x = x.abs();
326
327 if x < 1.0_f64 {
328 return poly3(x, self.p0, 0.0, self.p2, self.p3);
329 }
330 if x < 2.0_f64 {
331 return poly3(x, self.q0, self.q1, self.q2, self.q3);
332 }
333 0.0_f64
334 }
335}
336
337#[inline(always)]
338fn poly3(x: f64, c0: f64, c1: f64, c2: f64, c3: f64) -> f64 {
339 x.mul_add(x.mul_add(x.mul_add(c3, c2), c1), c0)
341}
342
343#[inline(always)]
344fn lanczos_filter(x: f64, taps: usize) -> f64 {
345 let x = x.abs();
346 if x < taps as f64 {
347 sinc(x) * sinc(x / taps as f64)
348 } else {
349 0.0_f64
350 }
351}
352
353#[inline(always)]
354fn sinc(x: f64) -> f64 {
355 if x == 0.0_f64 {
357 1.0_f64
358 } else {
359 (x * PI).sin() / (x * PI)
360 }
361}