use std::ops::Deref; use criterion::black_box; use image::{imageops, ImageBuffer}; use fast_image_resize::images::Image; use fast_image_resize::{CpuExtensions, FilterType, ResizeAlg, ResizeOptions, Resizer}; use testing::{cpu_ext_into_str, PixelTestingExt}; use crate::utils::bencher::{bench, BenchGroup}; const ALG_NAMES: [&str; 5] = ["Nearest", "Box", "Bilinear", "Bicubic", "Lanczos3"]; const NEW_WIDTH: u32 = 852; const NEW_HEIGHT: u32 = 567; /// Resize image with help of "image" crate (https://crates.io/crates/image) pub fn image_resize(bench_group: &mut BenchGroup, src_image: &ImageBuffer) where P: image::Pixel + 'static, C: Deref, { for alg_name in ALG_NAMES { let (filter, sample_size) = match alg_name { "Nearest" => (imageops::Nearest, 80), "Bilinear" => (imageops::Triangle, 50), "Bicubic" => (imageops::CatmullRom, 30), "Lanczos3" => (imageops::Lanczos3, 20), _ => continue, }; bench(bench_group, sample_size, "image", alg_name, |bencher| { bencher.iter(|| { imageops::resize(src_image, NEW_WIDTH, NEW_HEIGHT, filter); }) }); } } /// Resize image with help of "resize" crate (https://crates.io/crates/resize) pub fn resize_resize( bench_group: &mut BenchGroup, pixel_format: Format, src_image: &[Format::InputPixel], src_width: u32, src_height: u32, ) where Out: Clone, Format: resize::PixelFormat + Copy, { for alg_name in ALG_NAMES { let mut dst = vec![pixel_format.into_pixel(Format::new()); (NEW_WIDTH * NEW_HEIGHT) as usize]; let sample_size = if alg_name == "Lanczos3" { 60 } else { 100 }; bench(bench_group, sample_size, "resize", alg_name, |bencher| { let filter = match alg_name { "Nearest" => resize::Type::Point, "Box" => resize::Type::Custom(resize::Filter::box_filter(0.5)), "Bilinear" => resize::Type::Triangle, "Bicubic" => resize::Type::Catrom, "Lanczos3" => resize::Type::Lanczos3, _ => return, }; let mut resizer = resize::new( src_width as usize, src_height as usize, NEW_WIDTH as usize, NEW_HEIGHT as usize, pixel_format, filter, ) .unwrap(); bencher.iter(|| { resizer.resize(src_image, &mut dst).unwrap(); }) }); } } /// Resize image with help of "libvips" crate (https://crates.io/crates/libvips) pub fn libvips_resize(bench_group: &mut BenchGroup, has_alpha: bool) { #[cfg(all(not(target_arch = "wasm32"), not(target_os = "windows")))] vips::libvips_resize_inner::

