#![allow(non_camel_case_types)] use criterion::*; type fb = imagescript::framebuffer; fn read(p: &str) -> lodepng::Bitmap { return lodepng::decode32_file(p).unwrap(); } fn imagers_rotate90(img: &mut image::DynamicImage) { img.rotate90(); } fn imagers_rotate180(img: &mut image::DynamicImage) { img.rotate180(); } fn imagers_rotate270(img: &mut image::DynamicImage) { img.rotate270(); } fn imagers_flip_vertical(img: &mut image::DynamicImage) { img.flipv(); } fn imagers_grayscale(img: &mut image::DynamicImage) { img.grayscale(); } fn imagers_flip_horizontal(img: &mut image::DynamicImage) { img.fliph(); } fn imagescript_rotate90(fb: &mut fb) { imagescript::ops::rotate::rotate90(fb); } fn imagescript_init(width: usize, height: usize) -> fb { fb::new(width, height) } fn imagers_invert(img: &mut image::DynamicImage) { image::imageops::invert(img); } fn imagescript_rotate180(fb: &mut fb) { imagescript::ops::rotate::rotate180(fb); } fn imagescript_rotate270(fb: &mut fb) { imagescript::ops::rotate::rotate270(fb); } fn imagescript_flip_vertical(fb: &mut fb) { imagescript::ops::flip::vertical(fb); } fn imagescript_flip_horizontal(fb: &mut fb) { imagescript::ops::flip::horizontal(fb); } fn imagers_blur_gaussian(img: &mut image::DynamicImage, sigma: f32) { img.blur(sigma); } fn imagers_brightness(img: &mut image::DynamicImage, amount: i32) { img.brighten(amount); } fn imagers_huerotate(img: &mut image::DynamicImage, amount: i32) { img.huerotate(amount); } fn imagescript_sepia(fb: &mut fb, amount: f32) { imagescript::ops::filter::sepia(fb, amount); } fn imagers_contrast(img: &mut image::DynamicImage, amount: f32) { img.adjust_contrast(amount); } fn imagescript_overlay(fb: &mut fb, fg: &fb) { imagescript::ops::overlay::blend(fb, fg, 0, 0); } fn imagescript_invert(fb: &mut fb, amount: f32) { imagescript::ops::filter::invert(fb, amount); } fn imagescript_replace(fb: &mut fb, fg: &fb) { imagescript::ops::overlay::replace(fb, fg, 0, 0); } fn imagescript_opacity(fb: &mut fb, amount: f32) { imagescript::ops::filter::opacity(fb, amount); } fn imagescript_contrast(fb: &mut fb, amount: f32) { imagescript::ops::filter::contrast(fb, amount); } fn imagescript_saturate(fb: &mut fb, amount: f32) { imagescript::ops::filter::saturate(fb, amount); } fn imagescript_blur_gaussian(fb: &mut fb, sigma: f32) { imagescript::ops::blur::gaussian(fb, sigma); } fn imagescript_grayscale(fb: &mut fb, amount: f32) { imagescript::ops::filter::grayscale(fb, amount); } fn imagescript_huerotate(fb: &mut fb, amount: f32) { imagescript::ops::filter::hue_rotate(fb, amount); } fn imagescript_brightness(fb: &mut fb, amount: f32) { imagescript::ops::filter::brightness(fb, amount); } fn imagescript_init2(width: usize, height: usize) -> fb { return unsafe { fb::new_uninit(width, height) }; } fn imagers_replace(img: &mut image::DynamicImage, fg: &image::DynamicImage) { image::imageops::replace(img, fg, 0, 0); } fn imagers_overlay(img: &mut image::DynamicImage, fg: &image::DynamicImage) { image::imageops::overlay(img, fg, 0, 0); } fn imagescript_fill(fb: &mut fb) { imagescript::ops::fill::color(fb, imagescript::colors::rgba { r: 1, g: 2, b: 3, a: 4 }); } fn imagescript_resize_nearest(fb: &mut fb, width: usize, height: usize) { imagescript::ops::resize::nearest(fb, width, height); } fn vips_gaussian(img: &libvips::VipsImage, sigma: f64) -> libvips::VipsImage { return libvips::ops::gaussblur(&img, sigma).unwrap(); } fn vips_rotate90(img: &libvips::VipsImage) -> libvips::VipsImage { return libvips::ops::rot(&img, libvips::ops::Angle::D90).unwrap(); } fn vips_rotate180(img: &libvips::VipsImage) -> libvips::VipsImage { return libvips::ops::rot(&img, libvips::ops::Angle::D180).unwrap(); } fn vips_rotate270(img: &libvips::VipsImage) -> libvips::VipsImage { return libvips::ops::rot(&img, libvips::ops::Angle::D270).unwrap(); } fn imagers_init(width: usize, height: usize) -> image::DynamicImage { return image::DynamicImage::new_rgba8(width as u32, height as u32); } fn imagescript_crop(fb: &mut fb, x: isize, y: isize, width: usize, height: usize) { imagescript::ops::crop::r#box(fb, x, y, width, height); } fn vips_flip_vertical(img: &libvips::VipsImage) -> libvips::VipsImage { return libvips::ops::flip(&img, libvips::ops::Direction::Vertical).unwrap(); } fn imagers_crop(img: &mut image::DynamicImage, x: u32, y: u32, width: u32, height: u32) { image::imageops::crop(img, x, y, width, height).to_image(); } fn imagers_fill(img: &mut image::DynamicImage) { let c = image::Rgba::([1, 2, 3, 4]); img.as_mut_rgba8().unwrap().pixels_mut().for_each(|p| *p = c); } fn vips_flip_horizontal(img: &libvips::VipsImage) -> libvips::VipsImage { return libvips::ops::flip(&img, libvips::ops::Direction::Horizontal).unwrap(); } fn imagers_resize_nearest(img: &mut image::DynamicImage, width: usize, height: usize) { img.resize(width as u32, height as u32, image::imageops::FilterType::Nearest); } fn imagescript_drop_shadow(fb: &mut fb, x: isize, y: isize, sigma: f32, color: imagescript::colors::rgba) { imagescript::ops::filter::drop_shadow(fb, x, y, sigma, Some(color)); } fn vips_crop(img: &libvips::VipsImage, x: i32, y: i32, width: usize, height: usize) -> libvips::VipsImage { return libvips::ops::embed(&img, x, y, width as _, height as _).unwrap(); } fn vips_resize_nearest(img: &libvips::VipsImage, width: usize, height: usize) -> libvips::VipsImage { return libvips::ops::resize_with_opts(&img, width as f64 / img.get_width() as f64, &libvips::ops::ResizeOptions { kernel: libvips::ops::Kernel::Nearest, vscale: height as f64 / img.get_height() as f64 }).unwrap(); } fn bench(c: &mut Criterion) { let milk = read("tests/images/milk.png"); let vips = libvips::VipsApp::new("testing", false).unwrap(); let fb2 = imagescript::framebuffer::from(milk.width, milk.height, milk.buffer.as_ptr() as *mut u8).clone(); let mut fb = imagescript::framebuffer::from(milk.width, milk.height, milk.buffer.as_ptr() as *mut u8).clone(); let image2 = image::DynamicImage::ImageRgba8(image::RgbaImage::from_vec(fb.width as u32, fb.height as u32, fb.as_slice().to_owned()).unwrap()); let mut image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_vec(fb.width as u32, fb.height as u32, fb.as_slice().to_owned()).unwrap()); vips.concurrency_set(1); let vip = libvips::VipsImage::new_from_file("tests/images/milk.png").unwrap().image_decode().unwrap(); c.benchmark_group("quant::quantize") .bench_function("imagescript", |b| b.iter(|| imagescript::quant::quantize(&mut fb, &imagescript::quant::options { fast: true, ..Default::default() }))) .bench_function("image-rs", |b| b.iter(|| { let q = color_quant::NeuQuant::new(1, 256, &fb); let v: Vec<_> = (&fb).chunks_exact(4).map(|pix| q.index_of(pix) as u8).collect(); return (q.color_map_rgb(), v); })); c.benchmark_group("ops::fill") .bench_function("image-rs::color", |b| b.iter(|| imagers_fill(&mut image))) .bench_function("imagescript::color", |b| b.iter(|| imagescript_fill(&mut fb))); c.benchmark_group("ops::crop") .bench_function("image-rs::box(128x128, 512x512)", |b| b.iter(|| imagers_crop(&mut image, 128, 128, 512, 512))) .bench_function("imagescript::box(128x128, 512x512)", |b| b.iter(|| imagescript_crop(&mut fb, 128, 128, 512, 512))) .bench_function("libvips::box(128x128, 512x512)", |b| b.iter(|| vips_crop(&vip, 128, 128, 512, 512).image_write_to_memory())); c.benchmark_group("ops::blur") .measurement_time(std::time::Duration::from_secs(10)) .bench_function("image-rs::gaussian(2)", |b| b.iter(|| imagers_blur_gaussian(&mut image, 2.0))) .bench_function("imagescript::gaussian(2)", |b| b.iter(|| imagescript_blur_gaussian(&mut fb, 2.0))) .bench_function("libvips::gaussian(2)", |b| b.iter(|| vips_gaussian(&vip, 2.0).image_write_to_memory())); c.benchmark_group("ops::overlay") .measurement_time(std::time::Duration::from_secs(10)) .bench_function("image-rs::blend", |b| b.iter(|| imagers_overlay(&mut image, &image2))) .bench_function("imagescript::blend", |b| b.iter(|| imagescript_overlay(&mut fb, &fb2))) .bench_function("image-rs::replace", |b| b.iter(|| imagers_replace(&mut image, &image2))) .bench_function("imagescript::replace", |b| b.iter(|| imagescript_replace(&mut fb, &fb2))); c.benchmark_group("init") .bench_function("image-rs::new()", |b| b.iter(|| imagers_init(milk.width, milk.height))) .bench_function("imagescript::new()", |b| b.iter(|| imagescript_init(milk.width, milk.height))) .bench_function("imagescript::new_fast()", |b| b.iter(|| imagescript_init2(milk.width, milk.height))) .bench_function("libvips::new()", |b| b.iter(|| libvips::VipsImage::image_new_matrix(milk.width as _, milk.height as _).unwrap())); c.benchmark_group("ops::resize") .measurement_time(std::time::Duration::from_secs(10)) .bench_function("image-rs::nearest(256x256)", |b| b.iter(|| imagers_resize_nearest(&mut image, 256, 256))) .bench_function("image-rs::nearest(1024x1024)", |b| b.iter(|| imagers_resize_nearest(&mut image, 1024, 1024))) .bench_function("imagescript::nearest(256x256)", |b| b.iter(|| imagescript_resize_nearest(&mut fb, 256, 256))) .bench_function("imagescript::nearest(1024x1024)", |b| b.iter(|| imagescript_resize_nearest(&mut fb, 1024, 1024))) .bench_function("libvips::nearest(256x256)", |b| b.iter(|| vips_resize_nearest(&vip, 256, 256).image_write_to_memory())) .bench_function("libvips::nearest(1024x1024)", |b| b.iter(|| vips_resize_nearest(&vip, 1024, 1024).image_write_to_memory())); c.benchmark_group("ops::rotate") .measurement_time(std::time::Duration::from_secs(10)) .bench_function("image-rs::rotate(90)", |b| b.iter(|| imagers_rotate90(&mut image))) .bench_function("image-rs::rotate(180)", |b| b.iter(|| imagers_rotate180(&mut image))) .bench_function("image-rs::rotate(270)", |b| b.iter(|| imagers_rotate270(&mut image))) .bench_function("imagescript::rotate(90)", |b| b.iter(|| imagescript_rotate90(&mut fb))) .bench_function("imagescript::rotate(180)", |b| b.iter(|| imagescript_rotate180(&mut fb))) .bench_function("imagescript::rotate(270)", |b| b.iter(|| imagescript_rotate270(&mut fb))) .bench_function("libvips::rotate(90)", |b| b.iter(|| vips_rotate90(&vip).image_write_to_memory())) .bench_function("libvips::rotate(180)", |b| b.iter(|| vips_rotate180(&vip).image_write_to_memory())) .bench_function("libvips::rotate(270)", |b| b.iter(|| vips_rotate270(&vip).image_write_to_memory())); c.benchmark_group("ops::flip") .measurement_time(std::time::Duration::from_secs(10)) .bench_function("image-rs::flip_vertical", |b| b.iter(|| imagers_flip_vertical(&mut image))) .bench_function("image-rs::flip_horizontal", |b| b.iter(|| imagers_flip_horizontal(&mut image))) .bench_function("imagescript::flip_vertical", |b| b.iter(|| imagescript_flip_vertical(&mut fb))) .bench_function("imagescript::flip_horizontal", |b| b.iter(|| imagescript_flip_horizontal(&mut fb))) .bench_function("libvips::flip_vertical", |b| b.iter(|| vips_flip_vertical(&vip).image_write_to_memory())) .bench_function("libvips::flip_horizontal", |b| b.iter(|| vips_flip_horizontal(&vip).image_write_to_memory())); c.benchmark_group("ops::filter") .bench_function("image-rs::invert", |b| b.iter(|| imagers_invert(&mut image))) .bench_function("image-rs::grayscale", |b| b.iter(|| imagers_grayscale(&mut image))) .bench_function("imagescript::sepia", |b| b.iter(|| imagescript_sepia(&mut fb, 1.0))) .bench_function("image-rs::contrast", |b| b.iter(|| imagers_contrast(&mut image, 1.0))) .bench_function("imagescript::opacity", |b| b.iter(|| imagescript_opacity(&mut fb, 1.0))) .bench_function("image-rs::brightness", |b| b.iter(|| imagers_brightness(&mut image, 1))) .bench_function("image-rs::hue_rotate", |b| b.iter(|| imagers_huerotate(&mut image, 180))) .bench_function("imagescript::saturate", |b| b.iter(|| imagescript_saturate(&mut fb, 1.0))) .bench_function("imagescript::contrast", |b| b.iter(|| imagescript_contrast(&mut fb, 1.0))) .bench_function("imagescript::invert(50%)", |b| b.iter(|| imagescript_invert(&mut fb, 0.5))) .bench_function("imagescript::invert(100%)", |b| b.iter(|| imagescript_invert(&mut fb, 1.0))) .bench_function("imagescript::grayscale", |b| b.iter(|| imagescript_grayscale(&mut fb, 1.0))) .bench_function("imagescript::brightness", |b| b.iter(|| imagescript_brightness(&mut fb, 1.0))) .bench_function("imagescript::hue_rotate", |b| b.iter(|| imagescript_huerotate(&mut fb, 180.0))) .bench_function("libvips::invert", |b| b.iter(|| libvips::ops::invert(&vip).unwrap().image_write_to_memory())) .bench_function("imagescript::drop_shadow", |b| b.iter(|| imagescript_drop_shadow(&mut fb, 0, 0, 5.0, imagescript::colors::rgba { r: 255, g: 0, b: 0, a: 255 }))); } criterion_group!(benches, bench); criterion_main!(benches);