1#![deny(clippy::all)]
2#![warn(clippy::nursery)]
3#![warn(clippy::pedantic)]
4#![allow(clippy::cast_possible_truncation)]
5#![allow(clippy::cast_possible_wrap)]
6#![allow(clippy::cast_precision_loss)]
7#![allow(clippy::cast_sign_loss)]
8#![allow(clippy::default_trait_access)]
9#![allow(clippy::inconsistent_struct_constructor)]
10#![allow(clippy::inline_always)]
11#![allow(clippy::missing_panics_doc)]
12#![allow(clippy::module_name_repetitions)]
13#![allow(clippy::redundant_closure_for_method_calls)]
14#![allow(clippy::similar_names)]
15#![allow(clippy::struct_excessive_bools)]
16#![allow(clippy::use_self)]
17#![warn(clippy::clone_on_ref_ptr)]
18#![warn(clippy::create_dir)]
19#![warn(clippy::dbg_macro)]
20#![warn(clippy::default_numeric_fallback)]
21#![warn(clippy::exit)]
22#![warn(clippy::filetype_is_file)]
23#![warn(clippy::float_cmp_const)]
24#![warn(clippy::if_then_some_else_none)]
25#![warn(clippy::lossy_float_literal)]
26#![warn(clippy::map_err_ignore)]
27#![warn(clippy::mem_forget)]
28#![warn(clippy::multiple_inherent_impl)]
29#![warn(clippy::pattern_type_mismatch)]
30#![warn(clippy::rc_buffer)]
31#![warn(clippy::rc_mutex)]
32#![warn(clippy::rest_pat_in_fully_bound_structs)]
33#![warn(clippy::same_name_method)]
34#![warn(clippy::str_to_string)]
35#![warn(clippy::undocumented_unsafe_blocks)]
36#![warn(clippy::unnecessary_self_imports)]
37#![warn(clippy::unneeded_field_pattern)]
38#![warn(clippy::use_debug)]
39#![warn(clippy::verbose_file_reads)]
40
41mod resize;
42mod util;
43
44use std::{
45 mem::size_of,
46 num::{NonZeroU8, NonZeroUsize},
47};
48
49pub use crate::resize::{ResizeAlgorithm, ResizeDimensions, algorithms};
50use crate::resize::{resize_horizontal, resize_vertical, should_resize_horiz_first};
51use anyhow::{Result, ensure};
52use v_frame::{
53 chroma::ChromaSubsampling,
54 frame::{Frame, FrameBuilder},
55 pixel::Pixel,
56};
57
58#[derive(Debug, Clone, Copy)]
60pub struct CropDimensions {
61 pub top: usize,
62 pub bottom: usize,
63 pub left: usize,
64 pub right: usize,
65}
66
67pub fn crop<T: Pixel>(input: &Frame<T>, dimensions: CropDimensions) -> Result<Frame<T>> {
73 ensure!(
74 dimensions.top % 2 == 0
75 && dimensions.bottom % 2 == 0
76 && dimensions.left % 2 == 0
77 && dimensions.right % 2 == 0,
78 "Crop dimensions must be a multiple of 2"
79 );
80 ensure!(
81 dimensions.left + dimensions.right <= input.y_plane.width().get() + 4,
82 "Resulting width must be at least 4 pixels"
83 );
84 ensure!(
85 dimensions.top + dimensions.bottom <= input.y_plane.height().get() + 4,
86 "Resulting height must be at least 4 pixels"
87 );
88
89 let new_w = unsafe {
91 NonZeroUsize::new_unchecked(
92 input.y_plane.width().get() - dimensions.left - dimensions.right,
93 )
94 };
95 let new_h = unsafe {
97 NonZeroUsize::new_unchecked(
98 input.y_plane.height().get() - dimensions.top - dimensions.bottom,
99 )
100 };
101 let mut output: Frame<T> =
102 FrameBuilder::new(new_w, new_h, input.subsampling, input.bit_depth).build()?;
103 for p in 0..(if input.subsampling == ChromaSubsampling::Monochrome {
104 1
105 } else {
106 3
107 }) {
108 let input_plane = input.plane(p).expect("plane exists");
109 let output_plane = output.plane_mut(p).expect("plane exists");
110 let plane_cfg = &input_plane.geometry();
111 let new_w = new_w.get() / plane_cfg.subsampling_x.get() as usize;
112 let new_h = new_h.get() / plane_cfg.subsampling_y.get() as usize;
113 let left = dimensions.left / plane_cfg.subsampling_x.get() as usize;
114 let top = dimensions.top / plane_cfg.subsampling_y.get() as usize;
115
116 for (out_row, in_row) in output_plane
117 .rows_mut()
118 .zip(input_plane.rows().skip(top).take(new_h))
119 {
120 unsafe {
124 out_row
125 .as_mut_ptr()
126 .copy_from_nonoverlapping(in_row.as_ptr().add(left), new_w);
127 }
128 }
129 }
130
131 Ok(output)
132}
133
134#[cfg(feature = "devel")]
135pub fn crop_u8(input: &Frame<u8>, dimensions: CropDimensions) -> Result<Frame<u8>> {
137 crop::<u8>(input, dimensions)
138}
139
140#[cfg(feature = "devel")]
141pub fn crop_u16(input: &Frame<u16>, dimensions: CropDimensions) -> Result<Frame<u16>> {
143 crop::<u16>(input, dimensions)
144}
145
146pub fn resize<T: Pixel, F: ResizeAlgorithm>(
153 input: &Frame<T>,
154 dimensions: ResizeDimensions,
155 input_bit_depth: NonZeroU8,
156) -> Result<Frame<T>> {
157 if size_of::<T>() == 1 {
158 ensure!(
159 input_bit_depth.get() == 8,
160 "input bit depth must be 8 for 8-bit pixel type"
161 );
162 } else if size_of::<T>() == 2 {
163 ensure!(
164 input_bit_depth.get() > 8 && input_bit_depth.get() <= 16,
165 "input bit depth must be between 9-16 for 8-bit pixel type"
166 );
167 } else {
168 unreachable!("32-bit types not implemented in v_frame");
169 }
170 let (ss_x, ss_y) = input
171 .subsampling
172 .subsample_ratio()
173 .map_or((1, 1), |(x, y)| (x.get() as usize, y.get() as usize));
174 ensure!(
175 dimensions.width.get() % ss_x == 0 && dimensions.height.get() % ss_y == 0,
176 "Resize dimensions must be a multiple of subsampling ratio"
177 );
178 ensure!(
179 dimensions.width.get() >= 4 && dimensions.height.get() >= 4,
180 "Resulting image must be at least 4x4 pixels"
181 );
182
183 let src_w = input.y_plane.width();
184 let src_h = input.y_plane.height();
185 let resize_horiz = src_w != dimensions.width;
186 let resize_vert = src_h != dimensions.height;
187 if !resize_horiz {
188 return resize_vertical::<T, F>(input, dimensions.height, input_bit_depth);
189 }
190
191 if !resize_vert {
192 return resize_horizontal::<T, F>(input, dimensions.width, input_bit_depth);
193 }
194
195 let horiz_first = should_resize_horiz_first(
196 dimensions.width.get() as f32 / src_w.get() as f32,
197 dimensions.height.get() as f32 / src_h.get() as f32,
198 );
199 if horiz_first {
200 let temp = resize_horizontal::<T, F>(input, dimensions.width, input_bit_depth)?;
201 return resize_vertical::<T, F>(&temp, dimensions.height, input_bit_depth);
202 }
203 let temp = resize_vertical::<T, F>(input, dimensions.height, input_bit_depth)?;
204 resize_horizontal::<T, F>(&temp, dimensions.width, input_bit_depth)
205}
206
207#[cfg(feature = "devel")]
208pub fn resize_horizontal_u8_bicubic(input: &Frame<u8>, dest_width: usize) -> Frame<u8> {
209 use resize::algorithms::BicubicMitchell;
210
211 resize_horizontal::<u8, BicubicMitchell>(input, dest_width, 8)
212}
213
214#[cfg(feature = "devel")]
215pub fn resize_horizontal_u16_bicubic(
216 input: &Frame<u16>,
217 dest_width: usize,
218 input_bit_depth: usize,
219) -> Frame<u16> {
220 use resize::algorithms::BicubicMitchell;
221
222 resize_horizontal::<u16, BicubicMitchell>(input, dest_width, input_bit_depth)
223}
224
225#[cfg(feature = "devel")]
226pub fn resize_vertical_u8_bicubic(input: &Frame<u8>, dest_height: usize) -> Frame<u8> {
227 use resize::algorithms::BicubicMitchell;
228
229 resize_vertical::<u8, BicubicMitchell>(input, dest_height, 8)
230}
231
232#[cfg(feature = "devel")]
233pub fn resize_vertical_u16_bicubic(
234 input: &Frame<u16>,
235 dest_height: usize,
236 input_bit_depth: usize,
237) -> Frame<u16> {
238 use resize::algorithms::BicubicMitchell;
239
240 resize_vertical::<u16, BicubicMitchell>(input, dest_height, input_bit_depth)
241}
242
243#[cfg(feature = "devel")]
244pub fn resize_horizontal_u8_lanczos3(input: &Frame<u8>, dest_width: usize) -> Frame<u8> {
245 use resize::algorithms::Lanczos3;
246
247 resize_horizontal::<u8, Lanczos3>(input, dest_width, 8)
248}
249
250#[cfg(feature = "devel")]
251pub fn resize_horizontal_u16_lanczos3(
252 input: &Frame<u16>,
253 dest_width: usize,
254 input_bit_depth: usize,
255) -> Frame<u16> {
256 use resize::algorithms::Lanczos3;
257
258 resize_horizontal::<u16, Lanczos3>(input, dest_width, input_bit_depth)
259}
260
261#[cfg(feature = "devel")]
262pub fn resize_vertical_u8_lanczos3(input: &Frame<u8>, dest_height: usize) -> Frame<u8> {
263 use resize::algorithms::Lanczos3;
264
265 resize_vertical::<u8, Lanczos3>(input, dest_height, 8)
266}
267
268#[cfg(feature = "devel")]
269pub fn resize_vertical_u16_lanczos3(
270 input: &Frame<u16>,
271 dest_height: usize,
272 input_bit_depth: usize,
273) -> Frame<u16> {
274 use resize::algorithms::Lanczos3;
275
276 resize_vertical::<u16, Lanczos3>(input, dest_height, input_bit_depth)
277}
278
279#[cfg(feature = "devel")]
280pub fn resize_horizontal_u8_spline36(input: &Frame<u8>, dest_width: usize) -> Frame<u8> {
281 use resize::algorithms::Spline36;
282
283 resize_horizontal::<u8, Spline36>(input, dest_width, 8)
284}
285
286#[cfg(feature = "devel")]
287pub fn resize_horizontal_u16_spline36(
288 input: &Frame<u16>,
289 dest_width: usize,
290 input_bit_depth: usize,
291) -> Frame<u16> {
292 use resize::algorithms::Spline36;
293
294 resize_horizontal::<u16, Spline36>(input, dest_width, input_bit_depth)
295}
296
297#[cfg(feature = "devel")]
298pub fn resize_vertical_u8_spline36(input: &Frame<u8>, dest_height: usize) -> Frame<u8> {
299 use resize::algorithms::Spline36;
300
301 resize_vertical::<u8, Spline36>(input, dest_height, 8)
302}
303
304#[cfg(feature = "devel")]
305pub fn resize_vertical_u16_spline36(
306 input: &Frame<u16>,
307 dest_height: usize,
308 input_bit_depth: usize,
309) -> Frame<u16> {
310 use resize::algorithms::Spline36;
311
312 resize_vertical::<u16, Spline36>(input, dest_height, input_bit_depth)
313}
314
315#[doc(hidden)]
328pub fn resample_bit_depth<T: Pixel, U: Pixel>(
329 _input: &Frame<T>,
330 input_bit_depth: usize,
331 target_bit_depth: usize,
332 _dither: bool,
333) -> Result<Frame<U>> {
334 if size_of::<T>() == 1 {
335 ensure!(
336 input_bit_depth == 8,
337 "input bit depth must be 8 for 8-bit pixel type"
338 );
339 } else if size_of::<T>() == 2 {
340 ensure!(
341 input_bit_depth > 8 && input_bit_depth <= 16,
342 "input bit depth must be between 9-16 for 8-bit pixel type"
343 );
344 } else {
345 unreachable!("32-bit types not implemented in v_frame");
346 }
347 if size_of::<U>() == 1 {
348 ensure!(
349 target_bit_depth == 8,
350 "target bit depth must be 8 for 8-bit pixel type"
351 );
352 } else if size_of::<U>() == 2 {
353 ensure!(
354 target_bit_depth > 8 && target_bit_depth <= 16,
355 "target bit depth must be between 9-16 for 8-bit pixel type"
356 );
357 } else {
358 unreachable!("32-bit types not implemented in v_frame");
359 }
360 ensure!(
361 [8, 10, 12, 16].contains(&target_bit_depth),
362 "Currently supported bit depths are 8, 10, 12, and 16"
363 );
364
365 todo!()
366}
367
368#[doc(hidden)]
378pub fn resample_chroma_sampling<T: Pixel, F: ResizeAlgorithm>(
379 _input: &Frame<T>,
380 input_bit_depth: usize,
381 _target_chroma_sampling: ChromaSubsampling,
382) -> Result<Frame<T>> {
383 if size_of::<T>() == 1 {
384 ensure!(
385 input_bit_depth == 8,
386 "input bit depth must be 8 for 8-bit pixel type"
387 );
388 } else if size_of::<T>() == 2 {
389 ensure!(
390 input_bit_depth > 8 && input_bit_depth <= 16,
391 "input bit depth must be between 9-16 for 8-bit pixel type"
392 );
393 } else {
394 unreachable!("32-bit types not implemented in v_frame");
395 }
396
397 todo!()
398}
399
400#[cfg(test)]
401mod tests {
402 use std::{
403 fs,
404 num::{NonZeroU8, NonZeroUsize},
405 path::Path,
406 };
407
408 use image::{DynamicImage, Rgb32FImage};
409 use yuvxyb::{
410 ColorPrimaries, Frame, MatrixCoefficients, Rgb, TransferCharacteristic, Yuv, YuvConfig,
411 };
412
413 use crate::{
414 CropDimensions, ResizeDimensions,
415 algorithms::{BicubicCatmullRom, Bilinear, Lanczos3, Point, Spline64},
416 crop, resize,
417 };
418
419 fn get_u8_test_image() -> Frame<u8> {
420 let i = image::open("./test_files/ducks_take_off.png")
421 .unwrap()
422 .to_rgb32f();
423 let rgb = Rgb::new(
424 i.pixels().map(|p| [p[0], p[1], p[2]]).collect(),
425 NonZeroUsize::new(i.width() as usize).expect("not zero"),
426 NonZeroUsize::new(i.height() as usize).expect("not zero"),
427 TransferCharacteristic::BT1886,
428 ColorPrimaries::BT709,
429 )
430 .unwrap();
431 let yuv: Yuv<u8> = (
432 rgb,
433 YuvConfig {
434 bit_depth: 8,
435 subsampling_x: 1,
436 subsampling_y: 1,
437 full_range: false,
438 matrix_coefficients: MatrixCoefficients::BT709,
439 transfer_characteristics: TransferCharacteristic::BT1886,
440 color_primaries: ColorPrimaries::BT709,
441 },
442 )
443 .try_into()
444 .unwrap();
445 let data = yuv.data();
446 data.clone()
447 }
448
449 fn get_u16_test_image() -> Frame<u16> {
450 let i = image::open("./test_files/ducks_take_off.png")
451 .unwrap()
452 .to_rgb32f();
453 let rgb = Rgb::new(
454 i.pixels().map(|p| [p[0], p[1], p[2]]).collect(),
455 NonZeroUsize::new(i.width() as usize).expect("not zero"),
456 NonZeroUsize::new(i.height() as usize).expect("not zero"),
457 TransferCharacteristic::BT1886,
458 ColorPrimaries::BT709,
459 )
460 .unwrap();
461 let yuv: Yuv<u16> = (
462 rgb,
463 YuvConfig {
464 bit_depth: 10,
465 subsampling_x: 1,
466 subsampling_y: 1,
467 full_range: false,
468 matrix_coefficients: MatrixCoefficients::BT709,
469 transfer_characteristics: TransferCharacteristic::BT1886,
470 color_primaries: ColorPrimaries::BT709,
471 },
472 )
473 .try_into()
474 .unwrap();
475 let data = yuv.data();
476 data.clone()
477 }
478
479 fn output_image_from_u8(image: Frame<u8>, filename: &str) {
480 let width = image.y_plane.width();
481 let height = image.y_plane.height();
482 let yuv: Yuv<u8> = Yuv::new(
483 image,
484 YuvConfig {
485 bit_depth: 8,
486 subsampling_x: 1,
487 subsampling_y: 1,
488 full_range: false,
489 matrix_coefficients: MatrixCoefficients::BT709,
490 transfer_characteristics: TransferCharacteristic::BT1886,
491 color_primaries: ColorPrimaries::BT709,
492 },
493 )
494 .unwrap();
495 let rgb: Rgb = yuv.try_into().unwrap();
496 let i = DynamicImage::ImageRgb32F(
497 Rgb32FImage::from_vec(
498 width.get() as u32,
499 height.get() as u32,
500 rgb.data().iter().copied().flatten().collect(),
501 )
502 .unwrap(),
503 )
504 .to_rgb8();
505 if !Path::new("/tmp/video-resize-tests").is_dir() {
506 fs::create_dir_all("/tmp/video-resize-tests").unwrap();
507 }
508 i.save(filename).unwrap();
509 }
510
511 fn output_image_from_u16(image: Frame<u16>, filename: &str) {
512 let width = image.y_plane.width();
513 let height = image.y_plane.height();
514 let yuv: Yuv<u16> = Yuv::new(
515 image,
516 YuvConfig {
517 bit_depth: 10,
518 subsampling_x: 1,
519 subsampling_y: 1,
520 full_range: false,
521 matrix_coefficients: MatrixCoefficients::BT709,
522 transfer_characteristics: TransferCharacteristic::BT1886,
523 color_primaries: ColorPrimaries::BT709,
524 },
525 )
526 .unwrap();
527 let rgb: Rgb = yuv.try_into().unwrap();
528 let i = DynamicImage::ImageRgb32F(
529 Rgb32FImage::from_vec(
530 width.get() as u32,
531 height.get() as u32,
532 rgb.data().iter().copied().flatten().collect(),
533 )
534 .unwrap(),
535 )
536 .to_rgb16();
537 if !Path::new("/tmp/video-resize-tests").is_dir() {
538 fs::create_dir_all("/tmp/video-resize-tests").unwrap();
539 }
540 i.save(filename).unwrap();
541 }
542
543 #[test]
544 fn crop_u8() {
545 let input = get_u8_test_image();
546 let output = crop::<u8>(
547 &input,
548 CropDimensions {
549 top: 40,
550 bottom: 40,
551 left: 20,
552 right: 20,
553 },
554 )
555 .unwrap();
556 output_image_from_u8(output, "/tmp/video-resize-tests/crop_u8.png");
557 }
558
559 #[test]
560 fn crop_u16() {
561 let input = get_u16_test_image();
562 let output = crop::<u16>(
563 &input,
564 CropDimensions {
565 top: 40,
566 bottom: 40,
567 left: 20,
568 right: 20,
569 },
570 )
571 .unwrap();
572 output_image_from_u16(output, "/tmp/video-resize-tests/crop_u16.png");
573 }
574
575 #[test]
576 fn resize_point_u8_down() {
577 let input = get_u8_test_image();
578 let output = resize::<u8, Point>(
579 &input,
580 ResizeDimensions {
581 width: NonZeroUsize::new(1280).expect("not zero"),
582 height: NonZeroUsize::new(720).expect("not zero"),
583 },
584 NonZeroU8::new(8).expect("not zero"),
585 )
586 .unwrap();
587 output_image_from_u8(output, "/tmp/video-resize-tests/resize_point_u8_down.png");
588 }
589
590 #[test]
591 fn resize_point_u16_down() {
592 let input = get_u16_test_image();
593 let output = resize::<u16, Point>(
594 &input,
595 ResizeDimensions {
596 width: NonZeroUsize::new(1280).expect("not zero"),
597 height: NonZeroUsize::new(720).expect("not zero"),
598 },
599 NonZeroU8::new(10).expect("not zero"),
600 )
601 .unwrap();
602 output_image_from_u16(output, "/tmp/video-resize-tests/resize_point_u16_down.png");
603 }
604
605 #[test]
606 fn resize_point_u8_up() {
607 let input = get_u8_test_image();
608 let output = resize::<u8, Point>(
609 &input,
610 ResizeDimensions {
611 width: NonZeroUsize::new(2560).expect("not zero"),
612 height: NonZeroUsize::new(1440).expect("not zero"),
613 },
614 NonZeroU8::new(8).expect("not zero"),
615 )
616 .unwrap();
617 output_image_from_u8(output, "/tmp/video-resize-tests/resize_point_u8_up.png");
618 }
619
620 #[test]
621 fn resize_point_u16_up() {
622 let input = get_u16_test_image();
623 let output = resize::<u16, Point>(
624 &input,
625 ResizeDimensions {
626 width: NonZeroUsize::new(2560).expect("not zero"),
627 height: NonZeroUsize::new(1440).expect("not zero"),
628 },
629 NonZeroU8::new(10).expect("not zero"),
630 )
631 .unwrap();
632 output_image_from_u16(output, "/tmp/video-resize-tests/resize_point_u16_up.png");
633 }
634
635 #[test]
636 fn resize_bilinear_u8_down() {
637 let input = get_u8_test_image();
638 let output = resize::<u8, Bilinear>(
639 &input,
640 ResizeDimensions {
641 width: NonZeroUsize::new(1280).expect("not zero"),
642 height: NonZeroUsize::new(720).expect("not zero"),
643 },
644 NonZeroU8::new(8).expect("not zero"),
645 )
646 .unwrap();
647 output_image_from_u8(
648 output,
649 "/tmp/video-resize-tests/resize_bilinear_u8_down.png",
650 );
651 }
652
653 #[test]
654 fn resize_bilinear_u16_down() {
655 let input = get_u16_test_image();
656 let output = resize::<u16, Bilinear>(
657 &input,
658 ResizeDimensions {
659 width: NonZeroUsize::new(1280).expect("not zero"),
660 height: NonZeroUsize::new(720).expect("not zero"),
661 },
662 NonZeroU8::new(10).expect("not zero"),
663 )
664 .unwrap();
665 output_image_from_u16(
666 output,
667 "/tmp/video-resize-tests/resize_bilinear_u16_down.png",
668 );
669 }
670
671 #[test]
672 fn resize_bilinear_u8_up() {
673 let input = get_u8_test_image();
674 let output = resize::<u8, Bilinear>(
675 &input,
676 ResizeDimensions {
677 width: NonZeroUsize::new(2560).expect("not zero"),
678 height: NonZeroUsize::new(1440).expect("not zero"),
679 },
680 NonZeroU8::new(8).expect("not zero"),
681 )
682 .unwrap();
683 output_image_from_u8(output, "/tmp/video-resize-tests/resize_bilinear_u8_up.png");
684 }
685
686 #[test]
687 fn resize_bilinear_u16_up() {
688 let input = get_u16_test_image();
689 let output = resize::<u16, Bilinear>(
690 &input,
691 ResizeDimensions {
692 width: NonZeroUsize::new(2560).expect("not zero"),
693 height: NonZeroUsize::new(1440).expect("not zero"),
694 },
695 NonZeroU8::new(10).expect("not zero"),
696 )
697 .unwrap();
698 output_image_from_u16(output, "/tmp/video-resize-tests/resize_bilinear_u16_up.png");
699 }
700
701 #[test]
702 fn resize_bicubic_u8_down() {
703 let input = get_u8_test_image();
704 let output = resize::<u8, BicubicCatmullRom>(
705 &input,
706 ResizeDimensions {
707 width: NonZeroUsize::new(1280).expect("not zero"),
708 height: NonZeroUsize::new(720).expect("not zero"),
709 },
710 NonZeroU8::new(8).expect("not zero"),
711 )
712 .unwrap();
713 output_image_from_u8(output, "/tmp/video-resize-tests/resize_bicubic_u8_down.png");
714 }
715
716 #[test]
717 fn resize_bicubic_u16_down() {
718 let input = get_u16_test_image();
719 let output = resize::<u16, BicubicCatmullRom>(
720 &input,
721 ResizeDimensions {
722 width: NonZeroUsize::new(1280).expect("not zero"),
723 height: NonZeroUsize::new(720).expect("not zero"),
724 },
725 NonZeroU8::new(10).expect("not zero"),
726 )
727 .unwrap();
728 output_image_from_u16(
729 output,
730 "/tmp/video-resize-tests/resize_bicubic_u16_down.png",
731 );
732 }
733
734 #[test]
735 fn resize_bicubic_u8_up() {
736 let input = get_u8_test_image();
737 let output = resize::<u8, BicubicCatmullRom>(
738 &input,
739 ResizeDimensions {
740 width: NonZeroUsize::new(2560).expect("not zero"),
741 height: NonZeroUsize::new(1440).expect("not zero"),
742 },
743 NonZeroU8::new(8).expect("not zero"),
744 )
745 .unwrap();
746 output_image_from_u8(output, "/tmp/video-resize-tests/resize_bicubic_u8_up.png");
747 }
748
749 #[test]
750 fn resize_bicubic_u16_up() {
751 let input = get_u16_test_image();
752 let output = resize::<u16, BicubicCatmullRom>(
753 &input,
754 ResizeDimensions {
755 width: NonZeroUsize::new(2560).expect("not zero"),
756 height: NonZeroUsize::new(1440).expect("not zero"),
757 },
758 NonZeroU8::new(10).expect("not zero"),
759 )
760 .unwrap();
761 output_image_from_u16(output, "/tmp/video-resize-tests/resize_bicubic_u16_up.png");
762 }
763
764 #[test]
765 fn resize_lanczos_u8_down() {
766 let input = get_u8_test_image();
767 let output = resize::<u8, Lanczos3>(
768 &input,
769 ResizeDimensions {
770 width: NonZeroUsize::new(1280).expect("not zero"),
771 height: NonZeroUsize::new(720).expect("not zero"),
772 },
773 NonZeroU8::new(8).expect("not zero"),
774 )
775 .unwrap();
776 output_image_from_u8(output, "/tmp/video-resize-tests/resize_lanczos_u8_down.png");
777 }
778
779 #[test]
780 fn resize_lanczos_u16_down() {
781 let input = get_u16_test_image();
782 let output = resize::<u16, Lanczos3>(
783 &input,
784 ResizeDimensions {
785 width: NonZeroUsize::new(1280).expect("not zero"),
786 height: NonZeroUsize::new(720).expect("not zero"),
787 },
788 NonZeroU8::new(10).expect("not zero"),
789 )
790 .unwrap();
791 output_image_from_u16(
792 output,
793 "/tmp/video-resize-tests/resize_lanczos_u16_down.png",
794 );
795 }
796
797 #[test]
798 fn resize_lanczos_u8_up() {
799 let input = get_u8_test_image();
800 let output = resize::<u8, Lanczos3>(
801 &input,
802 ResizeDimensions {
803 width: NonZeroUsize::new(2560).expect("not zero"),
804 height: NonZeroUsize::new(1440).expect("not zero"),
805 },
806 NonZeroU8::new(8).expect("not zero"),
807 )
808 .unwrap();
809 output_image_from_u8(output, "/tmp/video-resize-tests/resize_lanczos_u8_up.png");
810 }
811
812 #[test]
813 fn resize_lanczos_u16_up() {
814 let input = get_u16_test_image();
815 let output = resize::<u16, Lanczos3>(
816 &input,
817 ResizeDimensions {
818 width: NonZeroUsize::new(2560).expect("not zero"),
819 height: NonZeroUsize::new(1440).expect("not zero"),
820 },
821 NonZeroU8::new(10).expect("not zero"),
822 )
823 .unwrap();
824 output_image_from_u16(output, "/tmp/video-resize-tests/resize_lanczos_u16_up.png");
825 }
826
827 #[test]
828 fn resize_spline64_u8_down() {
829 let input = get_u8_test_image();
830 let output = resize::<u8, Spline64>(
831 &input,
832 ResizeDimensions {
833 width: NonZeroUsize::new(1280).expect("not zero"),
834 height: NonZeroUsize::new(720).expect("not zero"),
835 },
836 NonZeroU8::new(8).expect("not zero"),
837 )
838 .unwrap();
839 output_image_from_u8(
840 output,
841 "/tmp/video-resize-tests/resize_spline64_u8_down.png",
842 );
843 }
844
845 #[test]
846 fn resize_spline64_u16_down() {
847 let input = get_u16_test_image();
848 let output = resize::<u16, Spline64>(
849 &input,
850 ResizeDimensions {
851 width: NonZeroUsize::new(1280).expect("not zero"),
852 height: NonZeroUsize::new(720).expect("not zero"),
853 },
854 NonZeroU8::new(10).expect("not zero"),
855 )
856 .unwrap();
857 output_image_from_u16(
858 output,
859 "/tmp/video-resize-tests/resize_spline64_u16_down.png",
860 );
861 }
862
863 #[test]
864 fn resize_spline64_u8_up() {
865 let input = get_u8_test_image();
866 let output = resize::<u8, Spline64>(
867 &input,
868 ResizeDimensions {
869 width: NonZeroUsize::new(2560).expect("not zero"),
870 height: NonZeroUsize::new(1440).expect("not zero"),
871 },
872 NonZeroU8::new(8).expect("not zero"),
873 )
874 .unwrap();
875 output_image_from_u8(output, "/tmp/video-resize-tests/resize_spline64_u8_up.png");
876 }
877
878 #[test]
879 fn resize_spline64_u16_up() {
880 let input = get_u16_test_image();
881 let output = resize::<u16, Spline64>(
882 &input,
883 ResizeDimensions {
884 width: NonZeroUsize::new(2560).expect("not zero"),
885 height: NonZeroUsize::new(1440).expect("not zero"),
886 },
887 NonZeroU8::new(10).expect("not zero"),
888 )
889 .unwrap();
890 output_image_from_u16(output, "/tmp/video-resize-tests/resize_spline64_u16_up.png");
891 }
892}