use std::io::Cursor; use image::{io::Reader, DynamicImage, ImageResult, ImageFormat}; use webp::{Encoder, WebPMemory}; use crate::protobuf::image::Format; pub fn thumbnail(bytes: &[u8]) -> ImageResult<(Option, WebPMemory, String, Format)> { let original_image_encoded = Reader::new(Cursor::new(bytes)) .with_guessed_format().expect("IO errors impossible with Cursor"); let original_format = original_image_encoded.format(); let original_image = original_image_encoded.decode()?; let new_dimm = u32::min(original_image.height(), original_image.width()); let crop_x = (original_image.width() - new_dimm) / 2; let crop_y = (original_image.height() - new_dimm) / 2; let cropped = original_image.crop_imm(crop_x, crop_y, new_dimm, new_dimm); let scaled = if new_dimm < 400 { cropped } else { original_image.thumbnail_exact(400, 400) }.into_rgba8(); let scale = scaled.width(); let blurhash = blurhash::encode(4, 4, scale, scale, scaled.as_raw()); let (recoded_original, format) = match original_format { Some(ImageFormat::WebP) => (None, Format::WEBP), Some(ImageFormat::Avif) => (None, Format::AVIF), Some(ImageFormat::Jpeg) => (None, Format::JPG), Some(ImageFormat::Png) => (None, Format::PNG), Some(ImageFormat::Gif) => (None, Format::GIF), _ => ( // Unrecognized or format which isn't spec-supported Some( Encoder::from_image(&original_image) .expect("Error transcoding image as webp") .encode_lossless(), ), Format::WEBP ) }; Ok(( recoded_original, Encoder::from_image(&DynamicImage::ImageRgba8(scaled)) .expect("Unexpected difficulty interpretting thumbnail") .encode(50.0), blurhash, format, )) }