(bench_group, has_alpha); } #[cfg(all(not(target_arch = "wasm32"), not(target_os = "windows")))] mod vips { use libvips::ops::{self, BandFormat, Kernel, ReduceOptions}; use libvips::{VipsApp, VipsImage}; use super::*; const SAMPLE_SIZE: usize = 100; pub(crate) fn libvips_resize_inner( bench_group: &mut BenchGroup, has_alpha: bool, ) { let app = VipsApp::new("Test Libvips", false).expect("Cannot initialize libvips"); let num_threads: u32 = std::env::var("RAYON_NUM_THREADS") .map(|s| s.parse().unwrap_or(1)) .unwrap_or(1); if num_threads > 0 { app.concurrency_set(num_threads as i32); } app.cache_set_max(0); app.cache_set_max_mem(0); let src_image_data = P::load_big_src_image(); let src_width = src_image_data.width() as i32; let src_height = src_image_data.height() as i32; let band_format = match P::count_of_component_values() { 0x100 => BandFormat::Uchar, 0x10000 => BandFormat::Ushort, 0 => BandFormat::Float, _ => panic!("Unknown type of pixel"), }; let src_vips_image = VipsImage::new_from_memory( src_image_data.buffer(), src_width, src_height, P::count_of_components() as i32, band_format, ) .unwrap(); let hshrink = src_width as f64 / NEW_WIDTH as f64; let vshrink = src_height as f64 / NEW_HEIGHT as f64; for alg_name in ALG_NAMES { let kernel = match alg_name { "Nearest" => Kernel::Nearest, "Box" => { bench(bench_group, SAMPLE_SIZE, "libvips", alg_name, |bencher| { if has_alpha { bencher.iter(|| { let premultiplied = ops::premultiply(&src_vips_image).unwrap(); let resized = ops::shrink(&premultiplied, hshrink, vshrink).unwrap(); let result = ops::unpremultiply(&resized).unwrap(); let result = ops::cast(&result, band_format).unwrap(); let res_bytes = result.image_write_to_memory(); black_box(&res_bytes); }) } else { bencher.iter(|| { let result = ops::shrink(&src_vips_image, hshrink, vshrink).unwrap(); let res_bytes = result.image_write_to_memory(); black_box(&res_bytes); }) } }); continue; } "Bilinear" => Kernel::Linear, "Bicubic" => Kernel::Cubic, "Lanczos3" => Kernel::Lanczos3, _ => continue, }; let options = ReduceOptions { kernel, gap: 0. }; bench(bench_group, SAMPLE_SIZE, "libvips", alg_name, |bencher| { if has_alpha && alg_name != "Nearest" { bencher.iter(|| { let premultiplied = ops::premultiply(&src_vips_image).unwrap(); let resized = ops::reduce_with_opts(&premultiplied, hshrink, vshrink, &options) .unwrap(); let result = ops::unpremultiply(&resized).unwrap(); let result = ops::cast(&result, band_format).unwrap(); let res_bytes = result.image_write_to_memory(); black_box(&res_bytes); }) } else { bencher.iter(|| { let result = ops::reduce_with_opts(&src_vips_image, hshrink, vshrink, &options) .unwrap(); let res_bytes = result.image_write_to_memory(); black_box(&res_bytes); }) } }); } } } /// Resize image with help of "fast_imager_resize" crate pub fn fir_resize(bench_group: &mut BenchGroup, use_alpha: bool) { let src_image_data = P::load_big_src_image(); let mut dst_image = Image::new(NEW_WIDTH, NEW_HEIGHT, src_image_data.pixel_type()); let mut cpu_extensions = vec![CpuExtensions::None]; #[cfg(target_arch = "x86_64")] { cpu_extensions.push(CpuExtensions::Sse4_1); cpu_extensions.push(CpuExtensions::Avx2); } #[cfg(target_arch = "aarch64")] { cpu_extensions.push(CpuExtensions::Neon); } #[cfg(target_arch = "wasm32")] { cpu_extensions.push(CpuExtensions::Simd128); } for cpu_ext in cpu_extensions { for alg_name in ALG_NAMES { let resize_alg = match alg_name { "Nearest" => ResizeAlg::Nearest, "Box" => ResizeAlg::Convolution(FilterType::Box), "Bilinear" => ResizeAlg::Convolution(FilterType::Bilinear), "Bicubic" => ResizeAlg::Convolution(FilterType::CatmullRom), "Lanczos3" => ResizeAlg::Convolution(FilterType::Lanczos3), _ => continue, }; let mut fast_resizer = Resizer::new(); unsafe { fast_resizer.set_cpu_extensions(cpu_ext); } let sample_size = 100; let resize_options = ResizeOptions::new() .resize_alg(resize_alg) .use_alpha(use_alpha); bench( bench_group, sample_size, format!("fir {}", cpu_ext_into_str(cpu_ext)), alg_name, |bencher| { bencher.iter(|| { fast_resizer .resize(&src_image_data, &mut dst_image, &resize_options) .unwrap() }) }, ); } } }