Skip to content

Commit 7c5bc44

Browse files
committed
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.
1 parent c0e7841 commit 7c5bc44

4 files changed

Lines changed: 35 additions & 14 deletions

File tree

src/blob.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use futures::StreamExt;
1212
use image::ImageReader;
1313
use image::codecs::jpeg::JpegEncoder;
1414
use image::{DynamicImage, GenericImage, GenericImageView, ImageFormat, Pixel, Rgba};
15-
use num_traits::FromPrimitive;
15+
use num_traits::{FromPrimitive, cast};
1616
use tokio::{fs, task};
1717
use tokio_stream::wrappers::ReadDirStream;
1818

@@ -429,12 +429,33 @@ impl<'a> BlobObject<'a> {
429429
});
430430

431431
if do_scale {
432+
let n_px_longest_side = max(img.width(), img.height());
433+
432434
// target_wh will be used as the target-resolution for resizing the image,
433435
// so that the longest sides of the image match the target-resolution.
434-
let mut target_wh = if exceeds_wh {
435-
max_wh
436+
let mut target_wh = if !is_avatar {
437+
let n_all_px_sqrt = f64::from(img.width() * img.height()).sqrt();
438+
// Limit resolution to the number of pixels that fit within max_wh * max_wh,
439+
// so that the image-quality does not depend on the aspect-ratio.
440+
let limit: Option<u32> = cast(
441+
(f64::from(n_px_longest_side) * (f64::from(max_wh) / n_all_px_sqrt))
442+
.floor(),
443+
);
444+
let mut resolution_limit = limit.context("resolution_limit is out of range")?;
445+
// Align at least one dimension of the resampled image to a multiple of 8 pixels,
446+
// to have fewer partially used JPEG-blocks (which represent 8x8 pixels each).
447+
if resolution_limit != n_px_longest_side {
448+
while !resolution_limit.is_multiple_of(8) {
449+
resolution_limit -= 1
450+
}
451+
}
452+
resolution_limit
436453
} else {
437-
max(img.width(), img.height())
454+
max_wh
455+
};
456+
457+
if target_wh > n_px_longest_side {
458+
target_wh = n_px_longest_side;
438459
};
439460

440461
loop {

src/blob/blob_tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ async fn test_recode_image_balanced_png() {
384384
extension: "png",
385385
original_width: 1920,
386386
original_height: 1080,
387-
compressed_width: constants::WORSE_IMAGE_SIZE,
388-
compressed_height: constants::WORSE_IMAGE_SIZE * 1080 / 1920,
387+
compressed_width: 848,
388+
compressed_height: 477,
389389
..Default::default()
390390
}
391391
.test()
@@ -475,8 +475,8 @@ async fn test_recode_image_rgba_png_to_jpeg() {
475475
extension: "png",
476476
original_width: 1920,
477477
original_height: 1080,
478-
compressed_width: constants::WORSE_IMAGE_SIZE,
479-
compressed_height: constants::WORSE_IMAGE_SIZE * 1080 / 1920,
478+
compressed_width: 848,
479+
compressed_height: 477,
480480
..Default::default()
481481
}
482482
.test()
@@ -495,8 +495,8 @@ async fn test_recode_image_huge_jpg() {
495495
has_exif: true,
496496
original_width: 1920,
497497
original_height: 1080,
498-
compressed_width: constants::BALANCED_IMAGE_SIZE,
499-
compressed_height: constants::BALANCED_IMAGE_SIZE * 1080 / 1920,
498+
compressed_width: 1704,
499+
compressed_height: 959,
500500
..Default::default()
501501
}
502502
.test()

src/tests/pre_messages/additional_text.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ async fn test_additional_text_on_different_viewtypes() -> Result<()> {
3434
let (pre_message, _, _) = send_large_image_message(alice, a_group_id).await?;
3535
let msg = bob.recv_msg(&pre_message).await;
3636
assert_eq!(msg.text, "test".to_owned());
37-
assert_eq!(msg.get_text(), "test [Image – 146.12 KiB]".to_owned());
37+
assert_eq!(msg.get_text(), "test [Image – 228.45 KiB]".to_owned());
3838

3939
Ok(())
4040
}

src/tests/pre_messages/receiving.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ async fn test_receive_pre_message_image() -> Result<()> {
323323
// test that metadata is correctly returned by methods
324324
assert_eq!(msg.get_post_message_viewtype(), Some(Viewtype::Image));
325325
// recoded image dimensions
326-
assert_eq!(msg.get_filebytes(bob).await?, Some(149632));
327-
assert_eq!(msg.get_height(), 1280);
328-
assert_eq!(msg.get_width(), 720);
326+
assert_eq!(msg.get_filebytes(bob).await?, Some(233935));
327+
assert_eq!(msg.get_height(), 1704);
328+
assert_eq!(msg.get_width(), 959);
329329

330330
Ok(())
331331
}

0 commit comments

Comments
 (0)