mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
feat: Optimize avatar size multiplier for 2 << n px avatars
Instead of 2/3 which is not optimal for 512 px avatars usually passed to Core, use the sequence 3/4, 5/8, 4/8, 3/8... to do "smaller" downscaling steps and reduce aliasing effects. Before, it was discussed that just 3/4 can be used. However, if we repeat the reduction step, we get `3 << n` as a numerator and this way increase aliasing effects on each step. Better limit the numerator to 5.
This commit is contained in:
@@ -435,6 +435,8 @@ impl<'a> BlobObject<'a> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if do_scale {
|
if do_scale {
|
||||||
|
let (mut m, mut d) = (3, 4);
|
||||||
|
let wh = target_wh;
|
||||||
loop {
|
loop {
|
||||||
if mem::take(&mut add_white_bg) {
|
if mem::take(&mut add_white_bg) {
|
||||||
self::add_white_bg(&mut img);
|
self::add_white_bg(&mut img);
|
||||||
@@ -467,8 +469,11 @@ impl<'a> BlobObject<'a> {
|
|||||||
"Failed to scale image to below {max_bytes}B.",
|
"Failed to scale image to below {max_bytes}B.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
target_wh = wh * m / d;
|
||||||
target_wh = target_wh * 2 / 3;
|
(m, d) = match m > 3 {
|
||||||
|
true => (m - 1, d),
|
||||||
|
false => (5, d * 2),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ use super::*;
|
|||||||
use crate::message::{Message, Viewtype};
|
use crate::message::{Message, Viewtype};
|
||||||
use crate::param::Param;
|
use crate::param::Param;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::test_utils::{self, AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, TestContext};
|
use crate::test_utils::{
|
||||||
|
self, AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, TestContext, TestContextManager,
|
||||||
|
};
|
||||||
use crate::tools::SystemTime;
|
use crate::tools::SystemTime;
|
||||||
|
|
||||||
fn check_image_size(path: impl AsRef<Path>, width: u32, height: u32) -> image::DynamicImage {
|
fn check_image_size(path: impl AsRef<Path>, width: u32, height: u32) -> image::DynamicImage {
|
||||||
@@ -239,6 +241,22 @@ async fn test_selfavatar_in_blobdir() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_huge_selfavatar() -> Result<()> {
|
||||||
|
let mut tcm = TestContextManager::new();
|
||||||
|
let t = &tcm.unconfigured().await;
|
||||||
|
let avatar_src = t.get_blobdir().join("avatar.png");
|
||||||
|
let bytes = include_bytes!("../../test-data/image/noise400x400.png");
|
||||||
|
|
||||||
|
fs::write(&avatar_src, bytes).await?;
|
||||||
|
t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap()))
|
||||||
|
.await?;
|
||||||
|
let avatar_cfg = t.get_config(Config::Selfavatar).await?.unwrap();
|
||||||
|
// At 3/4 the avatar is still huge, so it's downscaled to 5/8.
|
||||||
|
check_image_size(avatar_cfg, 250, 250);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_selfavatar_copy_without_recode() {
|
async fn test_selfavatar_copy_without_recode() {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
|
|||||||
BIN
test-data/image/noise400x400.png
Normal file
BIN
test-data/image/noise400x400.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 470 KiB |
Reference in New Issue
Block a user