From af9d09f8ae7cd15ecb389bc9fd2b35adc78d79f7 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 3 Sep 2016 20:06:49 +0100 Subject: [PATCH] Ensure conv kernel scale is clamped to min val of 1 #561 --- docs/changelog.md | 6 ++ index.js | 23 ++-- .../expected/conv-sobel-horizontal.jpg | Bin 0 -> 19066 bytes test/unit/convolve.js | 102 ++++++++++-------- 4 files changed, 75 insertions(+), 56 deletions(-) create mode 100644 test/fixtures/expected/conv-sobel-horizontal.jpg diff --git a/docs/changelog.md b/docs/changelog.md index df4e6f42..96e525c7 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,12 @@ Requires libvips v8.3.3 +#### v0.16.1 - TBD + +* Ensure convolution kernel scale is clamped to a minimum value of 1. + [#561](https://github.com/lovell/sharp/issues/561) + [@abagshaw](https://github.com/abagshaw) + #### v0.16.0 - 18th August 2016 * Add pre-compiled libvips for OS X, ARMv7 and ARMv8. diff --git a/index.js b/index.js index 9cc908c9..98585510 100644 --- a/index.js +++ b/index.js @@ -503,22 +503,25 @@ Sharp.prototype.blur = function(sigma) { Convolve the image with a kernel. */ Sharp.prototype.convolve = function(kernel) { - if (!isDefined(kernel) || !isDefined(kernel.kernel) || - !isDefined(kernel.width) || !isDefined(kernel.height) || - !inRange(kernel.width,3,1001) || !inRange(kernel.height,3,1001) || + if (!isObject(kernel) || !Array.isArray(kernel.kernel) || + !isInteger(kernel.width) || !isInteger(kernel.height) || + !inRange(kernel.width, 3, 1001) || !inRange(kernel.height, 3, 1001) || kernel.height * kernel.width != kernel.kernel.length ) { // must pass in a kernel throw new Error('Invalid convolution kernel'); } - if(!isDefined(kernel.scale)) { - var sum = 0; - kernel.kernel.forEach(function(e) { - sum += e; - }); - kernel.scale = sum; + // Default scale is sum of kernel values + if (!isInteger(kernel.scale)) { + kernel.scale = kernel.kernel.reduce(function(a, b) { + return a + b; + }, 0); } - if(!isDefined(kernel.offset)) { + // Clamp scale to a minimum value of 1 + if (kernel.scale < 1) { + kernel.scale = 1; + } + if (!isInteger(kernel.offset)) { kernel.offset = 0; } this.options.convKernel = kernel; diff --git a/test/fixtures/expected/conv-sobel-horizontal.jpg b/test/fixtures/expected/conv-sobel-horizontal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f886a6073d6615f905ce02a7295a7e8c9ef865e5 GIT binary patch literal 19066 zcmb4pQ*Dac@F*z10vrM+0s;7oLuTQqG+cMCsU?yNaX2N-ZroBD8vp*Y zga-kD`hUIrbN9~_^gj(NIso#Y6G&(nsDFX{Zx|4e=;TmrVi;=B6eic0?7{VYlu5JV zE(JR`9O_?S01_0$zXYJr0V05xLPRJp1cd>4<&DXClBUZ!?9VykH5^bJ8rxm(knJOQ z@ZutnR83meP%>)x$(14fb-IYlEk#ZrsAbldbF%eZ8a@KX|(Cq7wV86;lTTd z#B8d4*8-oYu7+U@k70xrFmyn)G@8jJY0uVocBHpCo^XCSaSBdBlJol9!?a555{$eT zd*Dj_1^FA?7mSZxbYVCK9<(bI?JWthPplZR(f@_IzIUQopKOsP?dzjhjJZse715E3 zsuwZ{75h>3qXY<*b%4)%$B7(yax9K>EQRR0Q|$j9P9htzChT2V%14#e?n&-Ns8>60 z^=9I$qep=II4(UEB6(-wRP*m!5kTUAG#Z zXNM6^a{Xyy>N{1vJ{7r|>Z;Rjy}Zn2BEpcsJf-^r{JoqbnRq;tU%30}LKnZ|AFJrx z`+*XeR`+f-gDZ8Rm7fS$n)@>#zE?VQlF*IT@ACTJ^mK8_*zmOv6lAs7DLwr#Rf+<| zc1~CD50!3f*Qi*v#nheDeS)q<1Kaf3&9bK$NZH&l)H6*^$26bol*IRbvNf{D2W)4X z7hMdMLrFYvO>Wb~#gyPMmrb3{PsAdUixE)^zEfn)lwtXpYW54kqUc(|EO|YEyn%W= zy%?{FC>+OJ1})zprFpL1ZyuNV&EV)zJnN7abm1TA50_Bo% zlllP@*zG*3H#zV@@syGb2RgT{Dt_8f#los)+>Vk$&e~yrtjlrPN*kcc}bABni z(kpo3O%-}63WZ(S?Lgal2+_5ZsMh(Y4DU>Fu10*Y{l}EsLphf~p+df(8FpxZa$NFB zT$oLFX`6yv%{Q3=DGCO9$4X!~zJmvW9@T7-AY%5mWAEL_V|6qhuM-2s)T5sq_O@#^ z9`DPt>w>x=f6VN_{rY#U|4OYpYq(!TBS11vWI-kBr@mf&=}f2nf@V{-eixL6Efg0T zDhop{3`jEM(}09;Ioh_b$|c3&&m&K3zsE!l)rI0Dn~3~py)gE6vAP;S6qR7$RuvidI-i8Ayi9=%B>|Z9oG8EIIJ6?<)sZ>2PkP^$dZKS*YH>|f`XeD z9>1?LlCn#22jenPcAoE!VEHRm|3{Qtf_m^-SYf@v?HXa{>W_=Kk(cX=x*3*)Ai#)( z&C6AMn;N?lu}e)?3l-vDRX=3MArUY3qV4{+jKZqIS2DzLCJG-9<5GfmSNkxn2e7Fn zmSQAn`uP$$^@D|TPNd<%gEX}eO{EcJF33jZjun_0bbX=f6QzB&hmB<_^q)$2Og5<= z%inUiPcvDUaLA0Odc$lC+^OIww=C6?=-xBKWy%Vg8YX7^C25l%K)wpch$4Fo0Xev- z`DLtt?y`%h)bO>@D(E!irg}2y%KbdSMVN^Roe)`5x9laG_AJgqz3$VYa5G9M-lxh% z$Wyzx7eX_u*O+*0mIe;<2IS!bmESiCoJ5a+WpDM{OtK=Zyyd)o54T0; zv7uOs&Y1WlM&CpZB)W8zMfh9hgaXd=$bJ%mhJJww*T{+Ncl|sl(G_-~4nTqx`_8Ds z_nj!zOwMCIqdF@y(l>X{VC24>!!)LItKJ7JObI_ z3xKYCx$GGoNjHfDckGX-x~cG;@oD{UE3I&I;W^Oy@VwQQsae(soeksL&CojQo0cDu zI!Y5*Ndt>!hnns(LG4{{W+&nlSw=zNzN$QS>AV|oDl^Y@sErtjM`C2;aq>L^+@&{_ z!(+~sK|HaO^;h}}FqT1@AsqR#Bw;Xj&>TX^X<-o@tBv^1glthplPB3KV-+>8{vC%< zl(Gh-nqWXVb`fup^gt# zc)%my`ix1*fvb}gM_}aBY^-JO&OqQ};(<;595_!l7w?KHFUl?}3|fpX@7a7<-Aka% zp2JL5@^nQ8Fd}hzB~8+H)8F0a!@g*v6sE=tHOg`%#W%qT5C5kmgGbsx6qKm}@lnk8 zf}oGWT-W;r2%Y|HE>?S!y*qS~bu!k%a|PCr-9D8BQkh-J@`ozIlaX79ZwP)q6kGf~ z2x3HGWEJ67QCuqJo=gq&J`G?bHbQoPVRYbOo~9j%z}EE?Ycu5s#ndZo`>&D3psE_S zGN0t8sl7y}_n!|rurxS}2fUQb-EFPMN4BLTlz2pb0qDI|c;!7~MYc+TpIAS>04H3A zqdU;!5NV2)V>ex*#w4+VRfUn5Z7%6(N3@e2!Jrv0_MC=BsiQVmj@zQa!QFKVR$O^v zL;3i&lX>vZQ5z%qLxaAq{iAba6&Krj1O4LvexC|V`5^hu@?fs;=Hf@2k@RsZ zjz36qpu6B$hjRfWnwv5;49F7@yrWQD7OqJK8Rpj))Sy6v!=DI)Ax!pK($26mDD)<> zv6+?v{3!>D+G`XJgx76-$F|z3ctoSYu@QMG64~ zgoL^z++GRY0l8(H`7K@zO%XN{#(zjc!8M)6yPt@D5f;ou^4P)Kb!BJbkxai%=M~zG zI^WbPH`fhSpn2|~=r*=x$XtO1yeD_%Ob>{i)+LdU<|3PY{6}Y}3}rw;we;3x>XBqm z8?1`xC!(CPcm`j+z=*kQA`FE|zo+kK?~&9cakpvBDLX8EpSzydt?xA-$RI=gaXSGC z7eX0|Y-|(x%R-(w>5s{reYatGYA)Dh?A9I)K?c^?Ai*HYlk*^XOLLsYQ71t!w0gNB zr=_7lxn#s^o%;A zgQc;0&5GaDBHKHR|D^pec_`>Q9Xt9sk_|C=DG(Ze?}(|H#`c|+*IE5_BG)#*VXWwq zrP0SV4DM*)5)gEg7yQ)Bl?<>ehmgHSRh;*KE;$xTNFzHFh0)1d-9&l_`vSbD=fdey z(2nP&i8*>c6)kZ{i{ZRQsP{IM;*waVB{Tq1$Tzc4*fj8>{Dozv@>+N=rf$+5VQ~0i zHFinTisv`JEA7>~C8Sx}-ifEM33?Dz;b^6d!YqdzBz(uQ719aZ>LNygE98RdrNuLr zr6}wme#m#)RD~#RGfUpUcns>a_Q2ae$bzZ|ss~gu<6-~F(ZBOz56v?yt(slMW5=lF zN3&i-{M`}TxK891vz;h7BC=G&;3>63(G^QTF?DMv2PM9b<|^y~N$-h}--!7Gs3A%H z`&s!_8xC(raP(ofq6)*2PpW)zJDF~FThqf~RV@3c{B^+#X9>}!18k`fVFACpognxH z*h*7Zd!=sj0(Ym?4CJh1OjKSR!{b-4Yhu^LX|8W@**A3fU2t2qEKp)XvYH#YvhCZ7 zl``-CtP!!VXWyBhgxh;4z9?C!0C%fObYSWJ!UjsI^?ty>6rXXN+`*%xF9WbC0m1St zpanhWmXdnx#oV{d!f<)na}7IZShh(SAC|Wvg`lyY8#F*FRFNa2;Oh=6+npE(?7^NA zpa?v9pZx>a{|w!v*hs{>U~W;Mb1CqgDbf)y9!7mpy>mN91(g?MA=E9ut*9@`%hW@D zB59*lzrMvVvE#6C=_%+f^H9|ML2)MC-QBoImJI%+(Y(wwPC6BmA-1;TH4{)5mkIwb z_-$odt6r|Q^xAD~_tlQPJAXmCc1Fs^mMj8V0L{bXaQH$Lig8WG(PblEhA8_^%guMA;UXT!*hw*QVDNi!LBDLua}ajo^y*K83aliaOehJ`OX)v5)~_k zr+OGg{MP?Z7rpiiAb;7`TiZ))4fV&fxG7f7HD-Xpib*Ar*jBi-+FjqxeYw6ed9)s0vg)NsdS)a)kP-cO{?^7 zJjT=G(LkwGFX9J7%Qkk}`2PL@`ioY^WN#raq)fGq~A9RH{ct6F!N48SoZc&cNv4|($i4h7* zv#<1tl&B{=1MaJG{9z5*GAdeB10yP?!voHkQQv3FqCiy?vL)&81Bo2cH;JIs?U?xu z1Ea^j8sskgB?k)XP4c}Q+?=gDI@pFDqj#+qyY%zY2nRB1t^j$m`L><>AD@~e;T?JQ zTHQDco#@0?aBa>XD;62{JBxJ=K>J<(5HZqz8IM@rgsp|x8?AuCa{-%lmooy%lk#KC z>|qb|ss48q!8r57+5P#$=6MfzV>J)QjJoX0=5=_$D~@3qiAj2h!iBzUgaWVQVGQs_ zQ1-~oWtkXRvB-wbG+4RhHT!daIho9`L`+;-rWq>0jXq1NZR1ZqaI6~@bU_mA^o(6< zt*6PBJ8NXvlvSJ}?zed%XZ^@_+_u7d@1!@bd(z??WVN&WP1mtB%QBwP+1pgar@KPl z5Rn|Oy$j2830E84NfRDkWK-6&;tTM-gj?41-#{nQW9$Qm0xL9~Cg&k^S$MFIq|S~D zFfkk5_S0alzNEe)pc<#(jOU1}goDmgR;FLuRMgq-n&)!Bz}9(S#@)rONamAgeR|?* zXgQ~~dNUaGBd=p_sqAMv0T-bELM@b=NjbKg#F(?_NL~-#lAcD{V(sUvFf`I^#tHA- zMQDicyp`4_76Tx?9_Gw2T`GZ@fuQrHGOmbrGoiF~NhqSKcp!a?@f&WQ4u1_@J1QvQyl)2#`W33ZA*hOO2MMGXUjWkw;ep3w2U0Cn z&(Ar;umctfk#tF68D%9Pes$B|xel|n93Yw>y7KfAp z@quF{;aM1sLj&?Pi9t*0k6b7Xf7>F|+GVcuxL!%;fm1cLCFZ5O$MG<6neaU3xgjlj zJT_r1$OU$EPkK}akzJ)`OnVN+)5W^m?Yer zw8WM&>idbAJZ+yJ?jU&o3-GVA?>w%vGjf$-x)p8dvVIhQzk!T+eBM9tHD*ZYb<$1csB+~vf9wfA{M!-;o&9}d^Eqc^78NLxg&fg`d=#@u zr!N4EyVeD*{ZtCU_QslQ!N2JN&p2=!q1WTKF8>R#YPrOy?=*mH^24U-f+!5?-Bgo7Pi8DLx+{|N=ef7;J-p7kBdBT=YB7b^%3Sj>mcq)#{;B&N8V{s{+i9E@Qtm0~&Rm+YR1=)rxLEzHelCC*&RX4E=Zg1yBrm)3eJFlbh!}&U(Ds zz)bveXpdS$yc$*G5kE5xR$gj1q@a(ztNgT?a-~q2@k0=4Tq;s|XIT73OM~a}^S+6L zq>Nkn~tKqW+l71oUWSq;xp#X3e^^o=Pn6E<0=Nw$#7b7w-72C z?>#SAU4gQQn~P2#*}jhooNU9_;c)dy68$C><$Eg1uV3&3m7fx94D76oJY}Wbk5plB z)SEi<*Hb-G=&bfM|I_|4+Yl`57v&boJa+#)-^!s?RG=MeaK zSp|8^Goq@lC2UriwB>LSa%E<2GFL{HF48h4^aM76ij)&`xOIt{FA+w`j)}^zD}+Pm zYGKo8N^jTYJ1;E|36cc`*kTi$0VN*o^4#@Tn~0mMkETXrXUR5mN;h~d@!lH|@a(SA zB4MQb^I(H-jslP$8H;fIhe?=*$J!V~P4y6O3hMsP_}>#rK)PVvtL9O&1uj@pd?zd7 z3b!vnRykzo-CcEQS-C&b<1)Yd$Hqn*#z60^#AvL=4vBbj&PNIC6$VbsE9QP+Z1XB@PGyI()vaji-eYTdE59T07^ zpAu%3s1lEqRfY24N8m#-NTGPLQwt$#YJiODhcYl9UnIXwbgZGmr45zg_uQp&B-lOX9QBof>0IlAQJRmJ|>r2xOwmSt&YQqx&5VU)S31YWSCzU6jVb}s4_ zLgY$Y7nnH+ft=@~`pQw$AG^D0O7{!EBud`*N-$`%EWWI+>xB^>W$M51Flqaym!Z|2 zHFH&6MqhTCzCTjWGI*u-`{WXc9YssaTYayu@%(dx;5p4%@0-&BS-0{!*k}~}mX9Q} zU;#5x@bvEykDewEZARD=OF#g9hg9o;{2sVY9x5jNl#ikDw_P7c$cy3Rf-pP? zOXby_d!$3kD6z<5)V0c8+|R)_OZDh}0(4&CJj1!aDjo3fxrjBo4mzWwUltF;v<%r_ zqPHa(eo8raF{C7t$r0i26jl@gDPY}b!B456LqtOxUNM$yj zGTnBf-y)>oU)~+*h!OYB_hst>;O|)-uhDa(gPTqi$mI z9K%@X|BaEUuhFC;8P~7VXi>YZZj3G5tCNo-O*#EMc>dq2-4Y=F1yFzIX^ikOc}9jk zmx6|I*(8j=l{PySi$zVU`R3?{Z@2nJ%!i@iH~x!rp)0S=VI-Mbxi>%*J8Lma)e}ty zm-w;OCBZ$O?(Y}iBcj2YzE+`4|U$&OV9_-r|)1 z*$V?QG$8#o_}ymil(_Q(n%m0@!{{-gDZ@p~#fNO&Bv}5QBq$ZbyEh7AVQK9~eZ%}6 z_|BAtB}u&4>so|QmT-!!71THxqyHFk*4)6B)I_MuLe?Ob(P3I0hWa95m0)Y5psoC` z=x?1%9ud>i(*9I<>dUI?yttWl)yD0>bapC)W_iVGdHk{f9*LGLq)2UuP z2}kM_4&}blgeNu8?L7ZQ*WX%5KxJuLJ3f5q|Ij!9M5KzO2N$DA!oJ(!5F9A_yVh9C7R$8!C6}z+~h$I28?z(`EB%rL=|ua zXYCR()}s&S(iNe~!n~H11sG`)sa7PiF9x;MtET2LLu>IcO2);} zHK)$&g)^tEG98yxV)GIM+36sZY+-Z5ik$`?%38n+DZAEH zhU@MNVA-@<$3;jDuFiO?UeeWvt34fS7uFFx0yll+U$k^rou%t7bTkiSJo0;oY@X;a zWmjk$#4Ahm$Q=#X@&Bgsr0`Cl$7iE^fDVy;sM+Dnvj6Mrn5TT8nW%DuY^=q4Ejx>& zEM~0ibNAjPG{8sz05ZVSE+>69d*z=}a@vPU-#l9Z+KS_?P@ES2l4QhA{jH0rLoIDmpbLRC zLejij;eqe7SapV3(;M^m7JiS2rut#03I*copYVhi3+&#*1%LPUmFz_bAN&k8^pgB| zTsR16I$PSq@ly3&SXV^v`S?h5u)~fPtCQE<40-QQT9ykE>)Qy*c4p?U9JyI?f_hd+ zbi=B4B}ut}?~5saLU)|3S~og7T*KZ%V-`F$WYX^%H)<9>p*L)N9SZA{is?5LsA7_m zPS;afC+I5?M=qAPcY@Onti^uyQQ?}(LhU1jULrftl`p6zrT?gytjJIg>j^0+EyRdem{~hjL$Clm8`qR8vTNF0zMPMM*<2PbKsPE`Q zws87ctmz{$_d(x&{kf03l00S!H2^2NWn>$k`U6$f4&;WNw$TJ{d4ai^JUdLQv^vD& ze;V>S7a+WIacO2^rx*{(XhwQpH-a>#EwhrOx%X+ zG-ObC{UiU-j~gqmd8`gdt0rzSpNRrzYi1$r%b0i>H}aze>7k!9*|)H3|zi>jb#`TPUE;|WWiR?a3CjU=3B8Aza8~JvI;@^rKQa;KqBfG zT%5E2%YC)`?2`sNj#l6MNMG;^!IEuO&XLvrJo9<2fdoqiaG*cCc*Yz$qXTRN} zWDTQ6PF}RagVAG%dtZ$-Gg&n5W8>zSEXROHr3(Q|yRm!-S0vZ$lF><0s9ZuE_h&D| z(tQ38kw^D8B^B%g@VfrJs$#F)a3VxzLW$4K{FPFDJ6o%(@pIw8LqhjuYtY$l4NPfs z?dqxTdF&Hn@t_mTK=|*Q(#=B_{%vT`bO!#J=A;*;J{6xmL*`w|So%imK_~5@wR)Fp zD`kn4uQNJInqWG|hGVP@_V11%9|lXby`#2|a#^xuouedHXgcBs|DP~>r+=eb{xfAA zHDBFerHv5y32{3DJW*SFO7_Y`-Uuf?oR0@Wy=t`J!8f)}#j<(%fCqDV1nmsPd#<4u3EyhSOZCPvBr{TmX$Iw} zWD9}Wk)mZ=5w!1385k8x(#+LS@HlIz&`&>;@?KnR$5qaaYCKkQRGKF!e#+Hn>K{t? z3&zEx`RqAY+Evv4C)d>a3+wMKzS@r)HeR6c0w|7S`3rDeuCgm!VOik4@y& zn1rym4l6R%#T-rC#w4I6!IPGxD;;g`hT%d zu)a-aFXi3D@LF6T>7{4KM03hHIgjpqbElNaH1EYzN|5v_rB(aFM zw!R{tKTH+wS@iosi|m7uIiT#Ft5>PtTymH)bT$-CO4^AkSDzeD=$;COGDKM#bvh=O zvn?)-Iu~z=GoYXRHz|2f+oz^NyNkcGf#-5#&Ru4=e(;ZPyB^1fHx3NxY&1T`g*!4%gIu}$)?xW(N7p|k(pk3j3g6mGo8{UE)%~&AWKrU)NjcUGfFO~-{o|)a zSJIEIngJ4;)*G6`){{sMZxijjqj!&$<7Zkih(3#`{|F=^N%r26Tby{jd^JdPE{sh` zKKsjsftZi4%k^1Sb`C7|2YGLf{o8wV{kY|{LVBtQHXMrkVIc|GF-+n7i^EiS*^v#(8om^W@tNiu6c?&zdtgX$u-D+jl$qE&?8- zXxAck7JV!!T}u=3vCOKEiE()fL+D2myWLGLwqP=>|AERm)<{loL+@V>L2s8}#8?iM znnqSZmcajezBbHlW0d|-mN?LS(fiC$6lTPTjWF9QSViq%p0q{=THVlqN)7TL-sRFI zE9;WtFA*vx;Ln{^iISCoo)m-3PHGyGOd>Fu!3k!T`aEe>`f+@6B$kr*xJa<>!?uNp z$(6%>2rPHNF)`&^UnaLRVat2=3X;L6@%g*bbNLo0pwdUyrFfL5wOe7D(V4Rndq8Cr zu#j-3N37`ddp>fXZ51l`Xta_L4ra5!$?1SInv~ebn1Pe@q{8=4ds)=?%9$VsW1Q}y z+(n(=t?_v5L46qC?kmmO;ec~BZ{K-4F9PcrKDE0toZdS}NJ|-dT;5bsOBo7(OXg)Z zpQ~7x{bMFHO*$?kbETfK%+L0o{-I!JT>Jw@ZG2q5)qOl`l<1m$*uRQ4@@uc(lYW{~ zndaI7oo$5}HrGeYUDX@b3cPVua^w7K$R{*{@VN8YmZds(D13%AlroFdbCy3r^FJ~L zm7L1;{v2d+yrd0h{l2>;BPpzEX4G-W+jDQZa(`*91Rm^+P?~)KqM-VYU6S%|4 z?;;o26OM%nR?{BrakJCt$6`;Uwj(&`!1mt(^?8T`>xrmIB&Lz5JO)9>3tin9Ux2*h zkjH~dBRS6EnF>m+O3)>v?io@IWCc_N;fWcb%R)xsf`@KLZ)JpZ2yVagkL3L6~9wbGaE%u-b~S zo0n^sf4$UD&o9!rFS8X2DmNchK2vbEDZd9-n;Ym33D!?`y|uV`r{sltnHzO<&`tkN z6fQ#dvHr5)P|w^FPNPK@dMv~MqB-?qmqoW=I^Xn$DzU@NQtBQxu|MfvH6=OqP*=(N z_96SGiK~%4*&3eg`UP;zo0!*fo|hhQh#(#N^K_IIxA4S<p$iHPXIz$4I})R_I7cX<8_@St{FUkz@~R*7qnuShvaiCuU~?8+cr zZK1>7t=+i|FOuQ6n2hYz0_r9EF^HJpCrEmHOAe-JDw^%odta)orv z(=^3p{cF}WzonIRqfSNdYoiV((&Y+uv*UD5=HuF-Us=&*Obc2 zsHc#Yt;h8r{Ti3X6B8Vlp?#CjIbI2hac)ZHWL)TV9;*Zx_G?9XhwFH&UQ7vc>x)iW zCHs&|D&fbo9aKwYUWhP+J)~S%GnHt1bIwZ@eNk1G?~5PV(|0_Vxt*mC5iR_FJS)Eq zaKGj;-2eF-rz|VL@thVU^ieIoC&}-xb(<66mAcm}_*m|geq$t-T$gD5)+%Zyn^YK_ zD$J4Ftt46Ghs*(5NzMBL{LD{KliSI((N?g`4^FwBJBNNH32du&0i|XL!^?mkgqvhh zmem-VVot*G%o5AWgbfIqF0`^cK=*3k5#16Hr56>{nMB^HRbEhXs*?&)pxrY^H^_?w zf9h(k$OC*3fJ{m;NtVdOHc|iMd^SF}G@p?uk+W0R^V(&a%bZJeA@v5ITJ&@nK*Cq+ zorCK}kJwi0AB{JChXrR{#*RHA=*rI8k-$THPkUJr__yW1p*ynpSrr!%F|1QX z?)Ol>m&chZKc0Syy=XEd|d2amg}O-P}%Ks zSBg0a@SQddLa%Xj$3Aa$EVSFeO^eufMk_nRO~u8l7C%d?q zrD!BYo3?>gAz&XGsPeg+LbmbahDcFvyRe%8!{)T_Hk-xY(Nd!a4Y;J7=x%78B7SI{ z{<{^;5jG0NbpC7=BB|=Jv@q)MW9%s|Ya7YU_ut3^|6$+8X2(1vVg40hhnTI6ehX;! z=7k1msVP?#yn>=uOat^TDxVSBa?&%ssc}2!M{$M!E||5BG~F+^Z89jZ1#w9}({igz z@Ook!?sv-=|0@~!<|M#}YSH|w=^)#116)ZxHM=ciF%6t1X5?YNXqM9nnRkB#?3ShP z>PK|9W%&^366?0!ZF-DyQue%g7ou;M?zOq<)6~f+v&k#362!Bo*r+pcI^f*CX~e*d zt?ewk-*PV`2!<$GTQ1*!K>poRI-gLwX<%d?s$L&^zpZ$uKb4`W@Yt|b_yR<oX`-=dreoECR~QRFz+El z7E0u}D_i7Kvf_U68Mh+Ev9Tf10#Hi`{e$c)*#?Z!0zpPqi315^be+F7$=u!~0o*&& z@)>Q*oI3hzJkG6w)Fw`9M1&`#3G!F)*}6bDiG$wEw&|n?AKOtcfn6#s2rz z&R!e5^9{p}#;P7?1a z26}TJ$K7PHU0%-PH8j~A(SV{YkxvG?hGm56AQqW%thR=oJF3p~iNSwNVEyD*q%De5;nqjnEFX7BRMI05-$@!!dN(`qqLY zfG;uD1VV(@wMRNtP9Cbi+uTno$o1GE zTh8edo|(s)hk*7iq~Y&JC<@QJD9()L$ih_yn%70mx48{m@|d*$VZKccV1?&-Fg_(B z#n8+km8&yxn5^*DiNQr(Y>~nDmDTV4f=$Cj@&>v0?u5$Rt=%}SIkRRqNO(}LowxnO z)+!iOF$#l(-1tB~vinzUZ#5H!5+XLCorCYWf8>u9M^g;f6@t3Ky3`)WHT!M*GdDv5 zEqs(nJoKcUXUYzx+Ufh3O!|bZ?3;fWoMmwS8!*X7;^Fq!9ac#bz(y-$sXwyCc^`1c zKa-roMx(pApn?<*-v!lE=>^O>p zK@WqJUHuc2tUnJC)g?Z#`QJGkQ$6xRC>jT6yJD;sN6}FwZVhpK0roXb{5ose-|Lpo zv~DkwJ25!xu*cKv>kY#aTtX$1MgVRGU9H_L$~(hC!p+~9{7|TxibXr(WujjW}<#Cibds%DxRS;V}k0&M5zsH| zL7Ta@BK^7(@g0`p<)a0>LzusL-wB}2wK@9M z({eVF=@e5%Hwo2T&tVg+j>?55q8e>$m`+8LD z#aYQs;2B9USmi>Ln^KJ&5SnoqGoqjb*m}m9wYEhUedIIn#LKi7N8F0F7i$~9USCct zYD@Nat|h{cYzFY|M$c1RIl>-n!1Y?(?HiM}7k4*t&+;op9Yv4HIc~@lp{hxU8}>Pj zQ>`s@*`gqRyF4o6lrF9yN|YkF0kMZA1>)A-mK0|o>_JU)G5?9VOb0xK*s z1r>YqwQ+O9L>QO}=wMNj{TI;8Qc;87FZ*iyT}DbuO7E4>7tf>8IaJ|?@0E7GCEJ%Q zRvtl@`_a5tsLG;eLogy7tMKl_Jjp|EvRR0D$*0!LPx&4gvg|VBCz9a)0_!ZthTF~2 za$EMl4%;|qQ5u0z94S*WiNtQYAa*%2xH!%Yc>83IaHwM!?YR?Q&o~=F-;$>wAIb}y z$D_ah`K(`D%|IwSp0J5I&ak9Z$vEZP>bcq^DhYvWS@daSL9&)>CrL>v7g)&>r8;_R z6A5Mf|79+UuE(xpn=Nb`tB$*pYNX30f<T+zJ>X>L1#hAx@}O2#a%g_NrHV&Gp$qC4C0OITkdYN$7N2 ze(sjVw3lFIRkA?eE;LkZg4!TD)l{&fMJ(s}MRy7Q#t>VAm=bzJFR?sVlOtY4ufqUR ztjFyjXN9U@CsPw+LCIqwusJrmutz1*hVSzFBLMzH&uQ52OiBAj+o-28k>DGaI_Hglz6Jldy(5jTYZMgus90>lkbfhJXFoqJl6!$<~-T#(T2Ilh7O=9X_d zj`l(kJkD}bFIX9p&FS0g(lm`t9J+z%0YY0656c`!9u4F#ET<-{_2L7$+d-Y-$hNp# zAFQXyow4ns!4Q@9{OH7~zqIJ7gjh(oD$xGZG>Oj?2IFCfGiI)}L20ai*kM7Y{S~J| z$3Oj6$$nWy{~hTRQ=45tGXD6Zx5xC~)5XuOWW$YBwcyXtyt$vAD8UlRVK}@%a{tCN z71H-c2Ls~@CY3y45T}d3q~svV$zr<{5XNQcmp^5URSf6QI{lF_`NATGuBY$8{aN@Q z@4_4f(d_OLl)WQlxE|Ay<;Ip_{!|> zGjlAvv-=rk?ac~uf*O+hN6!J;uQPYD$P@801_`xnYVFXF@Jv3Y0X8>9&n_f;bmZPs zKDV{eJfWOn=GI!Y0*`l>+EZM|%5}&42>XW!)ho5KQRll(#Ya>1 zV8#tbfuL5#Fkmw-x9|jHucu!)t{d#CSp4f=LOFl5z8;q%kw;?qC)Z-3yh+zND8bl)U=^wh97o z;}&6Tx`k2O`V%~mcvfWvk5$C7)=#*s!#0~MxXp1Tn2_4Ld?O?#KHGCWc#P|nO}}ak zv$(CT)a60KV~UB2IJZ z+-s>$a1X;0F-Z%>*CucRSld2tbNgN~2){x$av#D9_8_%xsp{~Af9##o=~7*hx5hB9 zip?M;|6}o$GJp>^;aD7*sW1!-_}Cal!iMtcr)G~9JW3TfA9)HN@}Id4yj&_T)>rlu z(x?-S&n(!BzoTKS|CqacpJN?z)t*mq;%{w=7#i1Yi%_SH(J@OjkPouKWJOLJ)*7uW z&eGA^)w05c$>RG^bmSum$xpC5nUDkJ;=)MtnM~gn-wK6XI)<)-^~BLxy3`f;b~b)u zRH~GJHh-tV*Y8v(_DTFhouG22;%+?$Ykq|u%3ndWN0f50oM%hb%WUt+l6*j%9ff5^ z9m=xnb}{od8-{O>^C^3fE=RH6#!!ix**AS#gKBZX(kvi6vq?#b$JA@O?lcPO6_#-f z(kr~Q?C5NrHw9hcC|@XeyAEt8`$v+BGTK>H*yu4g>gaab!e4h<$`DGXIPxI~K@8JY z2FuGYQWT!FOo+-^8drwFnVG}CjlrJ=)-6T(iNAuPqye&XcHoM>}2vDFgRrvdt56us4cNDXyi6{JbW!x0B|tvK%HG`?mVr`t`?5 zAf)92-R}1u3e?3qspjiw>O)@HFf3*jysCD^QNuH4LaYrc#OHA^IWo3lkK*$L7p5H; zmFo>;aeNRWtW26{X2fV$f*9logyQRm&PfsBERGzNcZF{0OWJtqxr?CFIe7d?P9W`5 zQ)XAJ5)uc+VEc(&(c6%s6MjKo3kTjmB(`Kw%Kz26lAh6LD#K?Ah}t_*niQ~86vk>KbPKV-+z8>9IkaeUp z%aw!)FvZTIviIJ^zGM@raqDR|8h{HkO>rk~q_%{SSgLtxiHNp?{@cuCCDduOoi8^$ zK0}#5BodZ;)8^Z94Wto0{iR6%z6J~2TFN7G9qw5&ciEh75QWug2t0lo4`PTvmyd-$ z!MBQK*=CFD`Rp>DVUhZcFo-qs_(H8`J~|@OA^N(|I4%S(l%-@}E9{Lahr&L}b7f`B z#VeREixFeeOT}~~yXJQO$3ewW0hhJKnJg5998k6RdEv}uzF4fr?fbU4DL*5Ry+!Ko zTuJI1pvCv!=AxhoMh~A{X`xv%^COBLYIsqMn2MxnVji9POpk@MXlCpfC!+si*Fk?# z`Cf;mRH^d$;De-p;jrc3Mw*0o@d~>R1piL};|U!0icfJ}14VAvdVz#AQ8PKocG{rl zrA==OLGhFBbxURusbPl6Y+!mEZa+$8szq;eV%L$GAS@-30o#<$I{gpch?QnGSGMj- z%?pOO1-EyM8G$+V83XS_07)Q7&H&zHa~nQ<4B6wKObS5KpNW`6fk5uqH}3BA2hW36 zwgS%US6wxpNc3s$S)!4b#17J`LHX_D{jmUiAjy$qQ=}nqelTi!ZFho7rfywZwJgN2^(el9^lUQBI8sg?i z8t!yG2Ie6#kD)(0j7}L@_9I=|$oCV-$BDNxsb7~r&W*+wXArr9>H%_A5b`W6Mt8o# zRderxGwv#uIn)J7BT%ucU;)b(0CIm?EWvqW4xZ~HELULMK!Ex0X!-O$6Z9gVq}dj- zySUhmCAr==423Dq8`zA2>O}|{0z5I?OYqJNaYvLg4DLRB9+~Efjwoe<8*cHLN+O{L z8(q#=pI|a5nRI8Abzzhws$smk=-m( zL51$*C$8o#jDye>AEiTcIlk}boT5171sL4KkLj8yE`}Gn+&0M}?ql1W{#88V^)yDS za}C|hZX-yU;*2}5Oo8G!{{X&~V)iYjT-l>S*LF9c$r=yN;AKg`>E=K_R1Eg8{58*W zBD@y&B?E==?O;G-{v4?L`_mIZvm&5{q;-(W31Fuf8NfO6H8!OiAc2%QWsDNQakGG= z{{Y{mcAXRx-N$KnBEt-lg?oh?h~R;bZ1tzvvqNigq`Y(7#6S!@G9h7~w$grLfg$Hm zO+Qv!oi#G?6?J)hM6q8MeSAkErPQRBYj6BcS)`Frh)Fr!A#htiAk|Tp?$3t>$;%%x z)}*|V-auWqutAak02bCfeAg9R0o5&r6f~w(AtPDz48uoHL!rhR<9D zk-K@~$ zoHzhC)SRDe;+Y()Hj0{gR`1f}%#V&XlmLPM0Hhis`@BmlYpcQwURt|v!QCqfNW*)L zpy$|983cD0Nq2VgK>q*_C}vne!2=`&KV7Fj-t{%;w_P(&j%OoKoTI$NmrF{Bf9u>L*769+;#K^&Z@Ng(-Tc92-VsF2_=8KPY5oj$&NApV@i@Gr}kq* zhLIb4vz*33Bf@>UgHDFd31_>ujzFL~u$E5_*oI5sdGog)FM4%Y74k)MWMQ|qn8>}| z#B5_^JgEfkM)&9S6*RNQY|hPVnWTZEo+iOS89|Md^#mLrnD?jXM#d3ysA{&~6>k~a z9k%kKNeKr8jz9v1)Zn~!YrBlfvZA<}Kgo;_57VYRu|N);=9pQdswZ@!)DXBJ=XURN z&tE_)X)UIYLb!Xoh|wav?!~inER08qf${(#8TBHW4y7{5ZzuudwVpRwBuwCrc^>=4O#3UK1qvfM1yuY_g-O2%@e3WHlcTCZD|qivX=0GbGe((=1Hp8Ov!_of`i6AIQo)BJTYYi#d7f9cc}{P zl~`M|{{Uz;TMVkUQ^(yz&m@ZB zzj*@ZAbJCl_M(@(eHcpeY*+z`6;Xoa$=pfw#z)$o!rX@THI6tYihlRJkHl19MsmYp z{{Scl>sHpu9nPm?V*ywryS0uf`0z}?FU8>ro#2C@1bDxI=iv>acEOq&hIvz%`u-kYi2^5zOQX6(;ECyN<2;}>2VfV#O zEz3ha*2j)pOLUqkV_qc8p?A4G4qK0q`hygW1-8=mSbI)Ql*{%8iA%Bf%=%t(=O*8Ix{KN(TUpc>+iBqP0nq3!P%aPPv+U zc`m#&9}j;L7Qtcact3g$+8o=Hb0bF-fE55_z7Hqqf-_dq_d0}^lTNO-vD(TkTL2d- z!}EO@pS1%l@2{nwQnu4BZyj`quVWF+3+4(j=`cQ4%n~R5y83`NVLC_56&(LP891`1mhFhDt zZsvPwJK62xG9;PjXguxrcrG)6(6Jn!@e@g=G&(5Yy0(LO?n#rn?*}1MsmS>f zb4=7^M4e({Ww(XhVp4fA@Koo}=QR{pa$78ld@`Ap-3Y<(?il|7+(8v91-QAMF&vXl SiWU%qj3~z=) literal 0 HcmV?d00001 diff --git a/test/unit/convolve.js b/test/unit/convolve.js index c366da73..082b5a1a 100644 --- a/test/unit/convolve.js +++ b/test/unit/convolve.js @@ -9,18 +9,17 @@ describe('Convolve', function() { it('specific convolution kernel 1', function(done) { sharp(fixtures.inputPngStripesV) - .resize(320, 240) - .convolve( - { - 'width': 3, - 'height': 3, - 'scale': 50, - 'offset': 0, - 'kernel': [ 10, 20, 10, - 0, 0, 0, - 10, 20, 10 ] - }) + .convolve({ + width: 3, + height: 3, + scale: 50, + offset: 0, + kernel: [ 10, 20, 10, + 0, 0, 0, + 10, 20, 10 ] + }) .toBuffer(function(err, data, info) { + if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -30,16 +29,15 @@ describe('Convolve', function() { it('specific convolution kernel 2', function(done) { sharp(fixtures.inputPngStripesH) - .resize(320, 240) - .convolve( - { - 'width': 3, - 'height': 3, - 'kernel': [ 1, 0, 1, - 2, 0, 2, - 1, 0, 1 ] - }) + .convolve({ + width: 3, + height: 3, + kernel: [ 1, 0, 1, + 2, 0, 2, + 1, 0, 1 ] + }) .toBuffer(function(err, data, info) { + if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -47,36 +45,48 @@ describe('Convolve', function() { }); }); - it('invalid kernel specification: no data', function() { - assert.throws(function() { - sharp(fixtures.inputJpg).convolve( - { - 'width': 3, - 'height': 3, - 'kernel': [] - }); - }); + it('horizontal Sobel operator', function(done) { + sharp(fixtures.inputJpg) + .resize(320, 240) + .convolve({ + width: 3, + height: 3, + kernel: [ -1, 0, 1, + -2, 0, 2, + -1, 0, 1 ] + }) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual('jpeg', info.format); + assert.strictEqual(320, info.width); + assert.strictEqual(240, info.height); + fixtures.assertSimilar(fixtures.expected('conv-sobel-horizontal.jpg'), data, done); + }); }); - it('invalid kernel specification: bad data format', function() { - assert.throws(function() { - sharp(fixtures.inputJpg).convolve( - { - 'width': 3, - 'height': 3, - 'kernel': [[1, 2, 3], [4, 5, 6], [7, 8, 9]] - }); + describe('invalid kernel specification', function() { + it('missing', function() { + assert.throws(function() { + sharp(fixtures.inputJpg).convolve({}); + }); }); - }); - - it('invalid kernel specification: wrong width', function() { - assert.throws(function() { - sharp(fixtures.inputJpg).convolve( - { - 'width': 3, - 'height': 4, - 'kernel': [1, 2, 3, 4, 5, 6, 7, 8, 9] + it('incorrect data format', function() { + assert.throws(function() { + sharp(fixtures.inputJpg).convolve({ + width: 3, + height: 3, + kernel: [[1, 2, 3], [4, 5, 6], [7, 8, 9]] }); + }); + }); + it('incorrect dimensions', function() { + assert.throws(function() { + sharp(fixtures.inputJpg).convolve({ + width: 3, + height: 4, + kernel: [1, 2, 3, 4, 5, 6, 7, 8, 9] + }); + }); }); }); });