aviary-cli/src/thumbnailing.rs

51 lines
1.7 KiB
Rust

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>, 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,
))
}