From b4d72bd5440f66f5d9ef20ffe9958c3c1a79d7a1 Mon Sep 17 00:00:00 2001 From: Matthew McEachen Date: Sun, 8 Oct 2017 01:55:11 -0700 Subject: [PATCH] Add failOnError option to fail-fast on bad input image data (#976) --- lib/constructor.js | 3 ++ lib/input.js | 10 +++- src/common.cc | 9 +++- src/common.h | 2 + src/pipeline.cc | 4 +- test/fixtures/expected/truncated.jpg | Bin 0 -> 713 bytes test/fixtures/index.js | 2 + test/fixtures/truncated.jpg | Bin 0 -> 10000 bytes test/fixtures/truncated.png | Bin 0 -> 10000 bytes test/unit/failOnError.js | 77 +++++++++++++++++++++++++++ 10 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/expected/truncated.jpg create mode 100644 test/fixtures/truncated.jpg create mode 100644 test/fixtures/truncated.png create mode 100644 test/unit/failOnError.js diff --git a/lib/constructor.js b/lib/constructor.js index 12617b63..c49394aa 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -93,6 +93,9 @@ const debuglog = util.debuglog('sharp'); * a String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file. * JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present. * @param {Object} [options] - if present, is an Object with optional attributes. + * @param {Boolean} [options.failOnError=false] - by default apply a "best effort" + * to decode images, even if the data is corrupt or invalid. Set this flag to true + * if you'd rather halt processing and raise an error when loading invalid images. * @param {Number} [options.density=72] - integral number representing the DPI for vector images. * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering. * @param {Number} [options.raw.width] diff --git a/lib/input.js b/lib/input.js index 3a0f534c..eabd147c 100644 --- a/lib/input.js +++ b/lib/input.js @@ -9,7 +9,7 @@ const sharp = require('../build/Release/sharp.node'); * @private */ function _createInputDescriptor (input, inputOptions, containerOptions) { - const inputDescriptor = {}; + const inputDescriptor = { failOnError: false }; if (is.string(input)) { // filesystem inputDescriptor.file = input; @@ -26,6 +26,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { throw new Error('Unsupported input ' + typeof input); } if (is.object(inputOptions)) { + // Fail on error + if (is.defined(inputOptions.failOnError)) { + if (is.bool(inputOptions.failOnError)) { + inputDescriptor.failOnError = inputOptions.failOnError; + } else { + throw new Error('Invalid failOnError (boolean) ' + inputOptions.failOnError); + } + } // Density if (is.defined(inputOptions.density)) { if (is.integer(inputOptions.density) && is.inRange(inputOptions.density, 1, 2400)) { diff --git a/src/common.cc b/src/common.cc index 024a163d..cd8dfbe6 100644 --- a/src/common.cc +++ b/src/common.cc @@ -52,6 +52,7 @@ namespace sharp { descriptor->buffer = node::Buffer::Data(buffer); buffersToPersist.push_back(buffer); } + descriptor->failOnError = AttrTo(input, "failOnError"); // Density for vector-based input if (HasAttr(input, "density")) { descriptor->density = AttrTo(input, "density"); @@ -219,7 +220,9 @@ namespace sharp { imageType = DetermineImageType(descriptor->buffer, descriptor->bufferLength); if (imageType != ImageType::UNKNOWN) { try { - vips::VOption *option = VImage::option()->set("access", accessMethod); + vips::VOption *option = VImage::option() + ->set("access", accessMethod) + ->set("fail", descriptor->failOnError); if (imageType == ImageType::SVG || imageType == ImageType::PDF) { option->set("dpi", static_cast(descriptor->density)); } @@ -256,7 +259,9 @@ namespace sharp { imageType = DetermineImageType(descriptor->file.data()); if (imageType != ImageType::UNKNOWN) { try { - vips::VOption *option = VImage::option()->set("access", accessMethod); + vips::VOption *option = VImage::option() + ->set("access", accessMethod) + ->set("fail", descriptor->failOnError); if (imageType == ImageType::SVG || imageType == ImageType::PDF) { option->set("dpi", static_cast(descriptor->density)); } diff --git a/src/common.h b/src/common.h index 96a577d4..874a4f2c 100644 --- a/src/common.h +++ b/src/common.h @@ -47,6 +47,7 @@ namespace sharp { std::string name; std::string file; char *buffer; + bool failOnError; size_t bufferLength; int density; int rawChannels; @@ -59,6 +60,7 @@ namespace sharp { InputDescriptor(): buffer(nullptr), + failOnError(FALSE), bufferLength(0), density(72), rawChannels(0), diff --git a/src/pipeline.cc b/src/pipeline.cc index 517b10df..cc7ecbba 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -249,7 +249,9 @@ class PipelineWorker : public Nan::AsyncWorker { } if (shrink_on_load > 1) { // Reload input using shrink-on-load - vips::VOption *option = VImage::option()->set("shrink", shrink_on_load); + vips::VOption *option = VImage::option() + ->set("shrink", shrink_on_load) + ->set("fail", baton->input->failOnError); if (baton->input->buffer != nullptr) { VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength); if (inputImageType == ImageType::JPEG) { diff --git a/test/fixtures/expected/truncated.jpg b/test/fixtures/expected/truncated.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0bd7b80827f892da77d9423bd736122d7bf12101 GIT binary patch literal 713 zcmex=Ev5E>}ir!-2VP*tc!Ys&Ok7oKPcj$${|C<1e C=Ocyy literal 0 HcmV?d00001 diff --git a/test/fixtures/index.js b/test/fixtures/index.js index 2876fd87..ee9aaa02 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -66,6 +66,7 @@ module.exports = { inputJpgLarge: getPath('giant-image.jpg'), inputJpg320x240: getPath('320x240.jpg'), // http://www.andrewault.net/2010/01/26/create-a-test-pattern-video-with-perl/ inputJpgOverlayLayer2: getPath('alpha-layer-2-ink.jpg'), + inputJpgTruncated: getPath('truncated.jpg'), // head -c 10000 2569067123_aca715a2ee_o.jpg > truncated.jpg inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png inputPngWithTransparency: getPath('blackbug.png'), // public domain @@ -81,6 +82,7 @@ module.exports = { inputPngAlphaPremultiplicationLarge: getPath('alpha-premultiply-2048x1536-paper.png'), inputPngBooleanNoAlpha: getPath('bandbool.png'), inputPngTestJoinChannel: getPath('testJoinChannel.png'), + inputPngTruncated: getPath('truncated.png'), // gm convert 2569067123_aca715a2ee_o.jpg -resize 320x240 saw.png ; head -c 10000 saw.png > truncated.png inputWebP: getPath('4.webp'), // http://www.gstatic.com/webp/gallery/4.webp inputWebPWithTransparency: getPath('5_webp_a.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp diff --git a/test/fixtures/truncated.jpg b/test/fixtures/truncated.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2a3fe7a7b597d075d5f44c7b6f25b6c359223720 GIT binary patch literal 10000 zcmb7pXHXMd&~E4*ArvWsbVz7|6e&^@N~j45p<|&X3PNatjVeuAAoM7N1d?DtN`Qb^ zL8%HMfG;8nFQA~HG!>NB&+pFMxxepo_Q#od=IoxcbK36ydGqH3Kmz9E>IC580sy%F zHo%{^07n21H~0U_U-14FK0!V{US2+70RetNQDIS05n&M#F>#=Tn7E|4h=_!&grtG(sDp)8R`F3!o~A<3@@J$AD@u4n24D4|2O_T0Z0l8whL2uxYPjLl3YBJ zTz>`uN`L3c$MqM0{|jC&ZXP~le~3w|Cx?ql2l9$qdWpQM^G zzm%$jv=Kr;-Tnej<~00#hM;3yI$le6*@$BVoQ=!ZqIW03J zG|b$o4E0yBA{T(?f6e|syMVuTdHMJS{*q@U0o;GV_19tCe1AO#5co?<@~8rh?0Kc& zYR2dJq~p>{9U9u7PN^fl$(&x&xPaT{H<2~Xz_b6%14Mba{w|P55?~A1t@-?U+qX(t z+s{~^Ces6+7LM^$GNoXC>S=XdlZ-z7&o@16aff!|XFDm|WBZ2cOZOrFmKfUSXb>eC z$BXd>#*J@>4B(wm=dG>aWh_tCCQ4a%$46+b(}eW=g?zG#2Im#)_E$uTMO3Q*Ef_?C z?T(kHjpVLxITzU3$2J$GcV)sj!-doyZ`hH`?0U3!I9!#DX)s{OWVL?6@0T^)aCthH zXoxHgdPu|f76%p>%`>cw@tPfro32?S_wHfqo>v7*>UC1!RZ`xclOgELF}m8&S;f~A zJTXuB^&#kRZ|6Cc4NzsavxeXaTtB@E%(Fst+B#9LHFMW-O7%`^e}}hkP3J;$$ENG= zzT=QVr#Dxc_)MCiNm?5j`&&9) z5$!>J1a%{Usw&>r07TCt7B+o$sFVB7B?uxot0ZBkX=PAIbM&|yDt^M7Nm5RT2dgZm zPSsCgOKTI%8e;D4Q-c}SW%SjXf{|EL13KGS{l*l<`&eO+>TE$$IXJA^vEL(ES3>XV zp7v>9fP+XH#QHZr&>=QAn|E6fWWwcbYcM-JpjLnSn2G4i7WjzP{S5Qwt55YF5>QUf zKNl!e8S7FHh)qb+hKGHMRD$qe@Xc+B&mKFRf8+uKa`D2*|9rv&nxES8vP?Vr+`2>t zVA(&!!|u@Li>~j+-Z8_=*PyFl6>^XHV?2Z>QTHeyf{hyS-b(40+DOy3u1BH^)j|7Q zFOBQxGhc-D$e#4zF1orNcn2EZPUF*HVXVD>{sCyfE_2P|a^m*=nPEEUUWzZ__NkEUHqINufBR4QZtv{%H> zMtNHOW3+6YLz)HrQszm)0+Rz+CFH(ZrrKf2FQ_Nat$brsnj4cG?H-|wjau$=fwskg^-m>)hZ)-v&3!^O1vGu@)to_Fb z=MX0I6+wTUCAvE&jzTO~X+o}8^S#{%kHlmAWqmFfEkB5-x5<4`TzIzFQK9pgPgi7> z2|qx@3w!`8`{j7dmv==8-r&VQKbgTOu^x(%Vhan@2v|zch`0<3RSg@!q9f}Vzxjut zdn2N=)%AP+2jXT1f%Ex9GiJZ0hg#1*ePZcFA9QGJ#Hy{p<0FUH*H(V0D4{6WtkGy3 z*8VS!iUyK->P=Ae338uV{*4FEOYJUWykOix8xN+4Ne%b#PN}|^3XDb}8J{HIK&lZ0 zd7HD#@G_s6>>Di;D-*`Lmj@K{VcH8CGIk=2Yrepk@oW4zx6B@vs?9p4_ep60ZxYpY z?3x+PJE4PFL$ojf41(0Jw6c{OyS4@BF;H z!}KOL^b$L-9NT?ZmS*r+pGp?5ynq^=u5aRu=a|^NY~F#LPt^yuJTZE>`mFb$d!<=! zk7Bxo5V>H#(;StQHmqBT{MkPA ziH$FgKfAdHM2^75L;l?Bp?h@i%N6fSM$O?{EUO8wAS9?O=06Z6?_m9iTavKl+X9{}cC~>JPS6dm{x)3WKaswhpydzVOfU@L_$Un30CJGd*lCEM45dUo z^1A%pqZncR1bd{r5u;RlEgIc*d-dCUUeP*pnW)c+WQRx3Kb-KociS}JU|#p*z-83D zP3PWtaj|SFS^FTm<)`@iN!aL8>pO1}+c7D_Z6cEWlJw@74IO(nYSjahjd^F4tY(L4 zwpl4{JKz59ljhr9QrfN|L0F&?22ub|VF^G5XQx9DZ|kF#Geq4Zuy4i$75nlHc~d7K zSuL=yv0CToAA_}Aag-@&?&67eSSZm7Z2@~b%`~&{rcJ^8Q|O)}sY&7i4qK~F{0mnZ zMn}$ALWg2BsdNr6FnlSLCcGBm2vgJSNxag8Kk)uws_+rvHX%#UkEa6Wkz6>kcN&}QL0aXafwD--&t^P%b0ZBh@$5`cKS_=K8tCl&{QpWtuQ1$ zf;igb?8J;g56(DzCK#v<_xT6YXW|Zw@ZTaAxD;E?2Pds8$CsZ?YRt~;8SGv-mU12xaqDrRaXsg+(qK$k5Vg&93TGbT%fzS zxNHS`pD|Xu?SmE{@>d;y_P#oJnDdVW-CwkH#c{r0_2w~Kkcso>ZvpOBRgTFRz3<8< z(eKmv+{WDo2`itO!+Ej{!lr6Vbt`^(iJ_5aF+ z^1@wp@;yn!pxji|Otpkd6r1@OrytAZHy~*jbFc3=Bg&cT;jyKD{WvaRTYTxg5#!oN zD2DgS}JUR2Y;6r4!m>^pyz#b8d_*tJ}ZnozZ zO)8<=1PG|5Gpp9aQQp+A)l98HuTa!3neg%8z&6^HOA?xL)8Z^jQ7U6>|3+NYR8)8@byI1Ev z&K;uB=(Uop9z@7nv^aj`3?|?P=+1`h#oy@A7Hkaq258wsZP=CF@4TSjdpYR4V0@z^eo^h zw;K9*o!n5+7)|uf#b`4HK{X+eP!;9PbDXy zKeYp4N3P@mAD0ey0c6)+u=`*surfYlWzZ|y`cn<` zr|KnerkfAUTPOi4{4AgOvnkp^der|OZmHT{kKpYWehK?|9V_rsGKu5Fw<3#z!b#3NhSa=a^HB?_nU#1 zE1xX*%a+3FU}7UyE=Ys4Kkq7iB7?d)Nck8Tm@NdONIXU$Pdv-YNn96tCIcW)@LSP+ zaQk7coNt=P%{Ue^&ttj{E1ycA$cq8Gt26%5$<67BYVF_k%xzzI`mq<K`7k3@mEmDH6?x3+j!5y&6+K1^R zSilQmzPaYXyP+BPnFcDf1YgEbbk*K-X2!uZA=qws9z%U5X;0Aw-R#zL;o;v&Y1!TB zEnhk0;j@-LbQy!}hB!XB-6>jf1?L^oXNOn7*yKM)2ejn69gpH;1rRU0%-(Zv8K9^? zUm{tJ%mHip5?C&qSpjG%MsDB&kxLxKvK-%f9ZLZL-s~;(z8CIBNpMOeOE}l_R1sYp zeM=OFfsq_Nw|0P6G!a{4U-gmc+ptp5SXfJ7WAP6i!T@biPtf(0C97@a`SdRxamf6RcLPfD0vEa-p3TR(fP%+zY;0gt@7Ftgny#d8nJN! zBPBq#mO#<~J#EQu#)S&q3)tF%n!7W4yGT(d6~L!s($qUgHL>G&7!4|n)jo0~$*M%m zKX&@*m2sD~&7M_%@Tif&U08&Xv;1c`y9?oDpj9)!(EQkFAME#YNbqJ@)ObT;gYK8K zS`%_(g7S)m%Y=(|a$uQ+_lgas$;7bwlsG}U!NXOwxU9PeaQ-60>gRT9a6~eIOCcq(2R3<(~vlS3<)S! zvO@)xQE8zyrv1J%0eg3b0+12!gtsO0RNQy;$`(?a{B>H~)>}wj)bT538S*|8kVu4* zE3CXhmBH|Q`v*WfrR-5S7gXhuC&Tfi#=DW~{3!t={wiy{@9`J21EIt>m}!# zy!V`%Z{J;=d1>6l_LZXSx^$p;kIUW|L*A)vFG`=C<9uxDqa?&s4#G<^k zVr2BdSdnBr@lg@$ag21oV05kUVPF&qu%Xs_DJuU%>-|d1Gx@bQ>`a;qPv~#g_E%pu zjpR~h{BFx6ib*pm+#FlaNDjI65n&<2W}1#p(aDXM-dX1)H3heT>q`qwJyL!E%Lm@9 zF1R)ZT2E_)g&%sOrC8k+oDHkkl@i#~Pb3xUzTFLS)^}HMO5QBZpkdGZ-V#pO^QB2r zX#}YxLG3l`%udgmBP*21qt?1PUw(uC%RVrD_tls0)Q7>D1hafV;lC}d;p=db?gY3< zBCv$LsZSnjj+>Aa}s6MM{gR! zTxf_V-o9R-eyeh)Z_Y70J+{^HwR<^k6$?85%x#3Y4b{2&8@t>9|GLv#hq>lnv+Lhl zo)go$YRon&&kZR^I$7kYk2BSesojr|JnYOh#dKh?$oRR(Q9|3+7%9fT1N zjD;r|11^f?EX4l8i%F|Vyl%IRNqr7Ys>wnXW$Z>trlr4HRMzkfEBynS)bRDSI8 zbsFAF;hm+7A(Hg+L1|36A~HsU1XLC7uZ!7#JwP*%FSB(2NTkG* zlGRkcR9fwm_pu%IGbhgVUvM2GyI-YxcQ6dS3QfXT;ff=gXTmqC*v$3Nd;?|CxT3=i zIOrndY@vf&$MJhB!_o9<#`P)gr`~R7 zh$^P%Dfrc>+>$oC@9_n=Fp;s!BF*w^Bi>Eq-1pY0M2?xL%y(b);wpx8PZ7L`}<<}Kx2PXWii`lqt@K@$5s);DK0sg2Gh@W3&j<7)E8Z1)pRmF1neEh!cw)Yp-2m> z@p!Pd1Yu6?*+>v`0J%^Vez%Jixz@0C07qIXhmT)DWS0A`x|eF0NF0_$Pwi^HDT|^K zly^=NL@%?msi-;a>Kpyp+-zIs@~eERjhx5!~qhd+WnZbJxJ=gVpEw|w7>{ME2K1< z{;VHorHEtX(*;Jh$5>WQILLj(@?p7QZdpael!r>JK4Wzq>L=dWgXp?2`YeC3Z;}9c z9u-4+ocQnu7}VaW_Y0*i#E=Fm^yPS?V!FH*y2z?ddq>L+@r|p&1yPTRK!dMe0kIYI zoV~|8_`V^fhYM|SdcTUwQoR^sj}@&SQnKP6MEkx;!4Y4zoK~Di2M!j zHZ!M&OfIQfJO9H{3J9WqtHjuG`Tp>kz+Ol+5#A63LqicCL`MvQyX=%EoedGO#d}R9 z8^Lo3UNid;TNs>OwOTH@ugNhv!1JGB8nAmI0~nX?l`8et=_!{9*cS#9x`wrDg0gso z)h5#|Ib&)II*Wu8^bG6VJRWRDt%TNTP4OC8*YE2aeWO8?T>R(TD`XRDlkecpSqr$@ zvgQoXv%$yZht?(a1E0P62C{Ch$#2>--5!;@8W36hM)6bC!f0;#tte_77< zgwq=70GWnP{I5JMfN)dr!Q7FKG5Zb|g(f4p7!rtI-8La8*@6QIiw>m@g6u~yb2{q8 zkPEa_=PqZ~HEo$=YrHgkom~iuK`juQa^+`_t(3nYe8PXt5BL0Pk`;$JESo+p_RqT8 zLapX8;7Dx6C8~cAzL}<$BktA`nk@j!CDs#W=KE`SXs5JaJ#uU9?Q3}D@?ZIT1@#Na zQ!Tr}9ycVI6>6^59ygWX4kAit5d;iGEF`|mTzfH5nc9$z+)r?WP4aQIu54awozE8* zZs92B&0OW5N8|XP8IUov@u~O(u#kmX@D)xK0(0oSW)j2&gG*a#gBp8M&$}90`6L`@ zRbxhv)CgRLd9(!h)y&C0);&0!BLml;(uxRwtmY21lrLQGcO&^&N@_c-I62&SNimP% zEGK2+qW4sxz%v0r*C@P$sbVpfO@%c7Od^9PUB&+ zt4OEY#PqIu?tR^AuK>^RXBnsaTYpu?)76Sphcy-%QYn1~8Wt8c7~=DO7@2xKZ{kbW z9{|h~n^PM_W}zg!ZbZML5iA!-QX^)~I2~Wfn}osCn7xJ|T-Vq3Gr=^i62Dzb{IVib zIQxfC2k#>0ZPGr{>*75eNx}Qy>f;USMUpYzGvfuCB&X{|Lj}JmeBMIINi7e(ANNIc zt~ij}on22-tb>4$W&|rjVacZ;5~#YEAh!;+g+@a};vB}#=&h|a+sqtz9<$JkwZf(Y ztpjYruVq#C`gejE{L*NX^n?KU%aW5hluNkM*R?o>$I_ql^pu$mLXs9u{DA)Qk0`MrwS?&_moGiA*L-$j%c z$@xTq;zamXN|iC!O>ap<$J!Y4hRDBWSlkr0EBsFkK78Z7@Hm~5OrJv4}Hv$v)}AD(QoKBX3V?xMz_@+;_O6w zQ{$iV1;LWrNEVJ%c{u!(JEmyuScA?i+ifW;wVJZRj~}o+t|kS}Thl7@u5?_;Rd(r1 zXk*vLhtiB)T(EyD2(>WZRU^wOAJv5tinDkwH~2bmr1`3&v}x){oV_ zuc{val+}W0SIls^(Zq%U4Mng}VMqF&KtY0A)9NDVUxS|Jb3nLYA4=zi$n${XbxTd9 zeZk&bTgKd0>}%=M2)p_HWbLcw1#m5{J2u0m>~FAmx$d_T42QVanu~zn(_E{1#yi2w zv?Lf$X2>oi%l8`5PEvGAdFb^k@PQxsOnc4*=f!PPD>k=4#JyO9kMhEZ8>JdwCEl48 zVf-W}U(r^aF77ppe&Bl3+g$tv!EF%8`b`VMa1Jkog@W^Y)8|M4PshPP%jR93 zO^x000vrZr{GT8fMve}SSS}oZu^pvmG+re-E~kmbrPaSflBO+D$;LYy6`LXC+l1S_ z`lW%69>?X6sj@S{bNiZ2Nu*~PpMIJJD*%sNVZIK&8KRd$+4#C=C+G!Ae02{WkzdP& z-8Rnh9QsXV{`;?eLoh zz6%_NO#+ffhc??sNOPlLCinHFI%TQMmZlG19ErL~iEwAaEg0>|;Oh%vd(MgAV5lvw zN)c!{=vtMRYs)vG)HI+$%;%&;yI^+#NL|7@>fCtIe!xO%AzHe~ zHJ?1P9AdKX`iLI*8QT~U{rzL#iXV*fPb%SEHT*nr7K9;sk1Ge}!0J4+f+bW+W?1^L zjN1aVkWH919w`9U3!kaa^iUaVKO|=i% zisfwc4Lh+G*~E8ytw%d4C;Nw8AxNp^)ib>7lCqGZ*e!#68wNThPWt0?zaMWW&FXx?z%8>3j4hk>RLxk069EK4AGl^G%6_^ zJY_pE#x7p#a=MshLb##hFGlS7@i$fMGlokaF;!coJ3+(W13!{}c1-p~%8b}?1NXun=a4haol^tE zbGDIoQ5)(h`m?vV9G2h@t>NNRPW(=go)>hJ_^@Q%<3DMN!kj+Mu3Ly}>YnG=DZMz-?kr&~1|7WY^WPye(F?aKl7sU}a+1Cp8*=w!G z*o{oQPiAve#sA*W7P%{=wtsPep!H-A*XxG{qB$cr{n@-Og)jL?6Ly|?l82R+YmMGf zyY8jIRwesZecIMZKZ10GN5F|BDA{6nht4-Y+qJ$Ou$jz2VOz(QgeXrOc zoAc(s8*A;oV)vqNRguEs=zyf$bM)_l?@sj_&$mPlH%2emQULa<8=2uWBS#_W?eNL-2TOL=Ty_;OkE38?Al2TurIudoqyU~cMd#- zQCM30y@7%prA;`FxV`3M>&}O2*<>vxwhf&LNZ3bIGpOgLhHq~42-ltJ&KLk7A0r;B z>e-fwpSo-L#c;X#3jg)>NpKIJsM7>@??u1?*89lqTY(?`n$gnp9r0RY#4)im=*a>q zqf%|EdvG$Mz;?lX`fc&ksw=laj^o9u5CQQX`yKjpt-@gj#)-ko)!6Yk5C&X z=WWqR<+J&uiPE-eb^loxRm$}#_f>oAX-5%7SIP_DLk@MIyQZ`jL=RS-|NE!^x`L6q<0h= zJvJ6v9L<9cWX7_@Sq$!9CmKHG8=v!0roWUQ?&I#HAzzv(a#{=|leX;dNm&#? z!9CIDV82pa*$xBAvfj4N^yniPnU+=Nl4pz+W_VtoJ2-A;UPAZVp&NU2POqbPoV}oE zHBD<5rJ5dacen=ia(lC((E@cFX!!u5(j}!nR~Adhh{<;nQH!6}>JlP@yPUnTsJ2`s zcML0FB!4NJ$;+GjJALAcSe=hkBruZx+C6HxkCE_V@TKwI0xbwzz2?@V*!XHp5iAc> z_nmUcQs3~lAm3hT-|aVjt6U@$#kNaov>OREfjT{n_%_u;V~FDF^B2}qwSmLPe4uWD zC5YGN>`3nCGDZ{SJrOqZ+^vtyd*%2u8gHxTwSJTG=>sjW#O<#X%kuiYpa4c&RP!7< zK!sl{F|6srlsc#{~V-PsSWZ-UJ(w)C?*)*J)- I@$y0c15#sH#{d8T literal 0 HcmV?d00001 diff --git a/test/fixtures/truncated.png b/test/fixtures/truncated.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab39b69ad1c058bc832a4615b255a4d51dd6d1e GIT binary patch literal 10000 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 { + throw new Error('Expected rejection'); + }) + .catch(err => { + done(err.message.includes('VipsJpeg: Premature end of JPEG file') ? undefined : err); + }); + }); +});