upend/cli/src/previews/image.rs

72 lines
2.5 KiB
Rust

#[cfg(not(feature = "previews-image"))]
use anyhow::anyhow;
#[cfg(feature = "previews-image")]
use image::{io::Reader as ImageReader, GenericImageView};
use std::{cmp, collections::HashMap, path::Path};
use anyhow::Result;
use super::Previewable;
pub struct ImagePath<'a>(pub &'a Path);
impl<'a> Previewable for ImagePath<'a> {
fn get_thumbnail(&self, options: HashMap<String, String>) -> Result<Option<Vec<u8>>> {
#[cfg(feature = "previews-image")]
{
let file = std::fs::File::open(self.0)?;
let mut bufreader = std::io::BufReader::new(&file);
let exifreader = exif::Reader::new();
let orientation = exifreader
.read_from_container(&mut bufreader)
.ok()
.and_then(|exif| {
exif.get_field(exif::Tag::Orientation, exif::In::PRIMARY)
.and_then(|f| match &f.value {
exif::Value::Short(shorts) => Some(shorts.clone()),
_ => None,
})
})
.and_then(|shorts| shorts.first().cloned());
let image = ImageReader::open(self.0)?.with_guessed_format()?.decode()?;
let image = match orientation {
Some(3) => image.rotate180(),
Some(6) => image.rotate90(),
Some(8) => image.rotate270(),
_ => image,
};
let (w, h) = image.dimensions();
let max_dimension = {
if let Some(str_size) = options.get("size") {
str_size.parse()?
} else {
1024
}
};
let quality = {
if let Some(str_quality) = options.get("quality") {
str_quality.parse()?
} else {
90.0
}
};
if cmp::max(w, h) > max_dimension {
let thumbnail = image.thumbnail(max_dimension, max_dimension);
let thumbnail = thumbnail.into_rgba8();
let (w, h) = thumbnail.dimensions();
let encoder = webp::Encoder::from_rgba(&thumbnail, w, h);
let result = encoder.encode(quality);
Ok(Some(result.to_vec()))
} else {
Ok(None)
}
}
#[cfg(not(feature = "previews-image"))]
Err(anyhow!("Image preview support not enabled!"))
}
}