feat: Make quality of images sent in chats more consistent

Currently, the resolution of a resized image that was sent in a chat,
depends on the aspect-ratio.

Assuming the `balanced`-quality-setting is used,
a square image, that is larger than the limits for resolution and file-size,
will be resized to 1280x1280 (1,638,400 pixels),
an image with an aspect-ratio of 16:9,
will be resized to 1280x720 (921,600 pixels),
and if the aspect-ratio is 32:9, to 1280x360 (460,800 pixels).

This change makes it so, that the number of pixels,
in images with different aspect-ratios, will be similar.
This commit is contained in:
72374
2026-02-04 03:07:28 +01:00
committed by iequidoo
parent 456891a0af
commit 89a281dd27
4 changed files with 29 additions and 13 deletions

View File

@@ -430,12 +430,28 @@ impl<'a> BlobObject<'a> {
});
if do_scale {
let n_px_longest_side = max(img.width(), img.height());
// target_wh will be used as the target-resolution for resizing the image,
// so that the longest sides of the image match the target-resolution.
let mut target_wh = if exceeds_wh {
max_wh
let mut target_wh = if !is_avatar {
let n_all_px_sqrt = f64::from(img.width() * img.height()).sqrt();
// Limit resolution to the number of pixels that fit within max_wh * max_wh,
// so that the image-quality does not depend on the aspect-ratio.
let mut resolution_limit =
(f64::from(n_px_longest_side) * (f64::from(max_wh) / n_all_px_sqrt)) as u32;
// Align (at least) two sides of the resampled image to a multiple of 8 pixels,
// to have fewer partially used JPEG-blocks (which represent 8x8 pixels each).
while !resolution_limit.is_multiple_of(8) {
resolution_limit -= 1
}
resolution_limit
} else {
max(img.width(), img.height())
max_wh
};
if target_wh > n_px_longest_side {
target_wh = n_px_longest_side;
};
loop {

View File

@@ -384,8 +384,8 @@ async fn test_recode_image_balanced_png() {
extension: "png",
original_width: 1920,
original_height: 1080,
compressed_width: constants::WORSE_IMAGE_SIZE,
compressed_height: constants::WORSE_IMAGE_SIZE * 1080 / 1920,
compressed_width: 848,
compressed_height: 477,
..Default::default()
}
.test()
@@ -475,8 +475,8 @@ async fn test_recode_image_rgba_png_to_jpeg() {
extension: "png",
original_width: 1920,
original_height: 1080,
compressed_width: constants::WORSE_IMAGE_SIZE,
compressed_height: constants::WORSE_IMAGE_SIZE * 1080 / 1920,
compressed_width: 848,
compressed_height: 477,
..Default::default()
}
.test()
@@ -495,8 +495,8 @@ async fn test_recode_image_huge_jpg() {
has_exif: true,
original_width: 1920,
original_height: 1080,
compressed_width: constants::BALANCED_IMAGE_SIZE,
compressed_height: constants::BALANCED_IMAGE_SIZE * 1080 / 1920,
compressed_width: 1704,
compressed_height: 959,
..Default::default()
}
.test()

View File

@@ -34,7 +34,7 @@ async fn test_additional_text_on_different_viewtypes() -> Result<()> {
let (pre_message, _, _) = send_large_image_message(alice, a_group_id).await?;
let msg = bob.recv_msg(&pre_message).await;
assert_eq!(msg.text, "test".to_owned());
assert_eq!(msg.get_text(), "test [Image 146.12 KiB]".to_owned());
assert_eq!(msg.get_text(), "test [Image 228.45 KiB]".to_owned());
Ok(())
}

View File

@@ -393,9 +393,9 @@ async fn test_receive_pre_message_image() -> Result<()> {
// test that metadata is correctly returned by methods
assert_eq!(msg.get_post_message_viewtype(), Some(Viewtype::Image));
// recoded image dimensions
assert_eq!(msg.get_filebytes(bob).await?, Some(149632));
assert_eq!(msg.get_height(), 1280);
assert_eq!(msg.get_width(), 720);
assert_eq!(msg.get_filebytes(bob).await?, Some(233935));
assert_eq!(msg.get_height(), 1704);
assert_eq!(msg.get_width(), 959);
Ok(())
}