Skip to content

Commit 11a8cd0

Browse files
committed
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.
1 parent af16fc9 commit 11a8cd0

3 files changed

Lines changed: 26 additions & 3 deletions

File tree

src/blob.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ impl<'a> BlobObject<'a> {
435435
});
436436

437437
if do_scale {
438+
let (mut m, mut d) = (3, 4);
439+
let wh = target_wh;
438440
loop {
439441
if mem::take(&mut add_white_bg) {
440442
self::add_white_bg(&mut img);
@@ -467,8 +469,11 @@ impl<'a> BlobObject<'a> {
467469
"Failed to scale image to below {max_bytes}B.",
468470
));
469471
}
470-
471-
target_wh = target_wh * 2 / 3;
472+
target_wh = wh * m / d;
473+
(m, d) = match m > 3 {
474+
true => (m - 1, d),
475+
false => (5, d * 2),
476+
};
472477
} else {
473478
info!(
474479
context,

src/blob/blob_tests.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use super::*;
44
use crate::message::{Message, Viewtype};
55
use crate::param::Param;
66
use crate::sql;
7-
use crate::test_utils::{self, AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, TestContext};
7+
use crate::test_utils::{
8+
self, AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, TestContext, TestContextManager,
9+
};
810
use crate::tools::SystemTime;
911

1012
fn check_image_size(path: impl AsRef<Path>, width: u32, height: u32) -> image::DynamicImage {
@@ -239,6 +241,22 @@ async fn test_selfavatar_in_blobdir() {
239241
);
240242
}
241243

244+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
245+
async fn test_huge_selfavatar() -> Result<()> {
246+
let mut tcm = TestContextManager::new();
247+
let t = &tcm.unconfigured().await;
248+
let avatar_src = t.get_blobdir().join("avatar.png");
249+
let bytes = include_bytes!("../../test-data/image/noise400x400.png");
250+
251+
fs::write(&avatar_src, bytes).await?;
252+
t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap()))
253+
.await?;
254+
let avatar_cfg = t.get_config(Config::Selfavatar).await?.unwrap();
255+
// At 3/4 the avatar is still huge, so it's downscaled to 5/8.
256+
check_image_size(avatar_cfg, 250, 250);
257+
Ok(())
258+
}
259+
242260
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
243261
async fn test_selfavatar_copy_without_recode() {
244262
let t = TestContext::new().await;

test-data/image/noise400x400.png

470 KB
Loading

0 commit comments

Comments
 (0)