Refactor thumbnail generation.

This commit is contained in:
Bill Thiede 2020-02-17 17:50:43 -08:00
parent 43974b7406
commit d74a8117d7
2 changed files with 40 additions and 36 deletions

View File

@ -6,6 +6,8 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use google_photoslibrary1 as photos; use google_photoslibrary1 as photos;
use image::imageops::FilterType;
use image::ImageFormat;
use log::error; use log::error;
use log::info; use log::info;
use log::warn; use log::warn;
@ -16,7 +18,7 @@ use rocksdb::IteratorMode;
use rocksdb::DB; use rocksdb::DB;
// Used to ensure DB is invalidated after schema changes. // Used to ensure DB is invalidated after schema changes.
const LIBRARY_GENERATION: &'static str = "2"; const LIBRARY_GENERATION: &'static str = "5";
#[derive(Clone)] #[derive(Clone)]
pub struct Library { pub struct Library {
@ -143,36 +145,35 @@ impl Library {
fn generational_key(generation: &str, key: &str) -> String { fn generational_key(generation: &str, key: &str) -> String {
format!("{}/{}", generation, key) format!("{}/{}", generation, key)
} }
pub fn thumbnail(&self, media_items_id: &str, dimensions: (u32, u32)) -> Option<Vec<u8>> { pub fn generate_thumbnail(
fn generate_thumbnail( &self,
lib: &Library, media_items_id: &str,
media_items_id: &str, dimensions: (u32, u32),
dimensions: (u32, u32), filter: FilterType,
) -> Result<Vec<u8>, io::Error> { ) -> Result<Vec<u8>, io::Error> {
let (w, h) = dimensions; let (w, h) = dimensions;
match lib.original(&media_items_id) { match self.original(&media_items_id) {
None => { None => {
warn!("Couldn't find original {}", &media_items_id); warn!("Couldn't find original {}", &media_items_id);
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::NotFound, io::ErrorKind::NotFound,
format!("{}", media_items_id), format!("{}", media_items_id),
)) ))
} }
Some(path) => { Some(path) => {
let orig_img = image::io::Reader::open(&path)? let orig_img = image::io::Reader::open(&path)?
.with_guessed_format()? .with_guessed_format()?
.decode() .decode()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
// TODO (wathiede) resize..fill let img = orig_img.resize_to_fill(w, h, filter);
let img = let mut buf = Vec::new();
orig_img.resize_to_fill(w, h, image::imageops::FilterType::CatmullRom); img.write_to(&mut buf, ImageFormat::Jpeg)
let mut buf = Vec::new(); .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
img.write_to(&mut buf, image::ImageFormat::Jpeg) Ok(buf)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(buf)
}
} }
} }
}
pub fn thumbnail(&self, media_items_id: &str, dimensions: (u32, u32)) -> Option<Vec<u8>> {
fn cache_key(media_items_id: &str, dimensions: (u32, u32)) -> String { fn cache_key(media_items_id: &str, dimensions: (u32, u32)) -> String {
let (w, h) = dimensions; let (w, h) = dimensions;
Library::generational_key( Library::generational_key(
@ -191,13 +192,15 @@ impl Library {
// Cache miss, fill cache and return. // Cache miss, fill cache and return.
Ok(None) => { Ok(None) => {
info!("cache MISS {}", key); info!("cache MISS {}", key);
let bytes = match generate_thumbnail(self, media_items_id, dimensions) { let bytes =
Ok(bytes) => bytes, match self.generate_thumbnail(media_items_id, dimensions, FilterType::Lanczos3)
Err(e) => { {
error!("Failed to generate thumbnail for {}: {}", media_items_id, e); Ok(bytes) => bytes,
return None; Err(e) => {
} error!("Failed to generate thumbnail for {}: {}", media_items_id, e);
}; return None;
}
};
match db.put(key.as_bytes(), &bytes) { match db.put(key.as_bytes(), &bytes) {
Ok(_) => Some(bytes), Ok(_) => Some(bytes),
Err(e) => { Err(e) => {

View File

@ -80,6 +80,7 @@ fn image(
media_items_id: String, media_items_id: String,
params: ImageParams, params: ImageParams,
) -> Result<impl warp::Reply, warp::Rejection> { ) -> Result<impl warp::Reply, warp::Rejection> {
// TODO(wathiede): add caching headers.
match lib.thumbnail( match lib.thumbnail(
&media_items_id, &media_items_id,
(params.w.unwrap_or(0), params.h.unwrap_or(0)), (params.w.unwrap_or(0), params.h.unwrap_or(0)),