From 368fa9fc44b9f4bdfe21098a4907151ad51480ce Mon Sep 17 00:00:00 2001 From: Hocuri Date: Thu, 10 Jun 2021 18:52:09 +0200 Subject: [PATCH] Test image rotation --- src/blob.rs | 157 +++++++++++++----- .../rectangle2000x1800-rotated.jpg.xml | 7 + .../rectangle200x180-rotated.jpg.xml | 7 + .../image/rectangle2000x1800-rotated.jpg | Bin 0 -> 45773 bytes test-data/image/rectangle200x180-rotated.jpg | Bin 0 -> 2147 bytes 5 files changed, 134 insertions(+), 37 deletions(-) create mode 100644 test-data/image/.comments/rectangle2000x1800-rotated.jpg.xml create mode 100644 test-data/image/.comments/rectangle200x180-rotated.jpg.xml create mode 100644 test-data/image/rectangle2000x1800-rotated.jpg create mode 100644 test-data/image/rectangle200x180-rotated.jpg diff --git a/src/blob.rs b/src/blob.rs index d8c7d56cf..d13a33343 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -622,6 +622,7 @@ mod tests { use super::*; use crate::{message::Message, test_utils::TestContext}; + use image::Pixel; #[async_std::test] async fn test_create() { @@ -921,47 +922,129 @@ mod tests { } #[async_std::test] - async fn test_media_quality() -> anyhow::Result<()> { - for (media_quality_config, image_size) in vec![ - (Some("0"), 1000), // BALANCED_IMAGE_SIZE > 1000, the original image size, so the image is not scaled down - (Some("1"), WORSE_IMAGE_SIZE), - ] - .into_iter() - { - let alice = TestContext::new_alice().await; - let bob = TestContext::new_bob().await; - alice - .set_config(Config::MediaQuality, media_quality_config) - .await?; + async fn test_recode_image() { + let bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg"); + // BALANCED_IMAGE_SIZE > 1000, the original image size, so the image is not scaled down: + send_image_check_mediaquality(Some("0"), bytes, 1000, 1000, 0, 1000, 1000) + .await + .unwrap(); + send_image_check_mediaquality( + Some("1"), + bytes, + 1000, + 1000, + 0, + WORSE_IMAGE_SIZE, + WORSE_IMAGE_SIZE, + ) + .await + .unwrap(); - let file = alice.get_blobdir().join("file.jpg"); - let bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg"); - File::create(&file).await?.write_all(bytes).await?; + let bytes = include_bytes!("../test-data/image/rectangle2000x1800-rotated.jpg"); + let img_rotated = send_image_check_mediaquality( + Some("0"), + bytes, + 2000, + 1800, + 270, + BALANCED_IMAGE_SIZE * 1800 / 2000, + BALANCED_IMAGE_SIZE, + ) + .await + .unwrap(); - let img = image::open(&file)?; - assert_eq!(img.width(), 1000); - assert_eq!(img.height(), 1000); + assert_correct_rotataion(&img_rotated); - let mut msg = Message::new(Viewtype::Image); - msg.set_file(file.to_str().unwrap(), None); - let chat = alice.create_chat(&bob).await; - let sent = alice.send_msg(chat.id, &mut msg).await; + let mut bytes = vec![]; + img_rotated + .write_to(&mut bytes, image::ImageFormat::Jpeg) + .unwrap(); + let img_rotated = send_image_check_mediaquality( + Some("0"), + &bytes, + BALANCED_IMAGE_SIZE * 1800 / 2000, + BALANCED_IMAGE_SIZE, + 0, + BALANCED_IMAGE_SIZE * 1800 / 2000, + BALANCED_IMAGE_SIZE, + ) + .await + .unwrap(); - let alice_msg = alice.get_last_msg().await; - assert_eq!(alice_msg.get_width() as u32, image_size); - assert_eq!(alice_msg.get_height() as u32, image_size); - let img = image::open(alice_msg.get_file(&alice).unwrap())?; - assert_eq!(img.width() as u32, image_size); - assert_eq!(img.height() as u32, image_size); + assert_correct_rotataion(&img_rotated); - bob.recv_msg(&sent).await; - let bob_msg = bob.get_last_msg().await; - assert_eq!(bob_msg.get_width() as u32, image_size); - assert_eq!(bob_msg.get_height() as u32, image_size); - let img = image::open(bob_msg.get_file(&bob).unwrap())?; - assert_eq!(img.width() as u32, image_size); - assert_eq!(img.height() as u32, image_size); - } - Ok(()) + let bytes = include_bytes!("../test-data/image/rectangle200x180-rotated.jpg"); + let img_rotated = send_image_check_mediaquality(Some("0"), bytes, 200, 180, 270, 180, 200) + .await + .unwrap(); + + assert_correct_rotataion(&img_rotated); + } + + fn assert_correct_rotataion(img: &DynamicImage) { + // The test images are black in the bottom left corner after correctly applying + // the EXIF orientation + + let [luma] = img.get_pixel(10, 10).to_luma().0; + assert_eq!(luma, 255); + let [luma] = img.get_pixel(img.width() - 10, 10).to_luma().0; + assert_eq!(luma, 255); + let [luma] = img + .get_pixel(img.width() - 10, img.height() - 10) + .to_luma() + .0; + assert_eq!(luma, 255); + let [luma] = img.get_pixel(10, img.height() - 10).to_luma().0; + assert_eq!(luma, 0); + } + + async fn send_image_check_mediaquality( + media_quality_config: Option<&str>, + bytes: &[u8], + original_width: u32, + original_height: u32, + orientation: i32, + compressed_width: u32, + compressed_height: u32, + ) -> anyhow::Result { + let alice = TestContext::new_alice().await; + let bob = TestContext::new_bob().await; + alice + .set_config(Config::MediaQuality, media_quality_config) + .await?; + let file = alice.get_blobdir().join("file.jpg"); + + File::create(&file).await?.write_all(bytes).await?; + let img = image::open(&file)?; + assert_eq!(img.width(), original_width); + assert_eq!(img.height(), original_height); + + let blob = BlobObject::new_from_path(&alice, &file).await?; + assert_eq!(blob.get_exif_orientation(&alice).unwrap_or(0), orientation); + + let mut msg = Message::new(Viewtype::Image); + msg.set_file(file.to_str().unwrap(), None); + let chat = alice.create_chat(&bob).await; + let sent = alice.send_msg(chat.id, &mut msg).await; + let alice_msg = alice.get_last_msg().await; + assert_eq!(alice_msg.get_width() as u32, compressed_width); + assert_eq!(alice_msg.get_height() as u32, compressed_height); + let img = image::open(alice_msg.get_file(&alice).unwrap())?; + assert_eq!(img.width() as u32, compressed_width); + assert_eq!(img.height() as u32, compressed_height); + + bob.recv_msg(&sent).await; + let bob_msg = bob.get_last_msg().await; + assert_eq!(bob_msg.get_width() as u32, compressed_width); + assert_eq!(bob_msg.get_height() as u32, compressed_height); + let file = bob_msg.get_file(&bob).unwrap(); + + let blob = BlobObject::new_from_path(&bob, &file).await?; + assert_eq!(blob.get_exif_orientation(&bob).unwrap_or(0), 0); + + let img = image::open(file)?; + assert_eq!(img.width() as u32, compressed_width); + assert_eq!(img.height() as u32, compressed_height); + Ok(img) } } diff --git a/test-data/image/.comments/rectangle2000x1800-rotated.jpg.xml b/test-data/image/.comments/rectangle2000x1800-rotated.jpg.xml new file mode 100644 index 000000000..815de21f6 --- /dev/null +++ b/test-data/image/.comments/rectangle2000x1800-rotated.jpg.xml @@ -0,0 +1,7 @@ + + + + Created with GIMP + + + diff --git a/test-data/image/.comments/rectangle200x180-rotated.jpg.xml b/test-data/image/.comments/rectangle200x180-rotated.jpg.xml new file mode 100644 index 000000000..815de21f6 --- /dev/null +++ b/test-data/image/.comments/rectangle200x180-rotated.jpg.xml @@ -0,0 +1,7 @@ + + + + Created with GIMP + + + diff --git a/test-data/image/rectangle2000x1800-rotated.jpg b/test-data/image/rectangle2000x1800-rotated.jpg new file mode 100644 index 0000000000000000000000000000000000000000..286ae36089130c5bb81f7cb638feb69490faa7d6 GIT binary patch literal 45773 zcmeI4eQZ-z7{=dw+pZt$pdH;9M6uIp2(m~(kwkHf$*^RTIvMg6-PV0D!^YT(pb|lX zVuA@UB!bawiU~v{A%egkCVUzaBM})V8EWL1c)9P!0|Tv2*s$Li{yn4VHn$r9<~ z;GcR?8{a0Cuc`b!uaRfrE6>nf^6D!}!xiQJCDq~i{;7e&Ah#K3(Avo}EkBUYEs8Q) z8BL_!pdrFYtwY@z$jf^vSTsF9P%wpi^Y3n65UOdgjv=b44c8Y65Hb{DdiOnA%0JO?lmb?S0CoMgyZo`!gYGQ ziDO@AerY+!pL0CAo^O!jQ@UQ(9beSrsz|JJBwziEqC9?YK92oWed4k{acF*h4flDJ z`(%~Z)bjl5tnRp6kC*9j&4R^zZ;_&ZAnuCV;^+CA#ozbPR0>cb1<6lkw3w=C0fi}> zueGc+P!YFJmW&@B86V_PWjv~yLOkMWT1Yii8W~UeXTW{9MA8^)Qniwo_n%vdQf3nkIZou7+s%#J^mf|vBhd_IRd9@G^9Mu^Rq@>OB=1{a z@V(sP_PNPV`-$?%qN@6fi2{gOZay=^pP8 zUs_t4d+^YVbYDiQFU_YoW7Lg6yI$Z?GSk#c8C4AMe&mARV-dbJ3>Pv z8K-mTEe@xh8+>|h#TKoV+!lpYkHy2wcVld0yqb%?jMpq_tI!v7Vnvyh-key^zP;Sr z`_|&eBh{1fJD9a98%xY&Q_V(mR+u)#702ouN`j?1nRnjXElI^I5+34HUQW1gwBt8B zqwy^wbw&21TXZpL9yZfNlt@9_Hc3ky*)r-toYvSTq(UqYvl>#tj7qGAREXtaR>M=l zjEX_SQ^5elq>8742^50_gJb|=QiVY>fntzgkPJXfsxU|br>X(iBW+; zG7=H%cd0>g&Jb@^ru=5VlYcdn%?2F=KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;{yzln`>yk}q9AF3^ zW@bEKEqT|wa!kJC;N2F6x1Bxw&-7hK^s{BX#-1} zSx8a&$IYTzAN#bUF8qaJN!5?h9h>`H?*dKAQEzl?FZg-G#8EAemwz{H_p#ICPV5-> zO2JFzQgSj|T076~f1~UA)q%MbOG?o7 z*)7U@CtsM5ck$BloJs3#Ij)YA{l1ea;l2n3$l%x_2 zq%4)N$;ik!WoxNFbYKT|83Bn711Wjx!9YrOBy2L0RDyw&q!J9IB$Z$wWvPTsMn=Xd zTTA_+4=ncnxI-Bh=pXDkqK?b0tt*N%8{=|EimsFak~l+E!=(~Hx))Gha~YP*!9o&FDx^1PA& literal 0 HcmV?d00001 diff --git a/test-data/image/rectangle200x180-rotated.jpg b/test-data/image/rectangle200x180-rotated.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e5a1a00316f6f04cac4747680e37af1b8bdd90d GIT binary patch literal 2147 zcmcgsZD?C%6n@@&bCWb5?Y-$u*J^*H(oGi9QFTro!*-2p$!IjBt#od><*RL=NlTJC zVGaX+bkskkL+zZyeMrYPky*!tF?Gy|qautA?B+zPGEh()RfiDQ>v?aRrdr#wKRtPK z&Xe=~o_lVztJ?S2v+22b2jKU^4ZsWo0}O;n;38wQ_*8#<7C*`y5Op6jaZbX}D-cLJ z=(}x*vXJB%bn>QRp-e35+8NJuxte_b0NMVVL7RZQxzX217REfx187qyofoP7Ae{7h zz1su9CmMato5-7LAMB1K(uP_fk<6rmO%1O0El;^jH(-Q?J{714Mbf<+1A*pzL-XaW zucq6*Qp0o2w=b%(M`P&--N{8>^^x9GhVTx;>vm>(IUXjgM!G^#!tWCHq^Lo{SGhhs zjep^|Q^$OcP*bfzFWpTg?CP9@!*g(?E0rLhwd7MBO(ZG5&_0c$96!%-qPvfJ(}_P2 zTP)euLb95^m1u$wegxn`7=4JN8yVD)Op+#zAlVxhh`&pZ4^UK?qT+~9#AE0|0wFyf z{27oBQDL^}jtB17Rm|1^NZ)GO?<)b*Uf}kirsWQ4+U>)D_ziF_S%~jB2t52J=?4qC z>bHTCmw?k33cBzcz=!=n`L*6qDx}xpODc5GdQTn&>|21+OMqqT^xVkC?Km4a zzXbNZ39Ra*+}jqoH(&VKxh?85Ge7M*ybuL}A0h)C$t+0*gJdz8jAom~X0uwXR(r8S zwiheKR;yelE2XN_>9m!sC@)jX9ja61Ntj462B}Drid4JRuHG?e=b@N!3KvDDKv0;d zFzo`$^*4_3LFCC~E|SQi@|Wx1q^tV+gC&9F0U45-FO9L~Lfl0zou#_CwfqAo(gWfe6p7zJj~-vgdTfV8&$ z#l0U~rfpLkRkguT{tCuAA$PYsy!!RA;epub$UXbIkL?-Rx|kvtert_!VD ze?R=$t7RlQ23m(k+2vnd`Q_E$dU?oKy&Q*kX;_XzGuOFyiRF-&UXB?TK5bejet{Wc qN>z5wwB=84T~D0mr|0nl>oY%JIZ9$ze6#Vrmu1iTmVVm8YySY?7Q>MM literal 0 HcmV?d00001