From a83170e753148d01612f7141455ec20461fbf595 Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Thu, 5 Jan 2023 19:34:22 +0530 Subject: [PATCH] MM-49395: Increase compression for previews and emojis (#21985) We also reduce the max size of uploaded emojis to 512KiB. https://mattermost.atlassian.net/browse/MM-49395 ```release-note Max size of uploaded emojis is now reduced to 512KiB to reduce image download bandwidth. ``` --- app/emoji.go | 7 +++---- app/imaging/encode.go | 4 +++- app/user_test.go | 2 +- app/users/profile_picture.go | 5 ++++- i18n/en.json | 2 +- tests/10000x1_expected_preview.png | Bin 92 -> 92 bytes tests/10000x1_expected_thumb.png | Bin 76 -> 76 bytes tests/1x10000_expected_preview.png | Bin 121 -> 121 bytes tests/1x10000_expected_thumb.png | Bin 79 -> 79 bytes tests/fill_test_16bit_rgb_out.png | Bin 1218 -> 1011 bytes tests/fill_test_16bit_rgba_out.png | Bin 1568 -> 1338 bytes tests/fill_test_8bit_palette_out.png | Bin 140 -> 140 bytes tests/fill_test_8bit_rgb_out.png | Bin 896 -> 700 bytes tests/fill_test_8bit_rgba_out.png | Bin 1117 -> 897 bytes 14 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/emoji.go b/app/emoji.go index 48e7773b5a..9982428711 100644 --- a/app/emoji.go +++ b/app/emoji.go @@ -14,7 +14,6 @@ import ( "image/draw" "image/gif" _ "image/jpeg" - "image/png" "io" "mime/multipart" "net/http" @@ -31,7 +30,7 @@ import ( ) const ( - MaxEmojiFileSize = 1 << 20 // 1 MB + MaxEmojiFileSize = 1 << 19 // 512 KiB MaxEmojiWidth = 128 MaxEmojiHeight = 128 MaxEmojiOriginalWidth = 1028 @@ -155,8 +154,8 @@ func (a *App) UploadEmojiImage(c request.CTX, id string, imageData *multipart.Fi return model.NewAppError("uploadEmojiImage", "api.emoji.upload.large_image.decode_error", nil, "", http.StatusBadRequest).Wrap(err) } - resized_image := resizeEmoji(img, config.Width, config.Height) - if err := png.Encode(newbuf, resized_image); err != nil { + resizedImg := resizeEmoji(img, config.Width, config.Height) + if err := a.ch.imgEncoder.EncodePNG(newbuf, resizedImg); err != nil { return model.NewAppError("uploadEmojiImage", "api.emoji.upload.large_image.encode_error", nil, "", http.StatusBadRequest).Wrap(err) } buf = newbuf diff --git a/app/imaging/encode.go b/app/imaging/encode.go index 1afb3159d9..d10f73c91a 100644 --- a/app/imaging/encode.go +++ b/app/imaging/encode.go @@ -45,7 +45,9 @@ func NewEncoder(opts EncoderOptions) (*Encoder, error) { e.sem = make(chan struct{}, opts.ConcurrencyLevel) } e.opts = opts - e.pngEncoder = &png.Encoder{} + e.pngEncoder = &png.Encoder{ + CompressionLevel: png.BestCompression, + } return &e, nil } diff --git a/app/user_test.go b/app/user_test.go index 086e71e25f..b4a57dd32a 100644 --- a/app/user_test.go +++ b/app/user_test.go @@ -121,7 +121,7 @@ func TestAdjustProfileImage(t *testing.T) { assert.True(t, adjusted.Len() > 0) assert.NotEqual(t, testjpg, adjusted) - // default image should require adjustment + // default image should not require adjustment user := th.BasicUser image, err := th.App.GetDefaultProfileImage(user) require.Nil(t, err) diff --git a/app/users/profile_picture.go b/app/users/profile_picture.go index 1858140e52..4a9c73f36f 100644 --- a/app/users/profile_picture.go +++ b/app/users/profile_picture.go @@ -160,7 +160,10 @@ func createProfileImage(username string, userID string, initialFont string) ([]b buf := new(bytes.Buffer) - if imgErr := png.Encode(buf, dstImg); imgErr != nil { + enc := png.Encoder{ + CompressionLevel: png.BestCompression, + } + if imgErr := enc.Encode(buf, dstImg); imgErr != nil { return nil, ImageEncodingError } diff --git a/i18n/en.json b/i18n/en.json index 0fac9e2df3..c9d23f4a46 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1719,7 +1719,7 @@ }, { "id": "api.emoji.create.too_large.app_error", - "translation": "Unable to create emoji. Image must be less than 1 MB in size." + "translation": "Unable to create emoji. Image must be less than 512 KiB in size." }, { "id": "api.emoji.disabled.app_error", diff --git a/tests/10000x1_expected_preview.png b/tests/10000x1_expected_preview.png index bf2ca9cc218dc3f05531b743122fc2ae61df969e..6c48a5242149680b56b3660e0dc6402c64cf7835 100644 GIT binary patch delta 26 gcma!vnV`jZYofNIfTQ@H4hA6bboFyt=akR{0BS!6$p8QV delta 26 gcma!vnV`iuXQH;E0M8+t4Gciw>FVdQ&MBb@0A}U~sQ>@~ diff --git a/tests/10000x1_expected_thumb.png b/tests/10000x1_expected_thumb.png index a354c410473a0afaaffa29debb380348e798873c..93a8cb36673e6f0902388694de551d25bd174d73 100644 GIT binary patch delta 39 ucmebAnV_X~E9vKX1Fjd042%p6|NrN1VPrY+R!Wxv2s~Z=T-G@yGywo3!ws(h delta 39 ucmebAnV_XKC+X*T1Fjd042%p6|NrN1VPvV1xpsm92s~Z=T-G@yGywn{uMMjJ diff --git a/tests/1x10000_expected_preview.png b/tests/1x10000_expected_preview.png index b4317244e90f3076aac8255efdbd9b723e7bfc97..ba938e6aefeda805e2b8a648ad833854529b8763 100644 GIT binary patch delta 26 gcmb=doM6LvYoe`=fSicZYz83kboFyt=akR{0BP^mW5Ul_J delta 42 xcmebGpP;2WC+XMu0|$;6bg^@@u`n?F|F83&@x;#w8jBc!z|+;wWt~$(699U?5QYE% diff --git a/tests/fill_test_16bit_rgb_out.png b/tests/fill_test_16bit_rgb_out.png index bb9741d53fe3a0276abce816ce948732c6a00577..72f7b9ca99ae6326e8cd3655aeafd9cb54345a33 100644 GIT binary patch literal 1011 zcmeAS@N?(olHy`uVBq!ia0y~yV5|bN{|GPv$z^9$zA`W{@A7nU45_&F=Eg?B1_Kf2 zjrn@N*XLAmtq@)!7_;~DtW0)>2LjVM85jzg85Hsu7>@8VH0)r6Q3B=+43F3t9PYrW z4r#bjR2@L2AdN^mfJ#9ck#qnJN3sK|lu{iH=BHWeFQ|nve4D-{>_PW)Hj3Q<3JX+M zlNTh=utf48G%S$}r%51UdVo-{W9lH!%Rs-Pr2^V`*?(r{Sq6qVhlgTe~DWM4fiyuk8 diff --git a/tests/fill_test_16bit_rgba_out.png b/tests/fill_test_16bit_rgba_out.png index 491bee1ce511e72a546b06d0a76c401a4940c297..7e521ccbe65e8452ff891a6ad25e1ed8b6023ff2 100644 GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yV5|bN{|K-FNzHYe7cnrfGJ3i=hE&{ob8BPnAqSC$ zht{XB@EqjOaX9L;=AcT?5jK+xjCF!lJ3J;^^oi&_`mOS1LG9VUc6X)=O_XO~c(DKF z8lX`uwhRmkFBlmZ9Qhd-n&cQ51immZG%R3;$Z!Ddbhy9_kwH-kl0i`lG6b#^Bm*}U zW(eF=xD1MYAP2ydf?a}QABs|t42n_=`%s)_;F!<4MPt#mpk2?IpFg%{IAiInb`<+i;sGp!>@?~IE{)@z z#Gru31uQ)A2L(!~(JTw>4_YnD@Ze9w`mbRQ)k;P4&RgnFpR;}TU4{>P6Hip`y~UdU zkz@8p6E=}OR!_5amsbBP-V*gRM$f+8j=`tU=Grd{Yd>{hVg+VH-%ot#Ngw7>uQ zhq0%Rh&XbZIJo$3aa5h+!mcub@!n)pi(TG)oc;fIzn{D&{q)Jx-@aFTJH09QF)IVZ zl{abnK+|gGFJNbAFmU8&U`T9|V_-PMV#~nL!U?pFL--2=gMiu#Mg|3+3(O1-Ge(BO z+vnpL{-xZ$RvK9rZ*S56p7BAx?0mJ`+jQCwzwv#b&RL~*isR?%)gNCzOgwY@wxPZK z^ISHEb@znVu`W*y*r*^3UD74d1_CzK+@9%H_*%cpu2zS@^ukaw7W!YrpUu zKlQI4@<(Rij{17=W~7)6rE~W(GPur@{}cahvv|Y(+}ktOuTS2$xA*5q!+doHE53Ha z`}aXFi!#-|vZ>!+2|=t-XNI7UkItK;Y@>=d#Wzp$Pzal?YV; delta 28 icmeBS>|vZ>!#HQ6t-ZjcBN7)FfWXt$&t;ucLK6Ugh6vFB diff --git a/tests/fill_test_8bit_rgb_out.png b/tests/fill_test_8bit_rgb_out.png index 499026d665ee0a33dac235b00193272a5cbc962b..3214f84c0fa4896dc9018ef3458faf4a8f483664 100644 GIT binary patch literal 700 zcmeAS@N?(olHy`uVBq!ia0y~yV5|bN|8Ot?$!{?~wlOd;HG8@^hE&{obL}86gCd7Z z;EfCQr#I_X9PEBy`e4Q%gQ-kA9vCw!m^a*EIKd027>bxdJTL{60r9{TSV0jpTpd&w z19PdQgMd|=C%wKt#=p%cQPs!F}plr>o~zHFi~1T$=tyuuc2em zNX&W3$oy_z+yUlqbK^eP-W!x|9GoFHpsspTx?G(h|HEKPNhF5HKSlB0S728<0Cm=(S- zaM&_9@xz!f8ov-w7F{FJLO>f(Y=qbZ7CNv_#%IG^LtXLbDV#r^&FD!p=J*?@TpxKi z-27_0YeKEhDt4gAyxP6b@>g32AMor~v+$pDqi?#+95ea&uSljM`~&v~aY7un0~!FR zmLquxiAi0LpxOwFR2Yqr{eN0bxZ(51>%a(_8MrrO{ng!;390Muohj&(F4Jjzw0!FP zY3moie)USCHsNiilz#aaYZ5>(YPJ6t@BHYB!Np1N{ZQ~U7Cs^67LKg>R#yZ=1%+8RcM*GJzmGW>~l z;ulc=!caK$sP9{<9Zp)ktDkfHooqqU>xkmpwvVz}{yAPV)K7o*_spJ|Gv#-GKft+m z=Fbh)M?^XQKK`@o+5K~8cHeb=aK!GNT!HJo7xJf7`RmK7_r3agzC}*K?*-$dQEI3L z!M}}tcbOj?`D15RdCOKIt4(#NSb@pa?R zuPlEZcyA}0ZTDWT&=i>ZpZ5;O6!0z`SW^7||L~f;o9i|U86bzj)78&qol`;+0Dc3) AW&i*H