Use non-filling resize on server side. Client does filling.

This commit is contained in:
Bill Thiede 2020-02-23 08:46:20 -08:00
parent 792471bf00
commit 7ec3a11037
3 changed files with 39 additions and 3 deletions

View File

@ -40,3 +40,7 @@ load_image = "2.12.0"
[[bench]] [[bench]]
name = "image" name = "image"
harness = false harness = false
# Build dependencies with release optimizations even in dev mode.
[profile.dev.package."*"]
opt-level = 3

View File

@ -25,7 +25,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 = "13"; const LIBRARY_GENERATION: &'static str = "14";
#[derive(Clone)] #[derive(Clone)]
pub struct Library { pub struct Library {
@ -116,6 +116,25 @@ pub fn resize(
img: &DynamicImage, img: &DynamicImage,
dimensions: (Option<u32>, Option<u32>), dimensions: (Option<u32>, Option<u32>),
filter: FilterType, filter: FilterType,
) -> DynamicImage {
let (w, h) = dimensions;
let (orig_w, orig_h) = img.dimensions();
let (w, h) = match (w, h) {
(Some(w), Some(h)) => (w, h),
(Some(w), None) => (w, orig_h * w / orig_w),
(None, Some(h)) => (orig_w * h / orig_h, h),
(None, None) => (orig_w, orig_h),
};
match filter {
FilterType::Builtin(filter) => img.resize(w, h, filter),
FilterType::Nearest => unimplemented!(), //resize_to_fill_nearest(w, h, img),
}
}
pub fn resize_to_fill(
img: &DynamicImage,
dimensions: (Option<u32>, Option<u32>),
filter: FilterType,
) -> DynamicImage { ) -> DynamicImage {
let (w, h) = dimensions; let (w, h) = dimensions;
let (orig_w, orig_h) = img.dimensions(); let (orig_w, orig_h) = img.dimensions();
@ -261,11 +280,13 @@ 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 generate_thumbnail( pub fn generate_thumbnail(
&self, &self,
media_items_id: &str, media_items_id: &str,
dimensions: (Option<u32>, Option<u32>), dimensions: (Option<u32>, Option<u32>),
filter: FilterType, filter: FilterType,
fill: bool,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> { ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
match self.original(&media_items_id) { match self.original(&media_items_id) {
None => { None => {
@ -275,7 +296,11 @@ impl Library {
Some(path) => { Some(path) => {
let orig_img = load_image(&path, dimensions.0, dimensions.1)?; let orig_img = load_image(&path, dimensions.0, dimensions.1)?;
//.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; //.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let img = resize(&orig_img, dimensions, filter); let img = if fill {
resize_to_fill(&orig_img, dimensions, filter)
} else {
resize(&orig_img, dimensions, filter)
};
let buf = save_to_jpeg_bytes(&img) let buf = save_to_jpeg_bytes(&img)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(buf) Ok(buf)
@ -286,6 +311,7 @@ impl Library {
&self, &self,
media_items_id: &str, media_items_id: &str,
dimensions: (Option<u32>, Option<u32>), dimensions: (Option<u32>, Option<u32>),
fill: bool,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
fn cache_key(media_items_id: &str, dimensions: (Option<u32>, Option<u32>)) -> String { fn cache_key(media_items_id: &str, dimensions: (Option<u32>, Option<u32>)) -> String {
let dim = match dimensions { let dim = match dimensions {
@ -308,6 +334,7 @@ impl Library {
media_items_id, media_items_id,
dimensions, dimensions,
FilterType::Builtin(imageops::FilterType::Lanczos3), FilterType::Builtin(imageops::FilterType::Lanczos3),
fill,
) { ) {
Ok(bytes) => bytes, Ok(bytes) => bytes,
Err(e) => { Err(e) => {

View File

@ -73,6 +73,7 @@ fn album(lib: Library, id: String) -> Result<impl warp::Reply, warp::Rejection>
struct ImageParams { struct ImageParams {
w: Option<u32>, w: Option<u32>,
h: Option<u32>, h: Option<u32>,
fill: Option<bool>,
} }
fn image( fn image(
@ -81,7 +82,11 @@ fn image(
params: ImageParams, params: ImageParams,
) -> Result<impl warp::Reply, warp::Rejection> { ) -> Result<impl warp::Reply, warp::Rejection> {
// TODO(wathiede): add caching headers. // TODO(wathiede): add caching headers.
match lib.thumbnail(&media_items_id, (params.w, params.h)) { match lib.thumbnail(
&media_items_id,
(params.w, params.h),
params.fill.unwrap_or(false),
) {
None => { None => {
warn!("Couldn't find original {}", &media_items_id); warn!("Couldn't find original {}", &media_items_id);
Err(warp::reject::not_found()) Err(warp::reject::not_found())