From e362a7cff58d34db8bfeb7e108eaa8b7197422b5 Mon Sep 17 00:00:00 2001 From: Clinton Ingram Date: Mon, 7 Nov 2022 23:40:14 -0800 Subject: [PATCH] v0.13.2 --- doc/images/IMG_2301-ImageFlow.jpg | Bin 0 -> 3324 bytes doc/images/IMG_2301-ImageSharp.jpg | Bin 4765 -> 4683 bytes doc/images/IMG_2301-MagicScaler.jpg | Bin 4925 -> 4933 bytes doc/images/IMG_2301-NetVips.jpg | Bin 4004 -> 4772 bytes doc/images/IMG_2445-ImageFlow.jpg | Bin 0 -> 2499 bytes doc/images/IMG_2445-ImageSharp.jpg | Bin 4116 -> 4027 bytes doc/images/IMG_2445-MagicScaler.jpg | Bin 4089 -> 4082 bytes doc/images/IMG_2445-NetVips.jpg | Bin 3352 -> 4120 bytes doc/images/IMG_2525-ImageFlow.jpg | Bin 0 -> 3280 bytes doc/images/IMG_2525-ImageSharp.jpg | Bin 5039 -> 4881 bytes doc/images/IMG_2525-MagicScaler.jpg | Bin 4863 -> 4870 bytes doc/images/IMG_2525-NetVips.jpg | Bin 4037 -> 4805 bytes doc/images/sample-ImageFlow.jpg | Bin 0 -> 2924 bytes doc/images/sample-ImageSharp.jpg | Bin 6809 -> 6807 bytes doc/images/sample-MagicScaler.jpg | Bin 3957 -> 3973 bytes doc/images/sample-NetVips.jpg | Bin 3620 -> 6972 bytes readme.md | 282 ++++++++++-------- .../Magic/Processors/ChannelChanger.cs | 8 +- .../Magic/Processors/Converters.cs | 6 +- src/MagicScaler/readme.md | 4 +- src/NativeCodecs/Giflib/GifDecoder.cs | 14 +- src/NativeCodecs/Giflib/GifEncoder.cs | 8 + src/NativeCodecs/Libjxl/JxlDecoder.cs | 14 +- src/NativeCodecs/Libpng/PngDecoder.cs | 9 +- src/NativeCodecs/Libwebp/WebpDecoder.cs | 6 +- src/WebRSize/WebRSize.csproj | 2 +- 26 files changed, 196 insertions(+), 157 deletions(-) create mode 100644 doc/images/IMG_2301-ImageFlow.jpg create mode 100644 doc/images/IMG_2445-ImageFlow.jpg create mode 100644 doc/images/IMG_2525-ImageFlow.jpg create mode 100644 doc/images/sample-ImageFlow.jpg diff --git a/doc/images/IMG_2301-ImageFlow.jpg b/doc/images/IMG_2301-ImageFlow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..36d58c27c43408512981a60dbb4c228f6593f78b GIT binary patch literal 3324 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 literal 0 HcmV?d00001 diff --git a/doc/images/IMG_2301-ImageSharp.jpg b/doc/images/IMG_2301-ImageSharp.jpg index cb1f9836a653082ad6a921d888a9143724bfed35..55ccb6aefc6acd71e845465d1f4e87cf52217908 100644 GIT binary patch delta 2974 zcmV;P3t{w~CCenRR|2!N0*C?y6)8mY_me>dI{~(neFZ#!hXp-TGz+MhyGxV_z~h6S zwUv1`8C_Tv^v6n`6)Z_&3J;fdf6rt3R&0A_aTrBlP8%PUIbs@m1ZYOukWYN8Fi4;> z9o&#=TZd_wNKoN83ycCyGFXz@2N9-zZma82y~C(gW>EWbPeJwi)^e)eLn@aVkFXzzhaKHL<1`TIbFYgVg1+anE0^V+Uzy zZz%hxLt@DB7ad9KR_T`O`>cR**cyF%^j+e7-YF$JAtgH=5l+P=07gX=;wdpe z92JwB22TNLlj{avf0@bM*y=45OrB}UL-$y(@bu~ZXpz5k2v=>Vk@)`r^{bqiOfMyz z%);Xsak!1Aw@>9;miJ~$WSwPJRv0We1o|4q)b@r@oN^{TPL>`$LIcCL6he^ozP$>{8F7NxM+apt-+ zd2O^2p5xRSuX^#zO~@5m@gx`jUsS&Z)nK`WB9;5v5;}o@}<16j^RbxI9QmR64+AS+3WaJ zRuIK}e5*U%vf3$-U}Ngs@JIBomUx9pb5CRFC$V=~f4GlS2@7r#1S+wyE*KsI1C6W4 zIj(xj-gstNnaIe=;;&k? zfn6kx*B$ZO*Z%<3P?^;pSFpy|ZkfKy;zY<2e=43orfS8xPo5W%eB7Qob?KU(-tAdP zVyLa?F`9&`3%JU>j9Z-GVE$j$x2EkRXE^(>QSfQgPWe)~QP6l zYX&*f6-8twPkC0E$3kzjJZ`HuqT}ReQMRhLK!@?W{|db zb;qdB(wPz^wZxY4nB1ou)22IP9jihVDxr}VZh8ZdYGUkk#dAcZ2bpk6NTFLisW=0k zYV7kJHsT=(IAAh8Y2H9A(r~%PK&g$ZG{t23mmOzvB5{`84GHIQe+Y0082&D` zEv?A%R5Jz7Et;coD@lbXk-$)Rq}qItao3-GS9i2&-E4AuB;(5TX3UpB6$;#ElUC8j z&VVx)F&~2^0lVe>w~fN9$K7u!_<# z0VyaEp%Q_N{vVxMx?PUM_i#P?*0Hx!nsnSAgxY`E)+IBSn&F(C#|20E z{=8PCdYla^7;Qt{f4gEr2X9mLtfypvZjL`LGu2CFmA$>Y)%`VLi%{Ep{*1~>VGrM7 z*B*wGeT$8er3qY!)i1NgBI3WK3T5CxAzq|(kW};dD0D7>=l8dr$2ZN06s^)7!Su$|j zl##@S&EJas5P`IUqd<5Yf@;kk}3`tHJ~JA zLnd%k@DHU>e~Ev5r+)4##FDg$^CkkE99Lv6wMQ)ZWn|41y7Ln%a0jhB%|G6(!aifM zu%nJ>%YV;7T?%g6oN}QX=y2B83mu_GT#$3SxIdr2=~rQ#Ll|s3ZvbN)RydUkvSc=K zgPsY`TG_CSlCVRWrrWs#bif3W>0S#*u9+N`o?n?NJClY1ly2$&0M`Ei3T^A|wc4_f z=dj7h`gf$emgWR_r)bXHNCJ=u&r$rTEaF?wIL&dekV=AZN9oNglXVX|0p*jh4>bWu zljaX@e`#{_fOkmcS%)7e&*xCbaT>V~FOCL#WK{9myGS@8fx+%S zD%upC%;#BKMk*uAxw%cFkZImk!yx&F#r^ zBNC&ri5g7O9Fn|r#%fc-g ze+!MFxyMSgZy1>}#N;OjxaO-!?vgkzSS~h(=N%~`i}6a=DzQ(A0}dIwt_NzNaO|+L z&VFsY)%c}rl~||5frkv;R|ByXd|mC;4wJ>@DEO$X0(wP=NoVkfB^Tb z+y*Bg9s%jojMkDO{Nru{5C9(ZGNMYyf692ajP4xdnsvJp+fO5|F->FTJX=P04suO8 z-HC0dk=GcgWtVMLe91=9j1y0db8R~uD5%>Ut>yUrXwNkR;Idk)U+!Nb1bpS`;0t>D|{{TMK)g8&`lTH#A zM69cHQ!zpY8cY-4p#K0G)wi~VdLa3;n)NWcv&qJ2yA#C{Ajlk^GJ4a^GANM-K;-e0 U)}Cv=J04uO8fhs_B~d5;*)1-%(EtDd delta 3058 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 S6jz}gk1kt{G*Lw|Pyg9rE>XAu delta 3765 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 diff --git a/doc/images/IMG_2301-NetVips.jpg b/doc/images/IMG_2301-NetVips.jpg index 171a3d9a2a2757f920b394b4f4196ec36b92a639..ec531ae7d3ebd1e44e0f84bf5347c8fd25c516cb 100644 GIT binary patch delta 785 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 E2LKUFG5`Po literal 0 HcmV?d00001 diff --git a/doc/images/IMG_2445-ImageSharp.jpg b/doc/images/IMG_2445-ImageSharp.jpg index 5c06e821d4a554b0ebc2744205cf32d9a63b3c31..84668977d39b02c7c16949b5b98247cf1d4ec178 100644 GIT binary patch delta 2868 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 D3i0j04;BdIh{ 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 diff --git a/doc/images/IMG_2445-NetVips.jpg b/doc/images/IMG_2445-NetVips.jpg index 5928ab890b40ee2bfe1653fb5e1c164bfb76920f..d2544011269fd8db34c744fd38cffbc086c13430 100644 GIT binary patch delta 785 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 H4(9&@XQz_L literal 0 HcmV?d00001 diff --git a/doc/images/IMG_2525-ImageSharp.jpg b/doc/images/IMG_2525-ImageSharp.jpg index 328ebef3c2bf9ebce30d499169fcab0c0a355627..44de1941e3d53ac8e394d7217c6c450bac0c3ca9 100644 GIT binary patch delta 3600 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 W03T{izwJN$^lIzI^Vpa@5C7R7+xi&* delta 3739 zcmb7^X*kpkqsIT1vJ}deWkfS0yBOO{mPxXV!q^$hQ(0onj9pUtYqA?VBU?g@u_ik$ z_99G}Bum+aNb>Mld(S!7b*}5Y*Zb+*-|pXi-(T<4i#0MY>{*@H0Vk}NZ;)@Gm#?3c znz9OjyoxbnX9xaUXb39~U=x=%hOhzvE5Ht6)dDyXDk>-yErbSyRR=h!s*X@qQ-QGR z{a=p$UtVX&`WGvkk>Y%MGdr9Gnm)}g0$R%4DhWhY#m5)>Q4p#w?5l-gV-mBX$fCc@R#OnV(9W|Rpk5OQp7 z%sXPxnU=%6Oe1Xnf&IPToP28?@2gkDCb15`#CzlvOoRZHAtwq%H!#g-aMU%sEi&Uvh-2wstg!3pXmaUe>4EtkCBV<)9`o5x4UO|!R-ZKCiNqvZO_6#90#R77$Z ziLc>?wJu$!?z@xfeZpi$JUN5T21tc{TyDXv%s#y=7pI;1*{lPB> zvrSP{yaJq_ncpAVYu0Q`?Tw6kuA8j?)6tCk+GhViu0{A%a#@c%-u|=EicECKHNOtl zc~J>;Re&{a?|hUu?lLLtWENrap7oj&UASlH+epi#E~%gM2hRBB=SW2tg3VhvR zQH#q7w;H0Ip19dXgHj1{Scm+9P~><2ZzVo*&I^{c6BZYleT;|xKOOAvn&`7c`RiRw zn?JaZePAl|ymz`gf;&ksZ!9`;@@8{nukG1gcmKQyq{t3URJz$zX*H3{Gf4wsx*B`A z?#v0{-H;}pM)4;Lx4u9GY#QEoPq;xZxV`38%RB6R={hz$;|O-+t6dr+#c_zsko0vN z>PvRn)EW!0iEmh<`O=<@5hqLFQrF;l;d%{<0Rr5rSdlWBwfNr8>!qy+7vef!wgs+? z#3(3`apS{H%&KbXE%FD*b9couo2F4+yv8SJy0s=$j*Zo(r5AD12Sq4OniiX0w2Bu^ za6jHWOIG^^md%fqroC5wL3-7R4y}5$0j%vY@0)S&grz&;$@}Z;uc8x~{D=T^Ue38} zy<&J+xuY@Qn{E4~cIK%CsVhgi)`{q}?&VaIU4M6;=NO%+c?wRnUw5Y79=Vz9%CTZG z;q!qhsJ`^w@Lu&a>)6c1I|zTPf+hy-YD`eE3B1=G?{huHiKs9Op`JEw7HvnyDm zQ=UsJ^>+ZOLbWNEG}*YY06EQ#&78y}S-xyD;%O`nR(Bfg?uq!28D)CO_4R>WLt9@U z=e_ABSf(nyldKZ>&Y8?>X6Po=+M8;i=mi(?5P=_|DjwoBUW9hWetGX41_1QPz5MtL z2x!}p%`(I4<#{C($SK>RY^oXbtF;dXiBNr&-QqhfWc;KAm&+IuNJ8s-HLA=z37KA%V3dl}-dqY!fU7cKLvL#tzEi)y5HZ_Ukph2(T@^y`Y z_yw8%CSF)0gsONAm#Pw|uzDW60BGpX<6!Y{^sUkM>4EY)%2< zYCw#1OQjFqUO^}_?a^z&YX9R+A!@Mg*>Xd1(QAwr6WFQ8WOMCbd!J&r;R$Bc;nF{V z!=(rL28lo9>+JOQO_%s^7tj5y~2+( z8a)4rKAg}eZ9W;_YlflbPu7%xndMNaXdP&jGbPW;*}E~zU(u?wO{fWYdr4Q@?qy^i z>P9h={#&#bkC1Bc9w0;-tDRBZdeQL*c!S|sxn4Q_;bc*Tz{8&(>W_|r?@By=c#xcO4!nNLITTi#u6QhiR~`fgWrKCJ_}*Apfic6cUVrHvzBVm(oa~yAmAqV=$C`T&uTl= z80jR>)m5+H`?PZ>b*nWil#T!E5mWG5{Law&{N5*{oT&UB`RcoNQ;*@htd#UAZsi9R ze`PN6?saeteWU+fwA|mY=ZgKAcP4LrzW`Sqx(iElp;WY7D;4DcfA!L~E2td1@qsQz z#j|(CJYI|v2phD>6Db7QAz)Qd6V2i<5ok1O25Aj4`DN5yGxS{LhtcW~;;jKjn#i-} zNG_V;&AgDVG*Va_x-zW`$d7RI!b1FWG+LW?mpirXatEysKVca8c z$;e8Q#xO`j&&4;Hs%Z`V87@C`ThDuE&ll3PXJf_DjCm91 zAMElEZSO)m@5mhDZA5>_m8}=dN=DFi7VS_eyx?n0e|xb%ccY)y{ke>Lk9GKUSGw!d z2}vj?Zaoi|jzkr*TZWE@i+_p{XIY}5l7OJB9DLq+D>w(wU*$p@l6)SMO|96!-9I7v#6FJ%a?H4tWB5 z{p~$B(s4XEP><=i3+L}5hq8@x_vPBv+g|`f@3&P4ZWj@8!_HAhvl|;NjFA^h8nxS= z^x2jAEt2}&h+&EjMc~mYkNcpTcZFI)#@3}Bk?wqvg&@%K=j4hj1%vJkU!(rIn5c05 zs02Uzpy6mPm6DAAD)5HV>(^MTvoPrKeAP(2H;oIN0dr6i`m~Gm5)#&T?$oMF;Ne=J zOMQXMFm=rW$s{~Vg~{_xoZ)qYwXo3^U9Y`?KOykm0+r$}%t@-~CJP1B$hN5(Ww=*| zDOb%AHI(KYa@SG*EwEsASrMJ|o|||vY7`w8N!0Y(II|J=b;Sv?JHKa-&|tD&LWrX@ zLDKY-3|~f#M7hxCY~|EHK!EARUYEx{Y@;xyz2Y}5>!R~3t^0$kGW}xo!RP{Jh}bdeanG^=={W! zL|0xRxT(q6hRB~lE@JtW$ z@SUPd>ybAPCf{AG=a?$_{#6=lVr_edpT&c~z2V@RuW$24T#c750FfWm^TKB=IB09m zK7aB5!zVn?_*!;6(U;;*31b=L`ZCS6)-uc}j|mnq^OqSwun|vK&{k}p&P4c~1p`Vj zYfnRUwlx?G1;*p0g{0iTf<@ED)<~;8U%@mK_CS9~IC>o3D)zHXG=Y?w-*+O@SUd*2 z!IaeGohwsIaaf2CDS$Lt)eG+jGN5$NX&LIXuoQG}ec?ya#bz6-laD=z)Rk;f=t2%| zVvcyx%^YKP?40!MXh{V3JWC5aC-9CG5~U1qU*=waJ1bGAS>^XNc%ZzUO?yG0Ib@z< zcXL>H(jm#XLp*DlPFeGiv)zDiWr7%Z}~Aq zg2$Ed>1LMgrM7}oxL22<*(y5kl;4^cj3ocNZAtL!IBD^5S|IQc?L=Xg!?JT&FX0Ag=pw?^ilEN^0IXy*?nr|t@bvGxU5 zHUxQmTeR=c>;IR4|1-ibD%2PtjfRef43%!T8Qu}sO79Gk%r_`A7B29E#!C}GfrWz2 zBUvUa!J_%BA%7z}Zp-4IhZ*>@J+vv#qBtkX?md}9wCQ`MyEP`D0}f_=1b{<@XLTQE za#RL&+js2P_AT!ecBtRVx&P=#CC7FV!+`A7rM}AsesSPiaq8tEQA*(ZIo6@KJGC9$ zzxgdLa^A)CqPc6zzvl#3rW;E%UU6m}>OPuUt`e(`qv870{U_Z|v@8Cwm>von{?C&C z=bQ&)BZHR){8s3UQ{q8yM}LVZ$b7XPt@6Ps!ny|ujhmIG&jEoI@L2HQ!GCz6D9p6R z0zR=uS|>NA7pJKWvKnt!w$W~tzi&@{l5$3`-bI_o&WN4T9r5VzqLp#{OBJ{$oSm;q z;~Zzd(zjdQ_jCLwuPVc`?hF}J8*?<6opyCHDI8B5q#|W%{(t~3_V(6i?HgMDYG*c#hd4nPDZCtl-%Tx9#S!p{y44$8i@62U4L5aLZN#b(&nugRXXXf%Y& sCi=1L6bYV^q)kH81dW=31554`qwA>{ZkRI=US57F*}S_t=FgXZ0UFT^^8f$< diff --git a/doc/images/IMG_2525-MagicScaler.jpg b/doc/images/IMG_2525-MagicScaler.jpg index ecfcec02a316c031c9a51b4612f6c35d77acb262..f4d3ec941286c472148357b3ae135a1b80b0e5e0 100644 GIT binary patch delta 3689 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 H8z2AK;b$^u delta 3685 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 DggOtB diff --git a/doc/images/IMG_2525-NetVips.jpg b/doc/images/IMG_2525-NetVips.jpg index b4dbb9b0bc3f4af55bfcaa0b2b8287fe0b87b6d0..492a9442908e354cdc23881f5930237cb9870079 100644 GIT binary patch delta 785 zcmX>qe^j;p|Be3-8TPnVWTr7NczS9va4;}1urUZRGBYp&Ss*OM$O@*zfNW_fI}XU! zfU02vvW1xt>NDF}!0Lepg298yEDSH085m$R8w0}xb_N!poPm*Hy#eDy2!|191j7QT zgrR`};{u40|Nk>EFfD)>ISr_Z8Olz9n9lJ35tD?a_05zrezHD5sL)4^;eP<)9bLD(`Nc1dal&`bsf=lp`oqRjM+5(Ps` zOG^dEl>DSrh2YBKlGNN{1<$04% zR6vaT9LP`)PGw?e5P}Gsl1q!qpgcw&Q(sB%>R delta 12 TcmX@AdQ_h2|BcN|%!l~_B<2M& diff --git a/doc/images/sample-ImageFlow.jpg b/doc/images/sample-ImageFlow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9f88971e7f3269e6d300f1985fc69212490c733 GIT binary patch literal 2924 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 R>1Ps|dkii?G|d;Y{{e5T6Yl^3 literal 0 HcmV?d00001 diff --git a/doc/images/sample-ImageSharp.jpg b/doc/images/sample-ImageSharp.jpg index ba4750f16825dd5fb3c76edb9ed0215ecd3de6f5..05b41e07dce1378f6b1cdf6484e60a03ae4b5b20 100644 GIT binary patch delta 2877 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 diff --git a/doc/images/sample-MagicScaler.jpg b/doc/images/sample-MagicScaler.jpg index 0d588dff341ea15509cefdf1b4625184a0420982..e50d69f26d4c204c25410c760ef9aa2e8c428bf1 100644 GIT binary patch delta 3244 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 delta 3262 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 diff --git a/doc/images/sample-NetVips.jpg b/doc/images/sample-NetVips.jpg index 70065553f478ec5180ac72c18fbcb126c7e104e2..1252efa46a96e2df7cc354900ee4430758ebe2c2 100644 GIT binary patch delta 3389 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 delta 12 TcmdmEwnT>M|BcO3yh?lkBMStU diff --git a/readme.md b/readme.md index 2976a689..7f8f9792 100644 --- a/readme.md +++ b/readme.md @@ -12,9 +12,9 @@ Speed and efficiency are unmatched by anything else on the .NET platform. Requirements ------------ -MagicScaler currently has full functionality only on Windows. Although MagicScaler is compatible with -- and optimized for -- .NET Core and .NET 5+, it requires the [Windows Imaging Component](https://docs.microsoft.com/en-us/windows/desktop/wic/-wic-about-windows-imaging-codec) for its image codec support. +MagicScaler currently has full functionality only on Windows. -Work is in progress to reach full feature parity on Linux. +Work is in progress to reach full feature parity on Linux. A growing collection of cross-platform codecs is available on [nuget.org](https://www.nuget.org/packages?q=photosauce.nativecodecs), and at this point most use cases are covered. Notable exceptions are support for BMP and TIFF images and CMYK JPEG. Usage ----- @@ -35,94 +35,161 @@ See the [full documentation](https://docs.photosauce.net/api/PhotoSauce.MagicSca MagicScaler Performance ----------------------- -Benchmark results in this section come from the tests used in https://blogs.msdn.microsoft.com/dotnet/2017/01/19/net-core-image-processing/ -- updated to use current (Apr 2022) versions of the libraries and runtime. The original benchmark project [is also on GitHub](https://github.com/bleroy/core-imaging-playground). +Benchmark results in this section come from the tests used in https://blogs.msdn.microsoft.com/dotnet/2017/01/19/net-core-image-processing/ -- updated to use current (Nov 2022) versions of the libraries and runtime. The original benchmark project [is also on GitHub](https://github.com/bleroy/core-imaging-playground). *For these results, the benchmarks were modified to use a constant `UnrollFactor` so these runs more accurately report managed memory allocations and GC counts. By default, BenchmarkDotNet targets a run time in the range of 500ms-1s for each iteration. This means it executes slower benchmark methods using a smaller number of operations per iteration, and it can wildly under-report allocation and GCs, as those numbers are extrapolated from the limited iterations it runs. The constant `UnrollFactor` ensures all benchmarks' reported memory stats are based on the same run counts. The `UnrollFactor` used for each run is listed at the top of each set of results.* -Benchmark environment: +### End-to-End Image Resizing -``` ini -BenchmarkDotNet=v0.13.1.1695-nightly, OS=Windows 10 (10.0.19043.1586/21H1/May2021Update) +This is a semi-real-world image resizing benchmark, in which 12 JPEGs of approximately 1 megapixel each are resized to 150px wide thumbnails and saved back as JPEG. Not all libraries are supported on all platforms. See version notes below. + +#### Windows x64 + +```ini +BenchmarkDotNet=v0.13.2.1974-nightly, OS=Windows 10 (10.0.19043.2006/21H1/May2021Update) Intel Xeon W-11855M CPU 3.20GHz, 1 CPU, 12 logical and 6 physical cores -.NET SDK=6.0.300-preview.22204.3 - [Host] : .NET 6.0.3 (6.0.322.12309), X64 RyuJIT - ShortRun : .NET 6.0.3 (6.0.322.12309), X64 RyuJIT +.NET SDK=7.0.100-rc.2.22477.23 + ShortRun : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2 + +Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=32 WarmupCount=3 + +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | +|------------------------------------- |----------:|----------:|---------:|------:|--------:|----------:|----------:|----------:|-----------:|------------:| +| *MagicScaler Load, Resize, Save(1) | 46.85 ms | 2.948 ms | 0.456 ms | 0.13 | 0.00 | - | - | - | 42.37 KB | 4.65 | +| System.Drawing Load, Resize, Save(2) | 354.73 ms | 8.168 ms | 1.264 ms | 1.00 | 0.00 | - | - | - | 9.11 KB | 1.00 | +| ImageFlow Load, Resize, Save(3) | 226.48 ms | 2.284 ms | 0.353 ms | 0.64 | 0.00 | 968.7500 | 968.7500 | 968.7500 | 4627.13 KB | 508.17 | +| ImageSharp Load, Resize, Save(4) | 115.90 ms | 12.847 ms | 3.724 ms | 0.33 | 0.04 | 156.2500 | 62.5000 | - | 1532.8 KB | 168.34 | +| ImageMagick Load, Resize, Save(5) | 345.99 ms | 14.847 ms | 3.856 ms | 0.98 | 0.01 | - | - | - | 50.44 KB | 5.54 | +| ImageFree Load, Resize, Save(6) | 212.10 ms | 2.055 ms | 0.318 ms | 0.60 | 0.00 | 6000.0000 | 6000.0000 | 6000.0000 | 91.95 KB | 10.10 | +| SkiaSharp Load, Resize, Save(7) | 117.43 ms | 1.270 ms | 0.330 ms | 0.33 | 0.00 | - | - | - | 84.19 KB | 9.25 | +| NetVips Load, Resize, Save(8) | 100.92 ms | 4.383 ms | 0.678 ms | 0.28 | 0.00 | - | - | - | 115.9 KB | 12.73 | ``` -### End-to-End Image Resizing +#### Windows Arm64 (Windows Dev Kit 2023) -First up is a semi-real-world image resizing benchmark, in which 12 JPEGs of approximately 1-megapixel each are resized to 150px wide thumbnails and saved back as JPEG. +```ini +BenchmarkDotNet=v0.13.2.1974-nightly, OS=Windows 11 (10.0.22621.674) +Snapdragon Compute Platform, 1 CPU, 8 logical and 8 physical cores +.NET SDK=6.0.402 + ShortRun : .NET 6.0.10 (6.0.1022.47605), Arm64 RyuJIT AdvSIMD -``` ini -Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=32 WarmupCount=5 - -| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | Alloc Ratio | -|--------------------------------------- |----------:|----------:|---------:|------:|--------:|----------:|----------:|----------:|-----------:|------------:| -| *MagicScaler Load, Resize, Save(1) | 55.71 ms | 3.683 ms | 0.957 ms | 0.16 | 0.00 | - | - | - | 45.51 KB | 4.45 | -| System.Drawing Load, Resize, Save(2) | 357.62 ms | 12.352 ms | 3.208 ms | 1.00 | 0.00 | - | - | - | 10.23 KB | 1.00 | -| ImageSharp Load, Resize, Save(3) | 108.06 ms | 7.481 ms | 1.943 ms | 0.30 | 0.01 | 156.2500 | 62.5000 | - | 1492.73 KB | 145.98 | -| ImageMagick Load, Resize, Save(4) | 349.53 ms | 13.851 ms | 3.597 ms | 0.98 | 0.02 | - | - | - | 51.75 KB | 5.06 | -| ImageFree Load, Resize, Save(5) | 209.06 ms | 8.241 ms | 2.140 ms | 0.58 | 0.01 | 6000.0000 | 6000.0000 | 6000.0000 | 92.69 KB | 9.06 | -| SkiaSharp Canvas Load, Resize, Save(6) | 167.62 ms | 7.604 ms | 1.975 ms | 0.47 | 0.01 | - | - | - | 101.44 KB | 9.92 | -| SkiaSharp Bitmap Load, Resize, Save(6) | 169.28 ms | 2.591 ms | 0.401 ms | 0.47 | 0.00 | - | - | - | 85.5 KB | 8.36 | -| NetVips Load, Resize, Save(7) | 102.40 ms | 1.180 ms | 0.307 ms | 0.29 | 0.00 | - | - | - | 46.04 KB | 4.50 | +Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=32 WarmupCount=3 + +| Method | Mean | Error | StdDev | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | +|------------------------------------- |----------:|----------:|---------:|------:|---------:|---------:|-----------:|------------:| +| *MagicScaler Load, Resize, Save(1) | 65.72 ms | 0.532 ms | 0.082 ms | 0.17 | - | - | 42.36 KB | 4.65 | +| System.Drawing Load, Resize, Save(2) | 386.78 ms | 2.359 ms | 0.613 ms | 1.00 | - | - | 9.11 KB | 1.00 | +| ImageSharp Load, Resize, Save(4) | 287.06 ms | 3.125 ms | 0.812 ms | 0.74 | 375.0000 | 187.5000 | 1635.48 KB | 179.62 | +| ImageMagick Load, Resize, Save(5) | 588.63 ms | 13.049 ms | 2.019 ms | 1.52 | - | - | 50.44 KB | 5.54 | +| SkiaSharp Load, Resize, Save(7) | 158.27 ms | 1.816 ms | 0.472 ms | 0.41 | - | - | 82.32 KB | 9.04 | +| NetVips Load, Resize, Save(8) | 136.21 ms | 6.125 ms | 1.591 ms | 0.35 | - | - | 115.9 KB | 12.73 | +``` + +#### Linux x64 (WSL2) + +```ini +BenchmarkDotNet=v0.13.2.1974-nightly, OS=ubuntu 20.04 +Intel Xeon W-11855M CPU 3.20GHz, 1 CPU, 12 logical and 6 physical cores +.NET SDK=6.0.402 + ShortRun : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2 + +Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=32 WarmupCount=3 + +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | +|------------------------------------- |---------:|---------:|---------:|------:|--------:|---------:|---------:|---------:|-----------:|------------:| +| MagicScaler Load, Resize, Save(1) | 99.8 ms | 1.91 ms | 0.47 ms | 0.37 | 0.01 | - | - | - | 42.38 KB | 4.51 | +| System.Drawing Load, Resize, Save(2) | 271.7 ms | 12.34 ms | 3.20 ms | 1.00 | 0.00 | - | - | - | 9.4 KB | 1.00 | +| ImageFlow Load, Resize, Save(3) | 321.2 ms | 6.80 ms | 1.77 ms | 1.18 | 0.01 | 968.7500 | 968.7500 | 968.7500 | 4627.46 KB | 492.06 | +| ImageSharp Load, Resize, Save(4) | 226.5 ms | 4.09 ms | 1.06 ms | 0.83 | 0.01 | 156.2500 | 62.5000 | - | 1532.81 KB | 162.99 | +| ImageMagick Load, Resize, Save(5) | 522.6 ms | 27.02 ms | 7.02 ms | 1.92 | 0.04 | - | - | - | 50.84 KB | 5.41 | +| SkiaSharp Load, Resize, Save(7) | 338.4 ms | 38.62 ms | 10.03 ms | 1.25 | 0.04 | - | - | - | 84.48 KB | 8.98 | +| NetVips Load, Resize, Save(8) | 380.5 ms | 11.04 ms | 2.87 ms | 1.40 | 0.02 | - | - | - | 116.48 KB | 12.39 | ``` -* (1) `PhotoSauce.MagicScaler` version 0.13.0. +#### Linux Arm64 (Raspberry Pi 4b 2GB) + +```ini +BenchmarkDotNet=v0.13.2.1974-nightly, OS=ubuntu 22.04 +Unknown processor +.NET SDK=6.0.402 + ShortRun : .NET 6.0.10 (6.0.1022.47605), Arm64 RyuJIT AdvSIMD + +Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=8 WarmupCount=3 + +| Method | Mean | Error | StdDev | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | +|------------------------------------- |-----------:|---------:|--------:|------:|----------:|---------:|-----------:|------------:| +| *MagicScaler Load, Resize, Save(1) | 214.7 ms | 4.33 ms | 0.67 ms | 0.18 | - | - | 43.67 KB | 4.42 | +| System.Drawing Load, Resize, Save(2) | 1,205.9 ms | 26.54 ms | 6.89 ms | 1.00 | - | - | 9.87 KB | 1.00 | +| ImageSharp Load, Resize, Save(4) | 997.0 ms | 18.08 ms | 4.70 ms | 0.83 | 1625.0000 | 375.0000 | 1635.48 KB | 165.72 | +| ImageMagick Load, Resize, Save(5) | 1,688.5 ms | 12.84 ms | 3.34 ms | 1.40 | - | - | 51.47 KB | 5.21 | +| SkiaSharp Load, Resize, Save(7) | 279.7 ms | 1.87 ms | 0.48 ms | 0.23 | 125.0000 | - | 81.29 KB | 8.24 | +| NetVips Load, Resize, Save(8) | 421.5 ms | 14.72 ms | 3.82 ms | 0.35 | 125.0000 | - | 117.35 KB | 11.89 | +``` + +#### Versions Tested + +* (1) `PhotoSauce.MagicScaler` version 0.13.2 with `PhotoSauce.NativeCodecs.Libjpeg` version 2.1.4-preview1. * (2) `System.Drawing.Common` version 5.0.3. -* (3) `SixLabors.ImageSharp` version 2.1.0. -* (4) `Magick.NET-Q8-AnyCPU` version 11.1.0. -* (5) `FreeImage.Standard` version 4.3.8. -* (6) `SkiaSharp` version 2.80.3. -* (7) `NetVips` version 2.1.0 with `NetVips.Native` (libvips) version 8.12.2. +* (3) `Imageflow.AllPlatforms` Version 0.9.0. +* (4) `SixLabors.ImageSharp` version 2.1.3. +* (5) `Magick.NET-Q8-AnyCPU` version 12.2.0. +* (6) `FreeImage.Standard` version 4.3.8. +* (7) `SkiaSharp` version 2.88.3. +* (8) `NetVips` version 2.2.0 with `NetVips.Native` (libvips) version 8.13.2. Note that unmanaged memory usage is not measured by BenchmarkDotNet's `MemoryDiagnoser`, nor is managed memory allocated but never released to GC (e.g. pooled objects/buffers). See the [MagicScaler Efficiency](#magicscaler-efficiency) section for an analysis of total process memory usage for each library. The performance numbers mostly speak for themselves, but some notes on image quality are warranted. The benchmark suite saves the output so that the visual quality of the output of each library can be compared in addition to the performance. See the [MagicScaler Quality](#magicscaler-quality) section below for details. -### Parallel End-to-End Resizing +
+More Benchmarks -This benchmark is the same as the previous but uses `Parallel.ForEach` to run the 12 test images in parallel. It is meant to highlight cases where the libraries' performance doesn't scale up linearly with extra processors. +Benchmark environment: ``` ini -Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=64 WarmupCount=5 - -| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated | Alloc Ratio | -|----------------------------------------------- |----------:|---------:|---------:|------:|----------:|----------:|----------:|-----------:|------------:| -| *MagicScaler Load, Resize, Save - Parallel | 11.49 ms | 0.643 ms | 0.100 ms | 0.09 | - | - | - | 73.98 KB | 1.88 | -| System.Drawing Load, Resize, Save - Parallel | 133.11 ms | 0.709 ms | 0.184 ms | 1.00 | - | - | - | 39.41 KB | 1.00 | -| ImageSharp Load, Resize, Save - Parallel | 22.91 ms | 0.281 ms | 0.073 ms | 0.17 | 156.2500 | 78.1250 | - | 1524.18 KB | 38.68 | -| ImageMagick Load, Resize, Save - Parallel | 100.92 ms | 5.891 ms | 1.530 ms | 0.76 | - | - | - | 85.45 KB | 2.17 | -| ImageFree Load, Resize, Save - Parallel | 46.08 ms | 2.399 ms | 0.371 ms | 0.35 | 3062.5000 | 3062.5000 | 3062.5000 | 118.96 KB | 3.02 | -| SkiaSharp Canvas Load, Resize, Save - Parallel | 34.09 ms | 0.527 ms | 0.082 ms | 0.26 | 15.6250 | - | - | 134.99 KB | 3.43 | -| SkiaSharp Bitmap Load, Resize, Save - Parallel | 34.36 ms | 1.025 ms | 0.159 ms | 0.26 | 15.6250 | - | - | 116.9 KB | 2.97 | -| NetVips Load, Resize, Save - Parallel | 38.69 ms | 0.252 ms | 0.065 ms | 0.29 | - | - | - | 77.99 KB | 1.98 | +BenchmarkDotNet=v0.13.2.1974-nightly, OS=Windows 10 (10.0.19043.2006/21H1/May2021Update) +Intel Xeon W-11855M CPU 3.20GHz, 1 CPU, 12 logical and 6 physical cores +.NET SDK=7.0.100-rc.2.22477.23 + ShortRun : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2 ``` -Note the relative performance drop-off for NetVips. It uses multiple threads for a single operation by default, making it scale up poorly and leaving it vulnerable to [CPU oversubscription](https://web.archive.org/web/20200221153045/https://docs.microsoft.com/en-us/archive/blogs/visualizeparallel/oversubscription-a-classic-parallel-performance-problem) problems under heavy server load. +### Parallel End-to-End Resizing -Similarly, System.Drawing fails to scale up as well as the other libraries, but for the opposite reason. The System.Drawing tests run at less than 100% CPU when run in parallel, presumably due to some internal locking/serialization designed to limit memory use. +This benchmark is the same as the previous but uses `Parallel.ForEach` to run the 12 test images in parallel. It is meant to highlight cases where the libraries' performance doesn't scale up linearly with extra processors. -
-Resize-Only Synthetic Benchmark +``` ini +Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=64 WarmupCount=3 + +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | +|--------------------------------------------- |----------:|----------:|----------:|------:|--------:|----------:|----------:|----------:|-----------:|------------:| +| *MagicScaler Load, Resize, Save - Parallel | 11.07 ms | 0.511 ms | 0.133 ms | 0.08 | 0.00 | - | - | - | 71.35 KB | 1.95 | +| System.Drawing Load, Resize, Save - Parallel | 144.01 ms | 26.195 ms | 4.054 ms | 1.00 | 0.00 | - | - | - | 36.62 KB | 1.00 | +| ImageFlow Load, Resize, Save - Parallel | 51.70 ms | 5.179 ms | 0.801 ms | 0.36 | 0.01 | 984.3750 | 984.3750 | 984.3750 | 4628.02 KB | 126.39 | +| ImageSharp Load, Resize, Save - Parallel | 26.25 ms | 32.435 ms | 5.019 ms | 0.18 | 0.03 | 171.8750 | 78.1250 | - | 1564.91 KB | 42.74 | +| ImageMagick Load, Resize, Save - Parallel | 149.86 ms | 27.115 ms | 7.042 ms | 1.03 | 0.05 | - | - | - | 88.22 KB | 2.41 | +| ImageFree Load, Resize, Save - Parallel | 63.07 ms | 41.212 ms | 10.703 ms | 0.45 | 0.09 | 3156.2500 | 3156.2500 | 3156.2500 | 117.06 KB | 3.20 | +| SkiaSharp Load, Resize, Save - Parallel | 26.31 ms | 1.399 ms | 0.216 ms | 0.18 | 0.01 | 15.6250 | - | - | 110.13 KB | 3.01 | +``` + +The NetVips test hung during this benchmark and had to be excluded. Previous versions worked, so it is unclear whether the issue lies with BenchmarkDotNet or a change in NetVips. ### Resize-Only Synthetic Benchmark -This benchmark creates a blank image of 1280x853 and resizes it to 150x99, throwing away the result. MagicScaler does very well on this one, and it's the only one MagicScaler can do on Linux (for now), but it isn't a real-world scenario, so take the results with a grain of salt. +This benchmark creates a blank image of 1280x853 and resizes it to 150x99, throwing away the result. MagicScaler does very well on this one, but it isn't a real-world scenario, so take the results with a grain of salt. ``` ini -Job=ShortRun IterationCount=15 LaunchCount=1 UnrollFactor=256 WarmupCount=5 - -| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | Alloc Ratio | -|------------------------ |------------:|----------:|----------:|------:|--------:|---------:|---------:|---------:|----------:|------------:| -| *MagicScaler Resize | 577.9 μs | 1.01 μs | 0.94 μs | 0.06 | 0.00 | - | - | - | 1425 B | 10.33 | -| System.Drawing Resize | 9,093.6 μs | 84.16 μs | 74.61 μs | 1.00 | 0.00 | - | - | - | 138 B | 1.00 | -| ImageSharp Resize | 2,247.4 μs | 94.39 μs | 88.29 μs | 0.25 | 0.01 | - | - | - | 10364 B | 75.10 | -| ImageMagick Resize | 37,032.8 μs | 906.42 μs | 847.87 μs | 4.08 | 0.11 | - | - | - | 5338 B | 38.68 | -| FreeImage Resize | 5,940.9 μs | 119.98 μs | 112.23 μs | 0.65 | 0.01 | 500.0000 | 500.0000 | 500.0000 | 306 B | 2.22 | -| SkiaSharp Canvas Resize | 1,577.6 μs | 19.76 μs | 18.49 μs | 0.17 | 0.00 | - | - | - | 1745 B | 12.64 | -| SkiaSharp Bitmap Resize | 1,558.8 μs | 10.30 μs | 9.13 μs | 0.17 | 0.00 | - | - | - | 489 B | 3.54 | -| NetVips Resize | 3,540.6 μs | 23.28 μs | 21.78 μs | 0.39 | 0.00 | - | - | - | 3859 B | 27.96 | +Job=ShortRun IterationCount=5 LaunchCount=1 UnrollFactor=256 WarmupCount=3 + +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | +|---------------------- |------------:|------------:|----------:|------:|--------:|---------:|---------:|---------:|----------:|------------:| +| *MagicScaler Resize | 621.8 us | 57.39 us | 14.90 us | 0.07 | 0.00 | - | - | - | 1385 B | 10.04 | +| System.Drawing Resize | 9,525.0 us | 619.59 us | 160.91 us | 1.00 | 0.00 | - | - | - | 138 B | 1.00 | +| ImageFlow Resize | 6,464.7 us | 237.70 us | 61.73 us | 0.68 | 0.01 | 11.7188 | - | - | 116005 B | 840.62 | +| ImageSharp Resize | 2,299.1 us | 72.70 us | 18.88 us | 0.24 | 0.01 | - | - | - | 10365 B | 75.11 | +| ImageMagick Resize | 39,426.5 us | 2,093.00 us | 543.54 us | 4.14 | 0.10 | - | - | - | 5338 B | 38.68 | +| FreeImage Resize | 5,855.3 us | 324.42 us | 84.25 us | 0.61 | 0.01 | 500.0000 | 500.0000 | 500.0000 | 306 B | 2.22 | +| SkiaSharp Resize | 1,560.8 us | 49.18 us | 7.61 us | 0.16 | 0.00 | - | - | - | 489 B | 3.54 | +| NetVips Resize | 9,412.2 us | 131.95 us | 34.27 us | 0.99 | 0.02 | - | - | - | 3859 B | 27.96 | ```
@@ -140,57 +207,22 @@ In order to accurately measure both CPU time and total memory usage, I devised a I re-used the image resizing code from the benchmark app but processed the test images only once, using `Parallel.ForEach` to load up the system. Because of the test image set's size, startup and JIT overhead are overshadowed by the actual image processing, and although there may be some variation in times between runs, the overall picture is accurate and is more realistic than the BDN runs that cycle through the same small set of small images. Each library's test was run in isolation so memory stats would include only that library. -This table shows the actual CPU time and peak memory usage as captured by the [Windows Performance Toolkit](https://docs.microsoft.com/en-us/windows-hardware/test/wpt/) when running the modified benchmark app on .NET 5.0 x64. - -| Method | Peak Memory | VirtualAlloc Total | CPU Time | -|------------------------- |------------:|-------------------:|----------:| -| *MagicScaler Bee Heads | 404 MB | 4749 MB | 50053 ms | -| System.Drawing Bee Heads | 849 MB | 36435 MB | 201269 ms | -| ImageSharp Bee Heads | 7459 MB | 27575 MB | 161416 ms | -| ImageMagick Bee Heads | 699 MB | 17481 MB | 291919 ms | -| FreeImage Bee Heads | 612 MB | 16408 MB | 232971 ms | -| SkiaSharp Bee Heads | 991 MB | 26368 MB | 190533 ms | -| NetVips Bee Heads | 443 MB | 3170 MB | 130149 ms | - -A few of the more interesting points from the above numbers: - -ImageSharp shows relatively low allocations and GC counts in the BDN managed memory diagnoser, but it is clear from the WPT trace that it is allocating and never releasing large amounts of memory. In a repetitive benchmark, this might not be obvious, but when working on a larger number of larger images, it will put a major strain on memory. - -It's clear from the CPU time numbers that System.Drawing is spending a fair amount of its time idle. Its total consumed time is roughly the same as SkiaSharp's, but its wall clock time shows it to be roughly 3x slower. This can be seen in WPA's CPU utilization graphs but not in the BDN results. - -NetVips shows higher CPU time in the WPT trace than it does running without tracing. Its wall-clock time was almost identical to MagicScaler's on this image set. Both Vips and MagicScaler lazily evaluate requests for pixels, so their memory usage is significantly lower than other libraries'. +This table shows the actual CPU time and peak memory usage as captured by the [Windows Performance Toolkit](https://docs.microsoft.com/en-us/windows-hardware/test/wpt/) when running the modified benchmark app on .NET 6.0 x64. -
-32-bit Process Results -
- -Because the peak memory numbers for some libraries are so high, it's also worth looking at how they perform in 32-bit environment, which is naturally memory constrained. The following table shows results of the same test for .NET Core 5.0 x86. +| Method | Peak Memory | VirtualAlloc Total | CPU Time | Clock Time | +|------------------------- |------------:|-------------------:|----------:|-----------:| +| *MagicScaler Bee Heads | 420 MB | 2389 MB | 37153 ms | 3.99s | +| System.Drawing Bee Heads | 1001 MB | 36449 MB | 156050 ms | 39.58s | +| ImageSharp Bee Heads | 1079 MB | 1101 MB | 96510 ms | 10.76s | +| ImageFlow Bee Heads | 1485 MB | 28843 MB | 209247 ms | 22.61s | +| ImageMagick Bee Heads | 878 MB | 17426 MB | 277780 ms | 29.86s | +| FreeImage Bee Heads | 1048 MB | 16398 MB | 198207 ms | 21.77s | +| SkiaSharp Bee Heads | 1273 MB | 26371 MB | 110919 ms | 12.13s | +| NetVips Bee Heads | 785 MB | 3029 MB | 43515 ms | 5.01s | -| Method | Peak Memory | VirtualAlloc Total | CPU Time | -|------------------------- |------------:|-------------------:|----------:| -| *MagicScaler Bee Heads | 361 MB | 4747 MB | 57250 ms | -| System.Drawing Bee Heads | 769 MB | 36405 MB | 219007 ms | -| ImageSharp Bee Heads | FAIL - OOM | | | -| ImageMagick Bee Heads | 701 MB | 17381 MB | 359497 ms | -| FreeImage Bee Heads | 671 MB | 16393 MB | 264883 ms | -| SkiaSharp Bee Heads | 944 MB | 26366 MB | 288483 ms | -| NetVips Bee Heads | 424 MB | 3277 MB | 94891 ms | +It's clear from the CPU time vs wall clock time that System.Drawing is spending a fair amount of its time idle. Its total consumed CPU time is middle of the pack, but its wall clock time shows it to be the slowest by far. -ImageSharp failed to complete the test with less addressable memory available. - -Once again, MagicScaler is the most efficient with memory and CPU. However once again, NetVips completed the suite in similar wall-clock time to MagicScaler, so its CPU time may not be accurate under the profiler. All libraries that succeeded took longer in 32-bit mode, but SkiaSharp was disproportionately slower. - -For the record, here is the exception thrown by ImageSharp: - -ImageSharp -``` -System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. - at System.Buffers.ConfigurableArrayPool`1.Rent(Int32 minimumLength) - at SixLabors.Memory.ArrayPoolMemoryAllocator.Allocate[T](Int32 length, AllocationOptions options) - ... -``` - -
+Earlier runs of this test showed extreme total memory use in NetVips and ImageSharp, but they've both brough their memory use way down. MagicScaler still manages clear wins in peak memory and CPU time. MagicScaler Quality ------------------- @@ -230,8 +262,6 @@ The libraries tested in the benchmark have different capabilities, so the option The net result is that if you look at the sample image output in @bleroy's [blog post](https://devblogs.microsoft.com/dotnet/net-core-image-processing/), the MagicScaler output has different colors than all the others. 10 of the 12 images have washed-out colors in the output from the other libraries -- most apparent in the vibrant red, green, and blue hues, such as the snake or the Wild River ride on the back of what is now the [MoPOP building](https://www.mopop.org/building). If you download the project today and run it, the outputs from System.Drawing (corrected by me), ImageSharp (fixed in the library), SkiaSharp (fixed in the library), and MagicScaler will all have correct colors, and the rest will be wrong. -The recently-added NetVips test has the same problem as ImageMagick. It would do option 2) by default but would carry all the metadata with it and so has been written to do 3). Like ImageMagick, it could be modified to do option 1) instead, but that would require much more code and would be significantly slower. - These are common mistakes made by developers starting out with image processing, because it can be easy to miss the shift in colors and difficult to discover how to do the right thing.
@@ -239,23 +269,23 @@ These are common mistakes made by developers starting out with image processing, Sample Images: -| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   | -|----------------|-------------|------------|------------|---------|-----------|-----------| -|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp| +| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   |    ImageFlow   | +|----------------|-------------|------------|------------|---------|-----------|-----------|-----------| +|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp|ImageFlow| The color difference between these should be obvious. Compared to the [original image](https://github.com/bleroy/core-imaging-playground/blob/master/images/IMG_2525.jpg), it's easy to see which are correct (unless your browser is busted). ### Gamma-Corrected Blending -Of the libraries tested in the benchmark, only MagicScaler performs the resampling step in [linear light](http://www.imagemagick.org/Usage/resize/#resize_colorspace). ImageSharp, ImageMagick, and Vips are capable of processing in linear light but would require extra code to do so and would perform significantly worse. +Of the libraries originally tested in the benchmark, only MagicScaler performs the resampling step in [linear light](http://www.imagemagick.org/Usage/resize/#resize_colorspace). ImageSharp, ImageMagick, and Vips are capable of processing in linear light but would require extra code to do so and would perform significantly worse. ImageFlow is a recent addition which also processes in linear light by default. Sample Images: -| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   | -|----------------|-------------|------------|------------|---------|-----------|-----------| -|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp| +| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   |    ImageFlow   | +|----------------|-------------|------------|------------|---------|-----------|-----------|-----------| +|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp|ImageFlow| In addition to keeping the correct colors, MagicScaler does markedly better at preserving image highlights because of the linear light blending. Notice the highlights on the flowers are a better representation of those in the [original image](https://github.com/bleroy/core-imaging-playground/blob/master/images/IMG_2301.jpg) @@ -267,12 +297,12 @@ Most imaging libraries have at least some capability to do high-quality resampli Sample Images: -| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   | -|----------------|-------------|------------|------------|---------|-----------|-----------| -|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp| +| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   |    ImageFlow   | +|----------------|-------------|------------|------------|---------|-----------|-----------|-----------| +|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp|ImageFlow| -FreeImage and SkiaSharp have particularly poor image quality in this test, with output substantially more blurry than the others. +FreeImage and SkiaSharp have particularly poor image quality in this test, with output substantially more blurry than the others. ImageFlow benefits from its linear light processing but also produces blurrier output than others. Note that when the benchmark and blog post were originally published, Skia supported multiple ways to resize images, which is why there are two Skia benchmark tests. Under the current version of Skia, those two versions have the same benchmark numbers and same output quality, because the Skia internals have been changed to unify its resizing code. The lower-quality version is [all that's left](https://github.com/mono/SkiaSharp/issues/520). @@ -285,14 +315,14 @@ Finally, MagicScaler performs a post-resizing sharpening step to compensate for Sample Images: -| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   | -|----------------|-------------|------------|------------|---------|-----------|-----------| -|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp| +| System.Drawing |   MagicScaler  |   ImageSharp   |   Magick.NET   |     NetVips    |    FreeImage   |    SkiaSharp   |    ImageFlow   | +|----------------|-------------|------------|------------|---------|-----------|-----------|-----------| +|System.Drawing|MagicScaler|ImageSharp|MagickNET|NetVips|FreeImage|SkiaSharp|ImageFlow| The linear light blending combined with the sharpening work to preserve more details from this [original image](https://github.com/bleroy/core-imaging-playground/blob/master/images/sample.jpg) than the other libraries do. Again, some details are mangled by the poor JPEG settings, so MagicScaler's default settings would do even better. -Also of note is that ImageSharp's thumbnail for this image is roughly twice the size of the others because it has embedded the 3KiB sRGB color profile from the original image unnecessarily. +Also of note is that ImageSharp's and NetVips' thumbnails for this image are roughly twice the size of the others because they have embedded the 3KiB sRGB color profile from the original image unnecessarily. Versioning ---------- diff --git a/src/MagicScaler/Magic/Processors/ChannelChanger.cs b/src/MagicScaler/Magic/Processors/ChannelChanger.cs index f2ae7fd6..4600e88f 100644 --- a/src/MagicScaler/Magic/Processors/ChannelChanger.cs +++ b/src/MagicScaler/Magic/Processors/ChannelChanger.cs @@ -554,9 +554,7 @@ unsafe void IConversionProcessor.ConvertLine(byte* istart, byte* ostart, nint cb var v0 = Avx.LoadVector256((byte*)ip); ip += Vector256.Count; - v0 = Avx2.Shuffle(v0, vmask); - - Avx.Store((byte*)op, v0); + Avx.Store((byte*)op, Avx2.Shuffle(v0, vmask)); op += Vector256.Count; } while (ip <= ipe); @@ -572,9 +570,7 @@ unsafe void IConversionProcessor.ConvertLine(byte* istart, byte* ostart, nint cb var v0 = Sse2.LoadVector128((byte*)ip); ip += Vector128.Count; - v0 = Ssse3.Shuffle(v0, vmask); - - Sse2.Store((byte*)op, v0); + Sse2.Store((byte*)op, Ssse3.Shuffle(v0, vmask)); op += Vector128.Count; } while (ip <= ipe); diff --git a/src/MagicScaler/Magic/Processors/Converters.cs b/src/MagicScaler/Magic/Processors/Converters.cs index 40fed105..e84c428d 100644 --- a/src/MagicScaler/Magic/Processors/Converters.cs +++ b/src/MagicScaler/Magic/Processors/Converters.cs @@ -324,13 +324,13 @@ private static void convertIntrinsic(byte* ip, byte* ipe) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void convertScalar(byte* ip, byte* ipe) { - while (ip < ipe - sizeof(nuint)) + while (ip <= ipe - sizeof(nuint)) { *(nuint*)ip = ~*(nuint*)ip; ip += sizeof(nuint); } - while (ip < ipe) - *ip++ = (byte)~(uint)*ip; + if (ip < ipe) + *(uint*)ip = ~*(uint*)ip; } } diff --git a/src/MagicScaler/readme.md b/src/MagicScaler/readme.md index 24b66510..bfb3e296 100644 --- a/src/MagicScaler/readme.md +++ b/src/MagicScaler/readme.md @@ -10,9 +10,9 @@ Speed and efficiency are unmatched by anything else on the .NET platform. Requirements ------------ -MagicScaler currently has full functionality only on Windows 10+. +MagicScaler currently has full functionality only on Windows. -Work is in progress to reach full feature parity on Linux. A growing collection of codecs for Linux is available on [nuget.org](https://www.nuget.org/packages?q=photosauce.nativecodecs), and at this point most use cases are covered. Notable exceptions are support for BMP and TIFF images and CMYK JPEG. +Work is in progress to reach full feature parity on Linux. A growing collection of cross-platform codecs is available on [nuget.org](https://www.nuget.org/packages?q=photosauce.nativecodecs), and at this point most use cases are covered. Notable exceptions are support for BMP and TIFF images and CMYK JPEG. Usage ----- diff --git a/src/NativeCodecs/Giflib/GifDecoder.cs b/src/NativeCodecs/Giflib/GifDecoder.cs index cd55c18f..f44ef999 100644 --- a/src/NativeCodecs/Giflib/GifDecoder.cs +++ b/src/NativeCodecs/Giflib/GifDecoder.cs @@ -328,12 +328,6 @@ private void dispose(bool disposing) if (handle is null) return; - palette.Dispose(); - palette = default; - - iccpData.Dispose(); - iccpData = default; - GCHandle.FromIntPtr((IntPtr)handle->UserData).Free(); int err; @@ -341,7 +335,15 @@ private void dispose(bool disposing) handle = null; if (disposing) + { + palette.Dispose(); + palette = default; + + iccpData.Dispose(); + iccpData = default; + GC.SuppressFinalize(this); + } } public void Dispose() => dispose(true); diff --git a/src/NativeCodecs/Giflib/GifEncoder.cs b/src/NativeCodecs/Giflib/GifEncoder.cs index e3c2ef4b..56840460 100644 --- a/src/NativeCodecs/Giflib/GifEncoder.cs +++ b/src/NativeCodecs/Giflib/GifEncoder.cs @@ -176,6 +176,11 @@ private void dispose(bool disposing) var gch = GCHandle.FromIntPtr((IntPtr)handle->UserData); + // EGifCloseFile will attempt to write GIF trailer byte before cleaning up. + // We prevent that during finalization by taking the file handle away from it. + if (!disposing) + handle->UserData = null; + int err; _ = EGifCloseFile(handle, &err); handle = null; @@ -206,6 +211,9 @@ private int writeCallback(GifFileType* pinst, byte* buff, int cb) { try { + if (pinst->UserData is null) + return 0; + var stm = Unsafe.As(GCHandle.FromIntPtr((IntPtr)pinst->UserData).Target!); stm.Write(new ReadOnlySpan(buff, cb)); diff --git a/src/NativeCodecs/Libjxl/JxlDecoder.cs b/src/NativeCodecs/Libjxl/JxlDecoder.cs index fe2e4ae9..7de50304 100644 --- a/src/NativeCodecs/Libjxl/JxlDecoder.cs +++ b/src/NativeCodecs/Libjxl/JxlDecoder.cs @@ -228,17 +228,19 @@ private void dispose(bool disposing) if (decoder is null) return; - iccpData.Dispose(); - iccpData = default; - - exifData.Dispose(); - exifData= default; - JxlDecoderDestroy(decoder); decoder = null; if (disposing) + { + iccpData.Dispose(); + iccpData = default; + + exifData.Dispose(); + exifData= default; + GC.SuppressFinalize(this); + } } public void Dispose() => dispose(true); diff --git a/src/NativeCodecs/Libpng/PngDecoder.cs b/src/NativeCodecs/Libpng/PngDecoder.cs index 07019412..e8d1c021 100644 --- a/src/NativeCodecs/Libpng/PngDecoder.cs +++ b/src/NativeCodecs/Libpng/PngDecoder.cs @@ -351,14 +351,15 @@ private void dispose(bool disposing) if (handle is null) return; - _ = PngReadEnd(handle, null); + if (disposing) + { + _ = PngReadEnd(handle, null); + GC.SuppressFinalize(this); + } GCHandle.FromIntPtr(handle->io_ptr->stream_handle).Free(); PngDestroyRead(handle); handle = null; - - if (disposing) - GC.SuppressFinalize(this); } public void Dispose() => dispose(true); diff --git a/src/NativeCodecs/Libwebp/WebpDecoder.cs b/src/NativeCodecs/Libwebp/WebpDecoder.cs index 7375e4bd..2371122f 100644 --- a/src/NativeCodecs/Libwebp/WebpDecoder.cs +++ b/src/NativeCodecs/Libwebp/WebpDecoder.cs @@ -314,14 +314,14 @@ public bool TryGetMetadata([NotNullWhen(true)] out T? metadata) where T : IMe protected virtual void Dispose(bool disposing) { - if (disposing) - GC.SuppressFinalize(this); - if (!buffer.IsAllocated()) return; fixed (WebPDecBuffer* pbuff = &buffer) WebPFreeDecBuffer(pbuff); + + if (disposing) + GC.SuppressFinalize(this); } public void Dispose() => Dispose(true); diff --git a/src/WebRSize/WebRSize.csproj b/src/WebRSize/WebRSize.csproj index 7039ea5a..2580b425 100644 --- a/src/WebRSize/WebRSize.csproj +++ b/src/WebRSize/WebRSize.csproj @@ -1,7 +1,7 @@ - 0.6.6 + 0.6.7 net472 $(TargetFrameworks);net461