Use non-filling resize on server side. Client does filling.
This commit is contained in:
parent
792471bf00
commit
7ec3a11037
@ -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
|
||||||
|
|||||||
@ -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) => {
|
||||||
|
|||||||
@ -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())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user