From 571354efc5934d78935ca7152905c798291c92e6 Mon Sep 17 00:00:00 2001 From: Vladimir Rybas Date: Fri, 22 Jul 2011 16:43:03 +0700 Subject: [PATCH 1/4] Added failing assertions to issue #11 --- ...h spaces 'single' and \"double quotes\".doc" | Bin 0 -> 52224 bytes ...h spaces 'single' and \"double quotes\".pdf" | Bin 0 -> 30297 bytes test/unit/test_convert_to_pdf.rb | 9 +++++++++ test/unit/test_extract_images.rb | 5 +++++ test/unit/test_extract_info.rb | 4 ++++ test/unit/test_extract_pages.rb | 5 +++++ test/unit/test_extract_text.rb | 5 +++++ 7 files changed, 28 insertions(+) create mode 100755 "test/fixtures/PDF file with spaces 'single' and \"double quotes\".doc" create mode 100755 "test/fixtures/PDF file with spaces 'single' and \"double quotes\".pdf" diff --git "a/test/fixtures/PDF file with spaces 'single' and \"double quotes\".doc" "b/test/fixtures/PDF file with spaces 'single' and \"double quotes\".doc" new file mode 100755 index 0000000000000000000000000000000000000000..e7f7abd551084910fd96299d7b82124e100e2d2f GIT binary patch literal 52224 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 literal 0 HcmV?d00001 diff --git "a/test/fixtures/PDF file with spaces 'single' and \"double quotes\".pdf" "b/test/fixtures/PDF file with spaces 'single' and \"double quotes\".pdf" new file mode 100755 index 0000000000000000000000000000000000000000..d01fd649d503a1172494adf37241c4cc4e522463 GIT binary patch literal 30297 zcmce;1z26ZvoDOhYiTKLwD^XNyK8Zm;!xaoafhPCU5aa=Kyh~|6}-4R#oggiPPM!;IEs$K4PXY?8Cjz9@d0HmY)uUv zE!<5_04zXR04p(6>Y>>U597sSrZ{x3QXwtv%cak2iBj+KS=U%aq_nEzET2L}tw zKl5^MbN{QooGhS!(Q$$}|HTV8H^)DDVSxzhpMAx`#mf3mURb!;IsREM3l|rN?H~Ms zKrGz<%nJgs{i{3>h=cu~d6}6X(DFy$gB=YmtW6!!Q6RumfnW~6$_`X?GAO0aXXh;WOsgII(m zSVaW*SV5d3%p9ETT;d>cE(j$T3$rjMC%Z5+D;KwfusE~817J~{z=n?CpU`ARN1>t; zSCBwQ`3HQ_QCK1E_+x;W+M0pQ0W2U+poE1r*whgyVQmOD6*D!qGcg5916bI&Amaui zexM3~gHu4j3G8TUXam9jw2^^<0YVNBf;s{M2`Yj&0^FjR0kmi&JQ^+`Gc$2;NRXAQ z0Mu|Nflv-Kr5{{(cCw#vieJ)J0MjwmS)ef*+8YeQNe=t3N4UmAhJ0Hq;Jf#M!YgH{ zh$E>?A*@ej|x>v_<3TwL6L#6QqLKmy765PC>`pnmvq zvpw|UKmXVuu@7AQ_5M)yL)^pffv?~EKioP0(Uu3A2YQGW_=D~t?xDutWjvJq&wBss z=Z6v>a{bH+DMuG5V(4W0AReHqg^j6`ys3+_osFTbqKcdxr3q^jRg;AZ_Rdxqu^#u!EHtWEw0j6DpA|0ZKB zkjVoweEtL}=ugi60O^13?tg;rH`Q-&{eFHB<^!aDL+J-FA<%+|83Km~(f%kw& z5~A}!kVV|zi65}`Tl`>C8+8B|=!YJaH?)ChtG{#qz&K=Fs6ggLu(3H%-p_IT*mk%=|E?nmGYj*? z{F9Q4o8}(uAr@FuERG>6u z;e=_)=+Wd#a{>z4Q{&yPA{`ZE1IR1Zb_>URtSHl$) zhg7k|wDzY3H6xv+wa2#Eat zwX*tiA!R;at)*)>BSGLbQJx$upeWuQjVB$`VFcadz_G1B>o0sNsd&3*q}sYQ59-+Kte5m%xqb za4A*C%Hhv1W>ZY}n92?YFfY!+D+v9#LZm#g&joqOyIxUILvx(NvgE40tbQZ;`OD?< zN+7ym%C_5wr-loYkzSxnlXtsZOj;gxbCh(rX_YwJx%GO_qDDVPmIjtHoMLJfvtf^B zY6wP4w#m-|YCjlqMOnB2gEV67=b{A+J}cz3i-L*LD#_|!mj_G`!(l+*+-!znuC3}{ z6t3(FM%9tJI&Zq@d_ZK@mLwbuzPg;6Eu3NH%?SS%ta9L!UmvJvpwev3iN~tBd_~OM z7wPG=?@*Zr7xNr5-6z>-p8sm}+#jbUgnuR_9E)S%pyhamVY{MGcyZE6s7U7}tYAOD zi4d81Hm8})DCR7^twG)#=sDeWHg$=c94+uHNAU|y42$sIyn9=-uHKExi#C1llz|HW z8qa5m%gdujpTBNw(+^}mnKZ;=s(@b>3lE$lKZ&rvKD<(Au+wlcayu1%;d$$DdU{qF zzJV-oP=)z^R}zl;j(Gsh4$<#<`=fah_?cO*<3`v6@wp=;wavE;a>50{1P;Uz8l=s8 znEHYqKK1SOXHREX>{spL8y=bObZ`}&V=KTZNlo<`j@!JTz5p$)v#HJ~j&w}Q=c|VA!W`Fp(x&f= z4PTa~k~IpOY3RNPmtUr^gr z!R{};T~`dNDNQ5N8&LbOb~6wnAK({WQ5E>?e(!>2Bspc~_`>9{xz2S!@zPgJko>*c zB~2@FPahnw#!F~e9_y9w@Oz9Xd@I6zE7jp8m)~}lPn(!K8NxOzzsANx!3PT@cyP~C z=G=Ae52A(8q}#81DN}6)SRk0g+hlv&n0n*&dn<%UKQ8W4OK328VGfnmB7XS%(#%9# zL3&;W)R(1;a`|Mu)T+l~k*lorzMw*0b^qYX(C(FxLMqVYPI>mG{)Ja_#sI-tXX7oo zfPQFGIVa~t9lgV?QmKG0P7^ji!np3lNRhT~X8pLR3numgHe=@WR%c<8UsFYk)2UC` z?w5!r&5K5=(5gtdw-jXs3p&MN&)VgSL>P)mn5sBTQ(Zad+g}Y&Dwr;vZJndRXBEiQ zGozRGS-gpT#lVn~cw#IFPoYz(ln(Wx;Dzn6BRX{!;Yfzb@}g|vfk=y}R=jFy>nqRP z1b@4D5i(N*-=VVu37gL-Axm;-@&uGJ5?tIV<-^xmzVC2lk-7p|)$rDEgJC~YMNsRq zS)KP-Hq|*xe{Eg^+4ZPP6cj!FU>;t;6UJy`=v2>R`>5=^v~2HvDc-9~31Z6kGV$NF zK58h{CcJZjAtj$H<}0C0ZgJuwpK~#aAh|h(t$%y5??e{MpfX*hY`s*uL_D!yY^kak z*?(*=8tL$sPAji+!)lNX=YYv(Vr~3sR-YE19e|tgLJ7|x<26;vK`~+iS~gNoRpv-U zL7xH{=G!`7Z@lJc{VsU~8w)MAqq?A6t=!?&6se;|JbNf_DxHW_llP7yLMqBaS#A_& zLNDe!p-8kCN!*Q~by>tF^<3L+c@+f*=SZT1$=1Zo2~Cv&sA(J%@1;FBgCC*lzuF^- z0f~oy@n+1*OCx9@p>{CN_pDcU5G!ytO*yw22pyp8UZqfZ6)^3OFHI#r?Wmm^B$N}@ zxJ0F?mN5+1+we}VpHi$vsWIv~!R3L?&`gb(V)3IZgQGC&)hK?<6C@VPM`y&0#*9u> zne}o2M7fE%ni9b9LA>C^>fowRgrqo~QfdWQp_gdGe-n+cq2Qx1zGGDkt%e!}t}2{} zsO=i47^x>aAIsSjPlxWz0!eJYfcSN|ZVsKC!4P_{*238UH}8}7*CsH0O*zbl!RECl4v5qXcsYDTp|G8TijeZ^)$I>JVo=Uv`Quj-Slb|mnucd9060woLH zZO?*$TlbCAnJlBWMWwBJNs^%;vSkB#bN~zs zvjz^Oy1!Ri?k!;*Zk6Iqs^|NeTN1eJnds6C)AI->I-I)x;*{>CWWBjXN->O0ntchL zcN5eOg-;Oe?!P*WAMIbYZhuGI5jQ(@IyD6beJOd%4S#-A$1i?Rpu0im<)KpiOlAh1 zkIqDGf2@^Y-_&Wbfb&;0q?9H zSA}5lKgY~oCRI~b+#+?Rn+ugK53gKP-J?xN%}yU><1pWlI`&RpXCIN}E=A-XL-#GD zY57P~y+9KkTXoB;(>GTZgyg_z&$(tT!BE&#EuA`yuH&5;`&d&#z#4D@+BNN~l*a?F z;HM-e&H{v#639{|zwniEDb9FC9luedAP{{tQEYpOfe)l=Db#%CF8`qs6x`uSz^sG# zQZ;4pGr`(T8^N|#W9v|9>OmItJRzZJ4WdKvc-`sh(4*0>xn8?aTpw|sm zp0=}V#+tt;38^?fVon=4#AUapWHjZdkjS!e)`ltx%cROn1|>_1D#*&R+s2#7lj-_Q zRHrOsbZGjGwfj~x_Q;Q7@JLa!pZoSc7SR`!-DVu1k9Ko85nc}K?crghpO$d(Vq1R3 zP%UlwordRZzPSI)rfs_#ZsBpFzvz$$%9~U0qKSXrN>zmi_O27o0JvJSuqvEXCn=74 zV?<%(T`40`O2NwM~$FFj`Bo3ZvmdoeG!R8fo>`Ohdp@&tW z!~?8utms8mD|>q9T}hk!ilR5W!wLDwh3M@&K9|$-kJMD9 zW=CSNZP^%+OYV2yvJI(bXDj@ma8)ljcc=%KH@-C9_;qQh_3QaNmQ&GZe8|Y0!W&7G zSt{b*3LQC#a-0%()hd8|1@O8#<$LVPb+~NN3xL#PU9aHbTLrtJC%no17v|#SoqhO4 zBlMdamA-55_9CGqDApGhI}C0b5P-~CyQWH2^|SF;%##@U>d|V2yfv<+u`Qnrgiw6# zpr<*F3bWdqL=KVA9X^RPUZij^BP1#Hky=0VR z5$zWPL^_an>+ms-=Nf*~T*QJrB5kXv9e)kqLdz2OX2^eFIA2T4paMlEtL?Bt1q864E% z=853%r$RbpJp&g3>%-bu{P>Ev8cCmBMELeghs}4QGVi4~uB0uwQ$)Ssh6IVL8mL~} zguOQiyYI%PV9J}R^;{0G905=-e;-8jDB%xC@|OX;oT?XQ(3QPoP^ek*%wMJdX7Mrq zvQ}`VgYT|WsT{kU4~cb2M!@%RWVfmSn7Qs{0@8-_SULDZz((6Bi2?5YEbX`16Gp;g znx`ku%2@b92G7HCLT20?(UA(oulDg`Ep)R~idUj|>531#{p z4_nKxPD(pO$MG|Lp3I0k`EoJ1caLoV)gz}?i1HtdxsaFgKi^0H4`#xL?T^1(U|9aJ z4gDW1Fn_m!{O6~iR+OLij0gMg54+0`{(jOwSVR7r^QQ^$uQ7jyAM7H3H}?Ist31U2 zwy^xJ>4$aY2mKGr%3ln8Kg)wyYW@qG%Fp-w|A|%QhXwezN#M5#Am&=;Uq%cQLtF5J zaluLFVQ&axYx&bgsGunOTtc26VgfXKumw6XDw~?UvNm-5(>f?^0I6aXV2g`;_E+W+BKJ5ZX5SMgz*9J-M=uc`eS+#j zld}#f5)#A4h8B;`@`cXLmMRS~BBLoXz?8yLG-3`bDl(B6m+^FS+h1Ed?`v6@HrsbP zpYq78VS=JmAY}r=C&B>@&zGw;hL<{$zSjf zbsVfg!6_I}VU)F~T&1qqX(7qom>6K}Lq{n4ym}zlIx2yECET)TLtfs?;|7OAm`0}O zQMQ&gU$ZFEfwsOdIQnhuoAEy$fcqF~YTNeVxk2|j%QkYC_mPG{4sRxfSXTAtjPRReKVI*lbdy!Z(3)rliPi9=soj}f_A!9 z49#gK6#FM6sktne)eQmP94u%YH^tf0h3oYIO!(zA!UCQTT<4kax7TI%p%*a&5!b{U zIFDq_kS~eCt(L8jhkT(Zq47V$;%7mF{m7VM)!PZUU^pvaF8mCzFvejBLJ<3XF+svi zlV~VH*pu*Q{xXWN--Rj6p`QsMa-lQ%eqQ9MN8a;AG=O^(uwj7E41J6RXGjJT^IIiT zlR^dgegPnuU^WN~C<5>>#6=yjFmXg0h6sv~=w8!hYZqZ(5%9q4`j&~n4)L4grTTln zp6^1E^)Idfm7+iCLYqWB3kq0bw zAOd5^n(aR%QZMEzd)5%+8FQ0-qwY^`NV!DSkvK`CL^aIBLUSmB11zT6qHItHNmjl% z%3DS6x1eo~uZ<7KQ?U$CO&FssHZ0b%2&*ox&IDJ2KY-&-)V8FFO5fDJNkh}2)?csq zBA&v6A~Kv+uc#T%81Mdx>Jt~f=(lWlCEOzMF}tGMF(NIZDbvdAO07z@N;4Blb0oR6 zb@Asp2}ANjLFW5OG(ZRKPOVB~>CdqpR8Edzj**VU4I&Nd4ZM!~YgO5E{e@kE^t&gl}X64EdQj&sKQ@(^@i!WOU|=l`c3{5B6ccv1@>(1_u6gK&5e=n zA?_LOC07*a{s^KJ>bbJHI>r(zYNHyg8dX}ytps}E+4$u(3MCp=@;Z{dvL0#9!Do4q z>5)nDk@8goqPmr30k)~OZ})8Y-;js`mG*t-<-9Z(Le_t$p}-;V&~`;{MS+@tTAKQl8dKI(RwH>m z#X059vcRqvR03+Uk>_yXTri)vxN}VD01Z?IeBRSmWbkCH)dK5yR##W9>eOn=YguTE z>!|6VvlgNGNU*Ggu}@D=x#yl*Y`btIa=@hFaGOvYxDdfKNo4C zVZ~{rP#0AzXd<|rwcZXca&lcRTKed0ZJ%yG;v{3wvwqS!)t$0GyUw>^v{E_0)=aP??}U1iyPonwIK(!DIgeKr#0IKn0W*DJFJ-efNjQ9WT2dBFAL!J@OHqNH zjg5|7RWhf(uggzjfvttbT`gfIH=bHzg+EUHo*$QrsOJq2QA8w0xNX>7`-$;5izz(3acc23andlYo{3h_?YrfY*Ka@YUO#7ejzUz)=D$s92I@BKcwZWotL!(>J8Q`6 z*EG0)f4rjI_v-WZt`~uqjiBbu(74^yf_K+$(!_A< zGhqdiHy?U4?&I%9gAZ>CR}0s0-{D5Yy^Jd?oGr8!(7Cm~ar=IJx#gdk?^EWTeZAbI zPwcamrp3;B7klrxG_kC4R36!^ch=}J?sImSw#s?z^xAH1fyArNb>doJ=eFB(9dRc( zEXtjHR!1{pw9&WKK&}+rZSq20WAg&Fx)O&!$D?v~KCt>-P1=$)mBY6Sw9K z=;ZN*)g3v@h^Jz1Xly2oif)j8LG|x}PMm~Jo4&id8Jt+rew8R`8p@{|nm@4rdFccp zeFhk?ieLMGe_xXKW_qR7OEn8pa z59YToT0cz{%p4eZZQkA9*#^Jc+}v7O+f47?zP>oUIyt;L*x9+dJ>Oj4Utc_3oH?H! zJ0I&m{nUQdQ*$^rxOIEK`>}7U^8H3h-a>lHUcCQ)LBx4w##uw*d0WMHZrb;z`t^aq zq3zq*SXM5t+&QIX{i{a?Rgx&HJB>hpQ zQBjoq@yLcH;OJb{JpGP_7Rz?#EX!Zhf3vhH>3LSGDkdJTU3209f8}f0xdKsD`{^nD zvN$ls?%||^8e=BwUt}-52G7rVo)P!8|G!)Z!NN-$_jdPpq(HK}lT06sWP*>fN5I|_ zA|H3R^)DKf$(Q=Tmha^ziI*CN(;YKhnvfsc0fMQ?L zxvk{6s=l%MQyUd@ACX{*`S=DUQKU3vM4-L=iiU&idRx;_-Z3~ku|dB1BnDMztYmm_ zk-}Wx9%bDR4URrwn17jF2GP{W`^%_17+kvG|JvaYIaK-($bs0HBzCQWFrR!)eS`1w z@d-C>6#;*~*|WmDBdO8*VdtTsJ3~vhyg{Ga(}}>#C?|yST)}#1_`YFRII(V9Q-$vCwd3Bsuf>%I z89<@sr6%K{zILz*R~E-htE%EdLjk73P-?E@;;1@N_K9pT6e6lsQSgmRLZ@tBKyR-L z`dJN`w#v`8I$f1ZHnqV5?xXJ~;*7V&>E;2B7tbqR`KQ@whLH&7Q@S~*tB-%Wi0C;e zV;g9BqRE3F-#+8fpn`JeYVOuejGM~y?u#56OZ!aYH|VvPOKc^YoP{ZQW}4%59{!=L zy74Z|54TNebaZskY4r5;bQ~?u>xD>M$q&LBobJEt26#UY9j@E#rr_3zi660Hf-Nb4 zLvF^&>F%~eNcMI{coe!q&blNU_!&N?s^efrNem&togFQ?=JuT5twsfQyBHD1X@62x ztHEhwK(~q9c~`r|YGU9kq^kM3LyjeAiT4`;-D!4An5T~0bDJj0%bg|ph)y`e^HZN_ zivo|P0t2%Q?rw=sL^|0@gu}>9`s3UaWfC^5EeNtKy`u;ipdW?xVEG<<^+i6#Pe^mw z3!|Z7#!rTVhoa0e8pROCWRo#K)8fBtInOfu>Mm>g zVEFMe>_z_l*{td}9E>mCdTg-|Wjnaze%VuG5fSUZg5er9`xatHv1n6q;%Qt^qE7wV zw}A}{2~CIr3jb!Xqwyx$E&0M6J>5^y4w-(CtNxR!ucgpqxIQ=rS7#}m;dc$F{DfIy zHG%MRc&adg6PL@)8vQLtPpmpBFpwAAZRC`5Y-i-+>|MsSM>rXFzO<`vccTpXb4za1N6aIzcfG~Ra0GzhI+ z;il1j|IM_S&}N9!ofw0)-MOfB56~Y+r-;6vMKVACp{m2wgp9>OCOgRtm@vvFE`@}l zyhbEGNFnbIoqSj1k1>>MxuXHsPo33H3UW77@#8t*G z;+5BDC>DHN`XXKYpk<&P71i}gba(TM^-XO`3mBrwQ$Inw-ZXh82RZL7H}k(RrZ$c( zjK;~?C{Q}3eNxEMqgpx&fvhb!9V)W>Vk6&Ch2O&sGaSRSl) z8UuSugct*#Wyo3{By$;8hjqP9;NGHyOjJG0Wg2fVS+330s}=i1+7gC@5`^kpwsGxc z-gL;fibTZN2=d)R%03afXeEaN_7ety7!<1f;Kf_nI=W~6NP$3%oXavRRbO$wv<)3iThC0)zCeFn_=3i(8`1PvtL1EkmmHG)eaN>gima3e{bQlXw)nu26=kC%0x;E&n#MLM)}z)cE36W|Eh)e3%*@WPFtaPdem2Q z4*gW|vaG6G;_;Llcr>##4MkGZgKz6p9jQ-YUw;n%oP|646@6&M$b-hDwcVf2u9fan zpQ~>eE=@=XfOu>ln8_9uJpUQUt7%1U1i)@w_6qeke<44&>-CMXTUJ)_@uq6$^vD>$ zcXB$d`bhqL#PZHuTCC2CO4FrIMz)N?9eh!|y7$SkSV?J(COx%X^i{>g%cU(O)BGX6nAZzcS;oi&Tu>;oHP_#d z12Ea;oj*%!atFe9`U4R9H@=lGN+&N;TWz6@b0tJ;Gq?lL8P~^;?z9^yYvMC+n?k?F z!RXqmHZrnPai`zFa6ds-*z#T21H{5BdsQauo*nJznxdPU&)YR~Y}OlK_xPPE}u z&3iMP#ALN?_3PHGxV99?CZ(!QQ#pf=kBMA@p<|M^D2A`-J6_H0yrq4PjV;&I?3b59 zFlr(WiFvBP7=%RpV(Ab570w%tin5PuX~k)u1aimA7r1mvNNa{soa?urcikvEz6Ikh z)SZO{Ls>gkN#;F4evvmy#dxlUn#e7}R`mY1ueH+mHU=@LLE71{By}w2I_9-nO$|Jo z&_0S6IZhGI2qkT{y5yUv!OfO$8tuzqCl6rm(Qma>4aB zc`iGC7{BNjxGRsNTIDsDYn6kSY>By7LSJ$Y6vP^xWRu20dok%JWiR!r`4KZn>U;01 zbPpV+j8wGlhnbX3+n9Xq)jM&S%j;RjSZt3_&Dgx9L?kQPx6`Td^w}Ra@u|?SxE`qt19ucT5;8o7&s!YiaRw<-#`hqd?1qwu>UpAD0i(l*~M<&)ePe zo4S^Rv3Qh~c%;fg|8bSEx6$KJVoU66tb(TvDDx?I_H&0SdaW-rA3d_fEPN(XSLY9( zK4aE_c_F0{RH>`9@NARGp57D=~| z#UxbH!`h03D)EG1;DQc$)Y1x!CR1rZ)9|wVg_EJwjZoS>hN)3h<()(Dp_Qvo#Y#=-q zYy=t(Ri45-O{>Jnqe)(Eu7P8%h!>B$7hSG&1_}qulhFQ_Db; zZwrOVzS7wCSXj|*ZG1=3JPcwY{`uGdhO&-(xuBpRgkez*B5U^VqKKc)H#Q~$9-RrB z&~Q;6Qb^;vRQA;N$k@K18d5{%?4pgMMV4Ek_j@M1UjU~-8W`_atYcawKphsn$WdZy z6VA?TUc;KX@_9p+l#6+6Bm@l)fXLGLme)?rhNrDb9--~I=7<#|6(mpHGiI79#y^119 zkk&JWPC?&*H=bZ|M2x4(q!hewI(4Faz{{(BzAC;7o1`dwP`tu4C;JulkFcxWTrjZ*r26;B$Zt;P?ORN z{I2-Hr1AZ6Nv^8x=Yjbczm($pyN@4XSs;62bM8kcDT6ZuFavJ|eU>_V!U+XqpyqX( zU6(pvA8!o2?P5t9sMZ%CaokCE=M96d%By6yke7QxXw|~+O=YuzblLa}hejb392Q%! z(VLJ;$HMDQPGv0x$Bo}p#|2w8FKXgE_a!%x!LCWefkL7j4cp+k11@=ljlj7T3-^LyDO|I|LQl?x;-G{rvX|5%b|V7;$*`I#${^Lba-& zrCedCth;#aR5$Y}>&M`*Gx$(x^Dg-riDKC~us?fIES(!k5k?Xc zIsaOfeS|!Z(W#c0 z=#~(uI*9O?2{QTI{Ff;McT@<0>AW7t2p1GtP*PBfx~=!aYkOKfdfV*o+D2dn%4mr> zl=N&dq$&43T3Ww&8rsL)$V@T-hl%_naz72tb)d_FucX$I;mWWeuQ!%dy<~#@>GWyv zV${IA`@w0Cg8W-PH)7CeE=q}>-4L!&%gZH(Vf3Z$vPVPy!QVoe-Ol(5Mi$9bAlij2xzpl-KMdhu>o#_U<_ zLEOyk)|t!OzKUp}y58*;Ix?jbqHZrPQ#G1r9WGSSMwK+PB{=5eq*M{j+IYbi-zXWU zc!2w6~$G2X7Cw!MUX`d*)Spcv>gUU{= zeiyk-3w2)CRoZVeGDw~jT#5srbtY=v46boWeLNpmjh450`)+N?6^)g}-Qa;#h0Hd} zHCnG7>#O1#Wb@Rxiccl&x%`C_K)WsG>sVM3Mf|n6SW$m#G+^`lJqS zU%R?5Jq?~5{Y~K$jd6moy@u!o4y6}%O#%2xEh`Qq3 zO>D|x;*&wKNi z%gV;^SecTy##6)J27D}wuvu0sevZ$615dm6RPtzdZORS4L>hnnjQ`E!#vFnKZb4kH zZ;dddZ2*{ywWbbus{*+}+Vu5}jij>Ctxl1M#gizK`|79b{7`QcxZCUE1NMS3%k@QR zv2ZFB+tE%{W-b)^LxEH(>=3ZfX*YgVDIEy=tfyniM8`D1$kfRn{dfZUCa7VyMrvUE zg&t>PO@6*KpG;DG86|9f@R@JkXdI>Fmwd{lPfO=-@Oy+O`^j|)jtwz0KPSiZm%m`j zT(QtmH|b_@SWxOdv&`gPWY`KP*ww87m|YDDUZ3U{Zbym-6W^a4*QWVaDKbJKV^ZSH z@}TyB+$m_1XpyTmVR3j`1SIrZ44!*VO9&Y`r#HQNyYdd^8bt@?Hl7mON%UhUJ~C;y z(qO^YFolq3!1wAU$5(WBK1O(?`wd20XvK7U3(YId~eoGJ<*LNOA|^txwiCv zU{}9s&-klngc)>=kcAM;!CC++;fMGPvkJ|}IZ;nhRrRgW zTa5ZN&Pk_9#s^Bmpo(D>g&Y%hT%mJ3(f>#r&(5Rk-k7QX{JG(Pf4aE$mq>+>L{gs~ z|4RXmC>mt`C=y%(B=ow0OrBwF_?ooWtdCAWI3r3ZR^zg11V=_X2mOXzVfd^Ti`Y0w zr~r7O^RGID3e_YXFX6{*5yERz_n*?kScybE4X3@?J<@QQw$;Ck&^in~#NW*clM$lz zm27moGv4XfdWRnLy;p)U_^C~R-)cauu~(9ypvRiV3#EFOeVNg4+m1r0Z5u&c;^tgd0c;n83*oFL-J z`RqtCgB;Q8&X{)gTSsyR*}@X+30x%W2-4aG&x;F|8$R!o5Dovu$VPX8QxeQKXNL7t zS;pq%b~Ld=APxyV3q)dLFCYoBlxU-Tp;8bkrGcuzp&KW&FCJg3Ja=^T(0lGqIWd12 zFZAfFoqb7unyYw8ZEY_3(ZMDUSLnOUXsk)%&!;>R7r~f32r+?^cLeayA~iU4j1L98 zR$snw@(FipbJq9qVYnmxe7{hrbaIX;@?s0qv&;(bT4TN_%Edpc|oAlsvGH z99hF6=;Sgc^oYE~t3Kb(V6tpUJE&t2mheMYKnq5n6k_vJQ7^Q`L+qSDp=-@xBWul& zAuo)k+9|(6N%j|lg5Cz!czO|N5!}%X^>JMTQ5uVBA6_zfBd=_riAn0#xT zfoq-scEkN-^xVqh+*qVTG)iVup!h8_XTIMQOWvBq4y?hxCX=&usfz*F0BZq*z9g-W zSoD@6AS)1Kg(e!0_a)(YU__VkCxHr2pYmLd=S-xd_OKWplHqeKv(TmHY+V6Q1NH?A?otJKAQ zXm1nUTHVOnJX>Ae{+5g@%D5&O-=YRZ6(+Sxd!+)krM-P=sa@a=vify$0T8Q?Q#5b0 zeR9rEVjoGety>cPQACQpacLKZla!&$iGy)&vczuU{cxEPZKD?l@}vpHR}cQ!6f z(2s@7OoPFNkdWIYs)`&SW_D&+K^MIUp!CH-2oCPJ>BS}^MG@W?lN!R{F=9Vk%GTq= z3F>tZzBv5gh$G>O19Mn$#H|Xm?0PL%arr9tQK+&j_*Q8!cklT#>b5qt_$;w-UY;R3 z(MSPC1rcB~F&w_{;c!w`@D`~kK|FH}OPvMDE8hi6XEe)()+NJjKt16NJ%unVL2p|+ zH9-y!30shPkg$F_!g6pzEc4Y(Z2MCd62VtnFFEs}-r`_6=3ZN0_hY4DxRPZ8Pvvq&Z@+Cv6ruZOpAQF(A@Tha3s zA!lKM_%yRHgCJi;`2XI8oRNk7&tuyU-#Ys3ME=|T8T8=3{_oBCpUEr$4iE_9h5q}a zGUoF;nm($k=Lu~K``6sQAOL{AxYYrs21AftT`_=ynMRQUC6u){kjUTyTQUfSj7*x} zMD86?MLxQmLX{k)jqEq6Bdj>1@wsU>ZTAt5)AT%>aW;!4@aSkzM!}Ob8xQhZ&xI$N z4r$f=g=Q}In@!&HEejs|=id7*3;V|NagVU6lm(?#>))3ds108hKVmcUO-pt6cvFZH z`IN%QLhMsx;=p(du(@iUQrRkWHE3K)|MUFUsU9)fpFf)z~iYc231C`9v-p3o~L3=y#w#phfjNXWM5|ZY2 z7ntsn(KI%kH-ZaO_lz;4YgkRuz_8vc#5dEeu<`cW;3kW3_B)6qm;$ z{~OQy1ik!w6N}RLo=KvMyd#hIFLu6NEjeL;JHp7#>BB2%wv8|W>v%~QkHsR60z3oL zZro@ANpx|R?;6#^0VouaDw+N$;?+-zFz7i)`ZjW=PxyPMoYe=XCq=E{xYLbCvs_$B z7DCEUuhQ}2<5n~2J>r3W)Zd=eNP_V{;451o6UEC-WYdw3Pe!JvZE-Yy&S?@p&q}(N z3bqI&$u(w^7#yDHNd?E~6}k++HHj{=Vx%|Z6^2$Moax&W6+|e@65R>6PUjE4(K9JO zFfE!cKzdhKH9JVUUU(6HGjoG3(BspwkSOISg|3`C#`rWQ@;Oi%*srsSeaUjke#!ot zw%}W_D!W{Z_){o!OAMPR=gc#rUF_YdKu_&AjgCqh?7L!WUPY@UJW?!H6TL!(n?ysD zw<2TEsi7L=MS*G+GR_ni=# z*$=+(s%ehgU-h^Uy+OSRzmZP==-?f6AKe!DxbT8%ESV->W@|*b|CyTq_x!Yc-u&B< zqLXH@QfhB2RsY22{G*5?#-iJ1KB{|S-hO=Pe)VyhZ6O<(;7SD|MUtM-4E2IwM00?$2io ze>NjkQsS_FY1f>)!eUd$xkBCD4n%OLM+W^3DT!MI13HR+{XShXXRl5JKJJrA!P_R& z4li$imQt$@dozUx9E0X^kK;axlvp6J8dW93FHg{S2t|6myO`0u zGq@->RQ#N3)lm<8JIwWBR`Q4bQUTrYK0e`NrotDqwi$o);qBaY()p2(E)-)?G&9?i z(l4t!EGg98#1OiibWA7@H4iY6*M91+&eN?8W)^*?^Cfb@a(T64gu)m^v{~4cA%Pj>DVOi22yw zs5zE#=ER$Ny)yHfzRCP2B;YJxm7o}rB%L?}LB`0(?!IBs67NuzYu>{3<0*dx-5 zM|48TuefH9plXtoYnHS2GhRU%V1{iyE>|rU<+j$oW%#C2H$c9w3(K3ol{K2MQj)h4 z8tQK*QU2ENKIt^m{6i0IyaxQVZ4F;g31wRo_nV1^j#1WmMH;2ABuDp!Q%`!n9FkNy zAos(BcGok+?x>9R5X6^@P0qL4cM_3W!8NUY95oVG+D@_}?bU9L4MjUleoo*uEPrvO z>w6!>6&owJH}9UUc!Z7I(xd!Z)h-`RtBH8z!--i+k+>x-*C-?%wQRxDIm>BvlNbG+5OZQnQmunH*p){OapXxa4JJ7xCfy82l zhbV`NudEFE+;LU>^xq4dyfMSiZoJR1`$##7GjWJ`J@oNgB5Fb>+qydyZ#4Ee<9_w_ zyKg_T)&QU`Q0-$Pnu;vet2W{$pQS{x56tXr zvKn3zWco@<5);j`p)wX7&8=??7pM#HSnIoPl$d6 zHu?}-s}r70&&HpPWh1W5A+onuD~cG)nY6nclXHp9E9XAwo}8xtS>|S^ZhKBevg+Zd z=OiiW7#gOI9N$P)wtCg{XCs7Nr)3!}{h5ido{^lByh^R#K{ZY_w0y)Mo~Xz6MsrwS zO3*id=BhVAQ>G27(rw39Jr)Q76UPgt#mCJR!Q|IU9#Bs-bH1@8rY3f#Mn-VkP(eS_ z1#isN8}1Mms0|;Hd3v^UFh{p$#{$!%{0DO5C+EJySG}h=4(d*|D;=m~i$Aq{xuBl$ z;a3-FpNaZBPCxA6VHYE`?Q5q(R}@R{f~#-oR8nJy3S>`?==Fqlt^{SgGN0zxb=N%kpF$#qkmW z;`WB^9mgG_J90G!wA%WQi78U@Z|8M^E}8! zt3#s}P)rjXpcbI!uXIMCeW#=u{8okX)t>QtZ7Fx&>`Rh&E>k0zSeI!_)%4pwlBaN9?gE3*~6w#a0b&tjI( zVLsdubh}4S<&eY6pvIndXM$av)c*FMA3fzuq`vmJ(bu0eXSL*&bvq5+vg`G9JJ`sl zOx?^!(9d(K)brk<-0%gDFuf|Mh@iz@^!!duN_~sbTYRflVOru+sa6>UI}_NQ^mu2| z0qnTp{MnGW$j)X;>vC}Ed(7TcrWdQVh>-{fhwsnZ5f!nLZ%wZ{wpg`as$l8i)08`M zS2BYVq7cURB zn0)p&ZZ27Cp;@PyNMyAd=Adc3UMWJ1fxY9@jOPfQue~SYI^b>E?K*DvcIXnCwy@bl zz_&NU_eWuzUPf3x!Ce>j9@MKYb6jn*zlPpPw(vE%WM&xh+SiTWZXqH=qhPta+c!$r}nVzjL5n+Y9?<#i2s@;=&+jYqK zd8N?)P=@2G7fzq0B^Rp5n4u0ud;F|c%hzgz$s{Y3HGB!W-iu+|1=S3qO{kt`LEIJ~; z5Yl-NpSbicam2NYJ`2-yOzma7CFrS|d&sWD=iv{C%9G&Q5HKjvz4hT}g{t)wtk(M+ zu>!Mt{&Hg#duVFDn&8bTL=MY2ezKg+UFA{5OO|%|Ak?z4BO(3d5?7a=K%XK{55pwO zg7jmrN>n=gn2PWvbHC?ulYVa+cy5F^Q&QSKH6J#)xlg^&e_I__us_d2@E}`OUH4o0 z_K;IcgBQY1mf6-M6BRBi;5CdCgYEcIz(N_UIRnv$3RXGU-TQT)4~+9Ts`tBSyyz%Y zn|bmnFpie@y#D!wPb5O)p_A9o6*J1Le8PJ-441Oc3*wg|p3$u`xl{|F{ z3K%pZs%fZbTf0Cvf{dw&hF-1!BB#=>uAL)yadE;EsE5K~P+bxZPXeNpg*UQ`K!I>& zdjOMq2`d2vz<3dWMN`F;%F4E-xm!>#HT-*{S?g?Z>yBI7+4v*u`0u;zuN-k(cQpW- zVybu6IpUFi%aHD zNxkZB0nNGP1zR|j!{ql-UZb8+X(1h>wXNTXd za9V!lx4K}w0@kN5H&V!l`t1~L8mX$*a9I%7H!MX6AonGNEH-5ya`z!ihnlRgjuidq z3b*7rH5UjvLTvE7<(865z;_Mj`1XCue%f)`J5ix3M*7iku1SnSw}OGraCD5l%zV=k z{in}#2S=6yRiFV)zr;|Z%MtJdS4sm@6u zd;1gz@qb5vE@&=5O`7gho+y4Y+Q;UFPFNJvjXPmc%UCBx6b#`#Ux?|;>!C>a8JaT^ zKPEigKk3wzeK}1bspUX+*DHKh&jqWa2YYiAu1)tOKDth@nlS1zpDPG^F8QMjgRHib zVeYgWhT0~FWxO~pIRs`cUNsV_ZEMMTUKrqEe2S|)x2LY7u*Y=jCDO@^^KxEF#ASZf z!=e^oc@y)UD@|>~N-H8nXVi8eWm0><^sZM4D<;E*PhTnL zTQoOzXFva8zN?JyQUdq1a@7r-YKrsMJR=V|!>q>^0_-nW9gTXnN=G~w6}!=&bUWyDaP9u=GqpXW zw_OQ`(yOJQGphy+?ui!*WyoD9ZaF!ruOCWKftU4K%uQUD8q;6hxt3+DAW55znx0{( zRj)Nli0fulv0ZWcW}CQIxSST8C`dEOw*5y0h~h4gYC+@qD&~_OCX@gA1N=+#TIH2w zTEdl`EJD`k~P~w@)0HNDFbt)w()KFyjNco_W83Ygsn)6=auCn z)dmgfXIS|5F1KLCGJQjGNiX=S-KhE^u{yM~Cqv|*ujZCx5-MvqM^deKps z@%|SAy#myO54dD_P7Gbp1vPYMale0m_53BFmdelJxeEDLVAiGfHB3)AW(sJ9xGIHY zLW0Mz=dM3yi*!5~&VGyw>7o3_SM|LbL~f5Kx5)OBq4V&^x$1`JbF%0!aO;PqU1X|o z5%oX{us}+9#c6-YB_y_nb$?RZ>9P0QfSsdjo{Da;yl>VBi$t>Wol;b)QSF`P0vBh; zy8=b-@A+7MEdIb0nJ&H~UD8P_UvwTwWbID*s>-%nzK~3ZFsT3HVxQj7?+?3L-&5pVIeMoUCVgh7CrAsb;(uAP z%u+&`g4uKaTuL3ZpQn+gVlWbHt5thUP#w!M%RVhC4#hCr$9c*(9hJ2rn1L%uA?!O6 zdGXxrUiLD3Ua$<6_#GS?wQ&G-`STAmQDkO!efBJwiSirFzaD8mE0AXtd7YvWetL=$ zR(E*SM}hBF#gF5rIo0hV!ZcPAwYCUbHJ`=U+p{`i6cg0&zPmaijp2gaJ0xd5EGAtT znIjCJkS0S|#VFUu=%pb~J%_%`4G`787?$Nt@`dv`PTF5*ZF<5t*+-lHGv4h#~+TufV&+KnYkyYMcqK$9y~3PK%*L>&l{zU#GYKcF8phy-3dp=07%RWtMFYtj`lGY_@RRw^X`mzW`k75 z88;J%ngo0$bu{JU1uK_2uQt&#!!jB(p$4T%BiiDC1^F+y4kuO7T^KYvJ5j$z;$d^E zm|McIS!oo+EUSF~o?5<_SNF!~%*TaBWW#vupQqt9`Qj6cD{&mN8Wdj7BlV5^B`wlK z&up@O^nJQJtDT>>V;4<4GY1THcg_przF(kq^jBNWV=(Fc3VEp&73svLz_@Dj$mdoK zWhPqs%H20^C>7PxWo%JT5#o!P=3=Guzxd(-{pO0q0W z&z~O2u7^Ozj>xI$3@51JcJ3~d@H+B!%2$%$_kD-my_m_RZ>a(qca4>LIlDP4K;0*^ zXvSm9oz+&{buJi+v-IvIJq;Dmod#OzE*L(yl$Nt0H`Ke2#Fqrt zo#Zk7!w>1imU*s|L??@jhptz@y%gBc{)jg>jfta|bB+NoFd8^-c~H)w$kf9mu1t({ zr=j?WH+neM^5*F0tbE7%boETO51qGa96c8AEqu7$8z0H=0cjLglbJfv!Lh7YQSq#L zzrz_b70W1bxHjVkPQA+yE(h$Y%>%T zvebimpZnG*ZkzhHIgbN3Pr5h4GEl6Hq3SW`ZC-H3lemJOCN-|?J_L~I_NX;k##UnZ zIvLxaNFR25R&xH1pkZ)BRaiS+$11UPm6nTUmi_zG-+|jL3{E<31Xn;iVV#hB6E|(4 zQ!<3AY^HCCa91X}0T2zbj#t)19H5%^I9H1`4lV-_6`L4PbuWG@K>SUlu$i{jMw~EG z3ZUFx3+>%dhuB=ZV-!3A83ji?8Ds-MKWBOHWK9DYWRH^vo1(N~+Ahj?J9~9+65h~T z#|Z1~h?T{G6^=4uJkg#67XqL)0rDg`IlH1g<-yie#E1s2smV|Wf5?3kfED1NEZuWQmSwQ41h4wXt*RADGNSI)$qWO zaJFaz71f_*0srK|c4V>(8VdFB@PK$AAw<$yC?IAc3xy$|2!sTXL&DX|nQZMT;q1!4 zZe+vG2F$i6I)kWot!;>IWO*?77qO6^jk0$6qabHj$XWv-SRw)H2|#Q(1P1-XGSxVc zh*kz9LIC{+BO=l1sGi}Pnga@gb8-Ti;7P935>XHYhWhv~IX8=5GolU12-te500de` z0cS`{z~K@IStGz7C`q)Wlmtu)4TG&4*^={5Hr6VF{~a4!a{jb|fl~dl#ZPOU@c-~1 z4*Q4uT--=bYrTZSLh(w_t$}R{d#p7X@EOzvXN!Su-rCYq zAQ7NabHZ;_5UAruH31T`UsE@3IN4K&5!%Vx`K&zHQv!##wRUqNgO6(4V@X6;qAeL@ zN+jVx5+GG;U_ct$;en~4L;?g(fYSxCz##)w4IL#d2#$zdcaxL-uf?pV{#yE4?f+a+ z3{ZLO`f&M^1*-QA@#lU`-K_pmf+LYY05n)|IQ#!phhI&s)!|R&{m(iY=%GJ)`j?3U z+yHtR`D-r&iD+PJ0_TRsla49@UbnF(gH(WRCwnJALkJ`T0j3s67}#~g5j|W*Fx39v z%>Tb0qrhC$*8cm-Z_IK6;n(`FJ%UytV%@0wXc{U<-Q4VPXlaxU${J;ZlmNu5WF;hJ za99aI9tD`a*0!>6Yd8`ogT<}QT5avE&u$sb>vlDq0VyMAEPlf-!de!KlY-*_ladGt zNnpH6*hr)B5(pcdth9|JP7(zwX-f#cy2w>#pB$(q@)_-L>h9-?;kMUBBU^%`E@P zU5uMx5Wto4U=IN5{S8C)mIKXe-~m{pQ-OxC3YrR6sLN!yBua7(sR+SfLLyKlH?kd( zB)nza3VfnlU-}CF6G{@He!W^-A`1W0647#Fjc6$%0tKMZf3AcP6(|V**QqFhs%M_dDPz@I;99CoXRr&Ynl`c z25cVuISmQ;`_E}of3XLsGXh`0f6XT=L)9GINc)RMr!3I4t-6_TIH2hIQ#teh08?Fu AHUIzs literal 0 HcmV?d00001 diff --git a/test/unit/test_convert_to_pdf.rb b/test/unit/test_convert_to_pdf.rb index 438a4a3..2fb17ba 100755 --- a/test/unit/test_convert_to_pdf.rb +++ b/test/unit/test_convert_to_pdf.rb @@ -12,6 +12,10 @@ def test_rtf_conversion assert Dir["#{OUTPUT}/*.pdf"] == ["#{OUTPUT}/obama_hopes.pdf"] end + def test_png_conversion + Docsplit.extract_pdf('test/fixtures/image.png', :output => OUTPUT) + assert Dir["#{OUTPUT}/*.pdf"] == ["#{OUTPUT}/image.pdf"] + end def test_png_conversion Docsplit.extract_pdf('test/fixtures/image.png', :output => OUTPUT) assert Dir["#{OUTPUT}/*.pdf"] == ["#{OUTPUT}/image.pdf"] @@ -23,4 +27,9 @@ def test_conversion_then_page_extraction assert Dir["#{OUTPUT}/*.pdf"].length == 8 end + def test_name_escaping_while_converting + Docsplit.extract_pdf('test/fixtures/PDF file with spaces \'single\' and "double quotes".doc', :output => OUTPUT) + assert Dir["#{OUTPUT}/*.pdf"] == ["#{OUTPUT}/PDF file with spaces 'single' and \"double quotes\".pdf"] + end + end diff --git a/test/unit/test_extract_images.rb b/test/unit/test_extract_images.rb index 045b4a8..1b1dc4e 100755 --- a/test/unit/test_extract_images.rb +++ b/test/unit/test_extract_images.rb @@ -41,4 +41,9 @@ def test_repeated_extraction_in_the_same_directory assert Dir["#{OUTPUT}/*"] == ['test/output/obama_arts_1.gif', 'test/output/obama_arts_2.gif'] end + def test_name_escaping_while_extracting_images + Docsplit.extract_images('test/fixtures/PDF file with spaces \'single\' and "double quotes".pdf', :format => :gif, :size => "250x", :output => OUTPUT) + assert Dir["#{OUTPUT}/*"] == ['test/output/PDF file with spaces \'single\' and "double quotes"_1.gif', 'test/output/PDF file with spaces \'single\' and "double quotes"_2.gif'] + end + end diff --git a/test/unit/test_extract_info.rb b/test/unit/test_extract_info.rb index fb85030..54c4b61 100755 --- a/test/unit/test_extract_info.rb +++ b/test/unit/test_extract_info.rb @@ -32,4 +32,8 @@ def test_password_protected end end + def test_name_escaping_while_extracting_info + assert 2 == Docsplit.extract_length('test/fixtures/PDF file with spaces \'single\' and "double quotes".pdf') + end + end diff --git a/test/unit/test_extract_pages.rb b/test/unit/test_extract_pages.rb index 602a659..cc885c9 100755 --- a/test/unit/test_extract_pages.rb +++ b/test/unit/test_extract_pages.rb @@ -18,4 +18,9 @@ def test_doc_page_extraction assert Dir["#{OUTPUT}/*.pdf"].length == 7 end + def test_name_escaping_while_extracting_pages + Docsplit.extract_pages('test/fixtures/PDF file with spaces \'single\' and "double quotes".pdf', :output => OUTPUT) + assert Dir["#{OUTPUT}/*.pdf"].length == 2 + end + end diff --git a/test/unit/test_extract_text.rb b/test/unit/test_extract_text.rb index 9ad383e..f4ee7d0 100755 --- a/test/unit/test_extract_text.rb +++ b/test/unit/test_extract_text.rb @@ -44,4 +44,9 @@ def test_password_protected end end + def test_name_escaping_while_extracting_text + Docsplit.extract_text('test/fixtures/PDF file with spaces \'single\' and "double quotes".pdf', :pages => 'all', :output => OUTPUT) + assert Dir["#{OUTPUT}/*.txt"].length == 2 + end + end From c50dd9ac628468feaa9aa41b7c0d48d5117aa775 Mon Sep 17 00:00:00 2001 From: Vladimir Rybas Date: Fri, 22 Jul 2011 16:48:14 +0700 Subject: [PATCH 2/4] Escape icoming file names (closes #11) --- lib/docsplit.rb | 9 +++++++-- lib/docsplit/image_extractor.rb | 5 +++-- lib/docsplit/info_extractor.rb | 2 +- lib/docsplit/page_extractor.rb | 2 +- lib/docsplit/text_extractor.rb | 17 ++++++++++------- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/docsplit.rb b/lib/docsplit.rb index d4746eb..8f358cd 100755 --- a/lib/docsplit.rb +++ b/lib/docsplit.rb @@ -19,6 +19,8 @@ module Docsplit DEPENDENCIES = {:java => false, :gm => false, :pdftotext => false, :pdftk => false, :tesseract => false} + ESCAPE = lambda {|x| Shellwords.shellescape(x) } + # Check for all dependencies, and warn of their absence. dirs = ENV['PATH'].split(File::PATH_SEPARATOR) DEPENDENCIES.each_key do |dep| @@ -62,11 +64,13 @@ def self.extract_pdf(docs, opts={}) [docs].flatten.each do |doc| ext = File.extname(doc) basename = File.basename(doc, ext) + escaped_doc, escaped_out, escaped_basename = [doc, out, basename].map(&ESCAPE) + if ext.length > 0 && GM_FORMATS.include?(ext.sub(/^\./, '').downcase.to_sym) - `gm convert "#{doc}" "#{out}/#{basename}.pdf"` + `gm convert #{escaped_doc} #{escaped_out}/#{basename}.pdf` else options = "-jar #{ROOT}/vendor/jodconverter/jodconverter-core-3.0-beta-3.jar -r #{ROOT}/vendor/conf/document-formats.js" - run "#{options} \"#{doc}\" \"#{out}/#{basename}.pdf\"", [], {} + run "#{options} #{escaped_doc} #{escaped_out}/#{escaped_basename}.pdf", [], {} end end end @@ -113,6 +117,7 @@ def self.normalize_value(value) require 'tmpdir' require 'fileutils' +require 'shellwords' require "#{Docsplit::ROOT}/lib/docsplit/image_extractor" require "#{Docsplit::ROOT}/lib/docsplit/transparent_pdfs" require "#{Docsplit::ROOT}/lib/docsplit/text_extractor" diff --git a/lib/docsplit/image_extractor.rb b/lib/docsplit/image_extractor.rb index b7eed1c..2d7f591 100755 --- a/lib/docsplit/image_extractor.rb +++ b/lib/docsplit/image_extractor.rb @@ -32,6 +32,7 @@ def convert(pdf, size, format, previous=nil) basename = File.basename(pdf, File.extname(pdf)) directory = directory_for(size) pages = @pages || '1-' + Docsplit.extract_length(pdf).to_s + escaped_pdf = ESCAPE[pdf] FileUtils.mkdir_p(directory) unless File.exists?(directory) common = "#{MEMORY_ARGS} #{DENSITY_ARG} #{resize_arg(size)} #{quality_arg(format)}" if previous @@ -40,8 +41,8 @@ def convert(pdf, size, format, previous=nil) raise ExtractionFailed, result if $? != 0 else page_list(pages).each do |page| - out_file = File.join(directory, "#{basename}_#{page}.#{format}") - cmd = "MAGICK_TMPDIR=#{tempdir} OMP_NUM_THREADS=2 gm convert +adjoin #{common} \"#{pdf}[#{page - 1}]\" \"#{out_file}\" 2>&1".chomp + out_file = ESCAPE[File.join(directory, "#{basename}_#{page}.#{format}")] + cmd = "MAGICK_TMPDIR=#{tempdir} OMP_NUM_THREADS=2 gm convert +adjoin #{common} #{escaped_pdf}[#{page - 1}] #{out_file} 2>&1".chomp result = `#{cmd}`.chomp raise ExtractionFailed, result if $? != 0 end diff --git a/lib/docsplit/info_extractor.rb b/lib/docsplit/info_extractor.rb index f6a72a2..3d50d53 100644 --- a/lib/docsplit/info_extractor.rb +++ b/lib/docsplit/info_extractor.rb @@ -18,7 +18,7 @@ class InfoExtractor # Pull out a single datum from a pdf. def extract(key, pdfs, opts) pdf = [pdfs].flatten.first - cmd = "pdfinfo #{pdf} 2>&1" + cmd = "pdfinfo #{ESCAPE[pdf]} 2>&1" result = `#{cmd}`.chomp raise ExtractionFailed, result if $? != 0 match = result.match(MATCHERS[key]) diff --git a/lib/docsplit/page_extractor.rb b/lib/docsplit/page_extractor.rb index bd26266..3e8051e 100644 --- a/lib/docsplit/page_extractor.rb +++ b/lib/docsplit/page_extractor.rb @@ -11,7 +11,7 @@ def extract(pdfs, opts) pdf_name = File.basename(pdf, File.extname(pdf)) page_path = File.join(@output, "#{pdf_name}_%d.pdf") FileUtils.mkdir_p @output unless File.exists?(@output) - cmd = "pdftk #{pdf} burst output #{page_path} 2>&1" + cmd = "pdftk #{ESCAPE[pdf]} burst output #{ESCAPE[page_path]} 2>&1" result = `#{cmd}`.chomp FileUtils.rm('doc_data.txt') if File.exists?('doc_data.txt') raise ExtractionFailed, result if $? != 0 diff --git a/lib/docsplit/text_extractor.rb b/lib/docsplit/text_extractor.rb index f9786ad..fedefb7 100644 --- a/lib/docsplit/text_extractor.rb +++ b/lib/docsplit/text_extractor.rb @@ -45,7 +45,7 @@ def extract(pdfs, opts) # Does a PDF have any text embedded? def contains_text?(pdf) - fonts = `pdffonts #{pdf} 2>&1` + fonts = `pdffonts #{ESCAPE[pdf]} 2>&1` !fonts.match(NO_TEXT_DETECTED) end @@ -59,19 +59,22 @@ def extract_from_pdf(pdf, pages) def extract_from_ocr(pdf, pages) tempdir = Dir.mktmpdir base_path = File.join(@output, @pdf_name) + escaped_pdf = ESCAPE[pdf] if pages pages.each do |page| tiff = "#{tempdir}/#{@pdf_name}_#{page}.tif" + escaped_tiff = ESCAPE[tiff] file = "#{base_path}_#{page}" - run "MAGICK_TMPDIR=#{tempdir} OMP_NUM_THREADS=2 gm convert -despeckle +adjoin #{MEMORY_ARGS} #{OCR_FLAGS} #{pdf}[#{page - 1}] #{tiff} 2>&1" - run "tesseract #{tiff} #{file} -l eng 2>&1" + run "MAGICK_TMPDIR=#{tempdir} OMP_NUM_THREADS=2 gm convert -despeckle +adjoin #{MEMORY_ARGS} #{OCR_FLAGS} #{escaped_pdf}[#{page - 1}] #{escaped_tiff} 2>&1" + run "tesseract #{escaped_tiff} #{ESCAPE[file]} -l eng 2>&1" clean_text(file + '.txt') if @clean_ocr FileUtils.remove_entry_secure tiff end else tiff = "#{tempdir}/#{@pdf_name}.tif" - run "MAGICK_TMPDIR=#{tempdir} OMP_NUM_THREADS=2 gm convert -despeckle #{MEMORY_ARGS} #{OCR_FLAGS} #{pdf} #{tiff} 2>&1" - run "tesseract #{tiff} #{base_path} -l eng 2>&1" + escaped_tiff = ESCAPE[tiff] + run "MAGICK_TMPDIR=#{tempdir} OMP_NUM_THREADS=2 gm convert -despeckle #{MEMORY_ARGS} #{OCR_FLAGS} #{escaped_pdf} #{escaped_tiff} 2>&1" + run "tesseract #{escaped_tiff} #{base_path} -l eng 2>&1" clean_text(base_path + '.txt') if @clean_ocr end ensure @@ -100,14 +103,14 @@ def run(command) # Extract the full contents of a pdf as a single file, directly. def extract_full(pdf) text_path = File.join(@output, "#{@pdf_name}.txt") - run "pdftotext -enc UTF-8 #{pdf} #{text_path} 2>&1" + run "pdftotext -enc UTF-8 #{ESCAPE[pdf]} #{ESCAPE[text_path]} 2>&1" end # Extract the contents of a single page of text, directly, adding it to # the `@pages_to_ocr` list if the text length is inadequate. def extract_page(pdf, page) text_path = File.join(@output, "#{@pdf_name}_#{page}.txt") - run "pdftotext -enc UTF-8 -f #{page} -l #{page} #{pdf} #{text_path} 2>&1" + run "pdftotext -enc UTF-8 -f #{page} -l #{page} #{ESCAPE[pdf]} #{ESCAPE[text_path]} 2>&1" unless @forbid_ocr @pages_to_ocr.push(page) if File.read(text_path).length < MIN_TEXT_PER_PAGE end From a65fc0aeb18b01de2b45bc5d17402658a0cefbbf Mon Sep 17 00:00:00 2001 From: Vladimir Rybas Date: Mon, 25 Jul 2011 13:25:55 +0700 Subject: [PATCH 3/4] Escaping basename in gm convertion line also (issue #11) --- lib/docsplit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/docsplit.rb b/lib/docsplit.rb index 8f358cd..344f5af 100755 --- a/lib/docsplit.rb +++ b/lib/docsplit.rb @@ -67,7 +67,7 @@ def self.extract_pdf(docs, opts={}) escaped_doc, escaped_out, escaped_basename = [doc, out, basename].map(&ESCAPE) if ext.length > 0 && GM_FORMATS.include?(ext.sub(/^\./, '').downcase.to_sym) - `gm convert #{escaped_doc} #{escaped_out}/#{basename}.pdf` + `gm convert #{escaped_doc} #{escaped_out}/#{escaped_basename}.pdf` else options = "-jar #{ROOT}/vendor/jodconverter/jodconverter-core-3.0-beta-3.jar -r #{ROOT}/vendor/conf/document-formats.js" run "#{options} #{escaped_doc} #{escaped_out}/#{escaped_basename}.pdf", [], {} From e71f75d28e11ae79437ef29e5ef1f6d1b61aa0a5 Mon Sep 17 00:00:00 2001 From: Eduard Tsech Date: Fri, 9 Sep 2011 14:55:49 +0200 Subject: [PATCH 4/4] Add `brew` to installation. --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 0d21e0d..964583c 100755 --- a/index.html +++ b/index.html @@ -125,18 +125,18 @@

Installation & Dependencies

source, or use a package manager:
-[aptitude | port] install graphicsmagick
+[aptitude | port | brew] install graphicsmagick
  • Install Poppler. On Linux, use aptitude, apt-get or yum:
    aptitude install poppler-utils
    On the Mac, you can install from source or use MacPorts:
    - sudo port install poppler
    + sudo port install poppler | brew install poppler
  • (Optional) Install Tesseract:
    - [aptitude | port] install tesseract
    + [aptitude | port | brew] install tesseract
    Without Tesseract installed, you'll still be able to extract text from documents, but you won't be able to automatically OCR them.