#![allow(unused)] use std::any::Any; use std::fs::{File, read}; use std::io::{BufReader, Cursor}; use std::iter; use std::ops::Deref; use std::path::PathBuf; use std::time::Duration; use criterion::{AxisScale, BenchmarkId, PlotConfiguration}; use criterion::{Criterion, black_box, criterion_group, criterion_main}; use image::codecs::jpeg::JpegDecoder; use image::metadata::Orientation; use image::{DynamicImage, ImageResult, RgbaImage}; use imflow::image::{ ImflowImageBuffer, get_orientation, get_rating, image_to_rgba_buffer, load_available_images, load_image, load_thumbnail_exif, load_thumbnail_full, }; use zune_image::codecs::jpeg::JpegDecoder as ZuneJpegDecoder; use zune_image::codecs::qoi::zune_core::colorspace::ColorSpace; use zune_image::codecs::qoi::zune_core::options::DecoderOptions; const PATH: &str = "test_images"; /// Create a new decoder that decodes from the stream ```r``` // pub fn new(r: R) -> ImageResult> { // let mut input = Vec::new(); // let mut r = r; // r.read_to_end(&mut input)?; // let options = DecoderOptions::default() // .set_strict_mode(false) // .set_max_width(usize::MAX) // .set_max_height(usize::MAX); // let mut decoder = ZuneJpegDecoder::new_with_options(input.as_slice(), options); // decoder.decode_headers().map_err(ImageError::from_jpeg)?; // // now that we've decoded the headers we can `.unwrap()` // // all these functions that only fail if called before decoding the headers // let (width, height) = decoder.dimensions().unwrap(); // // JPEG can only express dimensions up to 65535x65535, so this conversion cannot fail // let width: u16 = width.try_into().unwrap(); // let height: u16 = height.try_into().unwrap(); // let orig_color_space = decoder.get_output_colorspace().unwrap(); // // Limits are disabled by default in the constructor for all decoders // let limits = Limits::no_limits(); // Ok(JpegDecoder { // input, // orig_color_space, // width, // height, // limits, // orientation: None, // phantom: PhantomData, // }) // } // pub fn full_load_benchmark(c: &mut Criterion) { // let mut group = c.benchmark_group("image_decode"); // group // .sample_size(10) // .measurement_time(Duration::from_millis(500)) // .warm_up_time(Duration::from_millis(200)); // let images = load_available_images(PATH.into()); // for image in images.iter() { // let image_name = image.to_str().unwrap(); // group.bench_with_input(format!("{}/zune", image_name), image, |b, image| { // b.iter(|| load_image_argb(image.clone().into())); // }); // group.bench_with_input(format!("{}/image-rs", image_name), image, |b, image| { // b.iter(|| load_image_argb_imagers(image.clone().into())); // }); // } // group.finish(); // } fn load_a(path: &PathBuf) -> ImflowImageBuffer { let file = read(path.clone()).unwrap(); let mut decoder = ZuneJpegDecoder::new(&file); let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::RGBA); decoder.set_options(options); decoder.decode_headers().unwrap(); let info = decoder.info().unwrap(); let width = info.width as usize; let height = info.height as usize; let mut buffer: Vec = vec![0; width * height * 4]; decoder.decode_into(buffer.as_mut_slice()).unwrap(); // Reinterpret to avoid copying let buffer_u32 = unsafe { Vec::from_raw_parts( buffer.as_mut_ptr() as *mut u32, buffer.len() / 4, buffer.capacity() / 4, ) }; std::mem::forget(buffer); // let total_time = total_start.elapsed(); // println!("Total loading time: {:?}", total_time); let rating = get_rating(path); ImflowImageBuffer { width, height, rgba_buffer: buffer_u32, rating, } } fn load_b(path: &PathBuf) -> ImflowImageBuffer { let file = read(path.clone()).unwrap(); let mut decoder = ZuneJpegDecoder::new(&file); let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::RGBA); decoder.set_options(options); decoder.decode_headers().unwrap(); let info = decoder.info().unwrap(); let width = info.width as usize; let height = info.height as usize; let mut buffer: Vec = vec![0; width * height * 4]; decoder.decode_into(buffer.as_mut_slice()).unwrap(); let image = RgbaImage::from_raw(width as u32, height as u32, buffer).unwrap(); let orientation = Orientation::from_exif(get_orientation(path)).unwrap(); let mut dynamic_image = DynamicImage::from(image); dynamic_image.apply_orientation(orientation); let rating = get_rating(path); let mut buffer = dynamic_image.to_rgba8(); let buffer_u32 = unsafe { Vec::from_raw_parts( buffer.as_mut_ptr() as *mut u32, buffer.len() / 4, buffer.len() / 4, ) }; std::mem::forget(buffer); ImflowImageBuffer { width, height, rgba_buffer: buffer_u32, rating, } } // fn load_b(path: &PathBuf) -> ImflowImageBuffer { // println!("path: {:?}", path); // // let file = read(path.clone()).unwrap(); // let file = BufReader::new(File::open(path).unwrap()); // let decoder = image::ImageReader::new(file).unwrap(); // let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::RGBA); // decoder.set_options(options); // let image = reader // .with_guessed_format() // .unwrap() // .decode() // .unwrap(); // let width = image.width() as usize; // let height = image.height() as usize; // // let buffer = image_to_rgba_buffer(image); // let im = RgbaImage::from_raw(width, height, image.as_rgba8()).unwrap(); // let rating = get_rating(path.into()); // ImflowImageBuffer { // width, // height, // rgba_buffer: buffer, // rating, // } // } pub fn thumbnail_load_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("thumbnail"); group .sample_size(10) .measurement_time(Duration::from_millis(500)) .warm_up_time(Duration::from_millis(200)); let images = load_available_images(PATH.into()); group.bench_function("exif", |b| { for image in images.iter().take(10) { b.iter(|| load_thumbnail_exif(image)); } }); group.bench_function("full", |b| { for image in images.iter().take(10) { b.iter(|| load_thumbnail_full(image)); } }); group.finish(); } pub fn file_load_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("image_load"); group .sample_size(10) .measurement_time(Duration::from_millis(500)) .warm_up_time(Duration::from_millis(200)); let images = load_available_images(PATH.into()); group.bench_function("zune_jpeg", |b| { for image in images.iter().take(10) { b.iter(|| load_a(image)); } }); group.bench_function("image_rs", |b| { for image in images.iter().take(10) { b.iter(|| load_b(image)); } }); group.finish(); } // criterion_group!(benches, thumbnail_load_benchmark); criterion_group!(benches, file_load_benchmark); criterion_main!(benches);