+8JE7^NI(UAushlsfJr$-?gX z+U;9Ib={>t88>%p1}#l3E%}8p#N8$=N{!VM$^#cYV^1q57#bNEB%HkE)GgF}%E+j` zrsjf7Y{$eM!d=EWBw-xJAp2H@ckWbu%2QKR%*)AXNDrJ}STHm+RP}p1-B)GflO3+D zN@4g;+6~1?BvPqfWr@75uC9k7hs0{KY)-c2*b!ypSSoEqyCP2_zQ|jrb9#Cja?%I) zhoB=rJ)Zlw)@?0)x3;#{&~TBFuN%`zHc*^VZ0N<>tLACfcj%_4XV$b+fy!QcJpK3UjCD^+87q%;n$S@scVge8a|GlWZacXo zpDI29SPsi+ X~E7{Dum6t9MdE`^)v#7Hkg)hSAffF=NCt-h|#oSOjG)2A-AOJV^(1VTB# z?k_eed-m*E;a~S9_^vMS$W==5kK`Tr(09(I9&W%R`84VomEnFxv(tyh7#z!H_B7|; zk$RMI*M+^bw3J`3MaOrZeWI808qaG K2o=&e?tO6&ev+57%vgj(WaPhj@oG_ SIFIf-Ini0{HFnV50Zs(YSxJ2%`ct7>+bE4p zmnA-74Xm#&w%INh#miaG{`6EYMKQi+eyq(x(rUTa>WFSkaZiAogTwRb$YJ=iydChC#7goapYfZF2btNt>b{SH8~k@+vTH zp%_?_q^lD&d^x4>c<-CF_wxIKTVi_rN%8+^fnt0aLFINj}wfL^OgWGXE+y)naQSL>n)!qO7c}qEhHwpBNe95Vjxc@slS{5<@qZ zq2l%^w4Qx#Dyuo)VxnTirY!pRe|k*5rD>AZ^6As>j6(pre(w^QFc(?U=*WowJln#} zF5ObDuD-qvTUqp!Oy)2{H}AKWt=D>m 8cJ^c|%?9#3cln`Qyir&>o199%r4LosAOI3%g&mcgT|Tp!j|`^Jd=l znk=c*f7YqC4+3CCzvvnx4Xmd}c_2(^myE9QY)cz+V?JPugN>ZLyzs7FQYUUauNL+V zosO{2R9A$oB5ln*O8UIFeCpnSZ|bX8i9s{f#%Tp3JNPM6n@_~#98|F@F3NBZUaSak z%}St1S1Z+Hn`Z*?Wq!GX(?uHxn;fcIot{YI3xAl+BX>5pcI{Kvjk%KB?ssWm)cCcE zQ8zP`TlBcwfftKp@q}@yo0 *dH)eE eZoyhOtdSUnCS0! zl!>(pSsZ0&K%En3Tmr(^ckS7=OJYE&DzD^9*zDw=3kynyKCJs+NntKa+R0tFV6K=k zOpI{r1R)_~i!U@G3z?7Zs)0})Dk>_xOV(ftH^F(X8Mu)7OiN`RI4i*qKkCPo@F! z?jDv;hkhd-YMke?_p?(z&Du2(4~(65@;*U5c&wEcX?R-@c|cV?2 K1b4@AwD$%LUBbbg~3gYkG^UZ>m_?xcx{3!cO(#7?=iwg^)5tXD^E#G}s zgdz3N4JdFy8XG72kXHZUKU|Qd9bT-7?HpDg@Lq;;e>8eeL?zsMd1l}vOJ8*RJy_4c z(9nG7sb?jS?%KYpXen+lsgoDBOY88S?VXx`(nfhapi4dJ<}Gb)7Qw$|a=s%7{Q{kn zLdn+~jhd~~n0)l;k+iPj$&>!$?Z vYC z7ra8K-G51zbU!>CD%jN2)MEJ} 5^+XJ~=5RA)$F|utuh|(kOJLnOp@TW6_y1Mf4Pf(r%+W ze}JTyVvAAJ& mz@w6_vA^_2qCsp z(Dxx!fQ^j}TTGjS(@A724Zi`JMXaBmgRT`FGWVje3Q~1&aPWzSm6;EXwMA&BGIheU zr_9Rh``!qJ@;4O~O&F*zz914pH#c;of=v(a@h<6l`}Qq}gi=*?NvvOk%-=^r&YHyr z`(6=+as(peLTa v(NI!##WC%;BASO_8*LQwhrka?Fc76?CI%|n0}N44HtN23tSu%wj5{X z96@7B9obeo?i2EC0;PY-Y$w!l q@?Uuzd~hk zch8)bUs+j!3RCy&Wd6eTzP`S_7+b$FS~2j|(O|zcQ){+K9NR6W8@7?yG3;GY+wLMl zBW8Pru6FWz4tRsSuMp8Iw(2=m(6fc}_+01uuNPuoQq;~O+*809SmI@N+Oy4d?&f-N z=xXu&zutNOioe#q- CFrHtZl@M!PD-ZIpu+1*xq)%p#VX|(_KCE9(JROIH z!v#3IW|`TfneLR*!UEJrno^32k}E5bJcZ-P4(7QXuy{o?m5syTITM!(n$k>CM`;F( zOoRM$o!Z|>u*88cUVq)ew8dKmhlPa!zqK#Ce3=b61-3uEGL|iM(%W%h8UmaBFl5Yz zJ6hCF1o~Jg6f3>_*`mB@!Uk%Lg?+HkjT5QGE*0`dcCN@=Jt2`o3EW&?q-;wzW4{4S&N i7iA(NbMdjYAqs7d14~EHIzRDl}fqZzk6$nFMjI+x@ zwfTqv0qp19yECJqi_FaB9MDJP9Xw)~v~FF3#^RTXFsP&1CPky?LG43!x!#B?JYA3; zd~=Lf%(Yvd`1I*htdUm9n>Xz<;vNcC1Uj^UT3iWo_5!6BedV`qYuE`*g}Pkh93`n) zx?rkO+CRI@T&6J7)O6=4+%+eP(3@YjY}s<_)-4a-^P`a0+0&yH^LJg$C{NDd1L>oG zG@9c#d*P%&(zDq`$>ekL$( p8h ;_wF5{3CqjNv+zy7AWJ;>F%M zU~Yc?C!~3F_xE+G=@z7u&q<}rZ?k!Gw!c1PA)jXd^6JJ?6|SgX9UiyD))Pd|U6(`M zZ*IOAyqRyomnf-Fmc#Y!?YT6YVsg!2Jc@Mb1<~#T{WwgaBQ{|gT8aDO?)I{PSk^8{ zZ2Lb7g94m%SAvWZ5Eaic>Bh*YLou$R@^LIm`59nZacPkKn~fi@<#!auL5HQhX?cY^ zg6vv=qb;&k@;v*;cxm0RDrkE^bD{J`MW&L^#Y$H@<->`?srYWTai)s$k_O?})&>*| zMCnk2$yc8yCiZA=b{6cyt=%}9!30jm%=E`582Wzoeg#sRyTRiY1@3V-4m(*Jjoa`$ zq{B}Fck6oME&+$Yt}_4p9_{znpqCeWaWQ+gOMG%?%dOxxXK@Bk-T{{yC D6 zx7>W`v1J@HuPUM$vgQ}A(`2bifwpwPS!Q3ejIfL{ZlV2Z!oF?DGv!<#glN0~>*d`J z1?AaKuoOrxusJ3UfDA}XOq2;5?(OYOKlsh~)4cKJEyv^lyYs?a$x!0h)bFl(G1Am} zoZr;*i-&(m*65bnm d)Ys>O+$AU*05(3g`Hld^~ zI&`g%Too;$(Hj4qG7+>-Vj@Ss+33QBN72Z|O4j%UmB>}nD79Ha@}DRzz|sE-#uaGu zqrSbipc_qP+56+7zOev+{rsO6Rcrl+a8`@Qsq5p;8pmSNmzS55l9Ehi=c{lVH=%QM z7t_55^lJO?P1<8=f{mk{Y&G?%!e7nYXd}YQJg-oj*(DJpY%Yn#Kl%j6M94EswFf}R zpySEEn6Ig;gFaqtDqHCM$N;QY_;$sXbgF(8QQdYYq7t?!?blB+W*nMsrfv|xRs88_ z7+<3Ui6cga5AsuI8q-lGip0<5zJK!Dvq?7*A%GZb=RY9wrnqr*AsMmqh#vUm4Ey!; ziVlw-lg&I5zOy>K2N>2^0zhi%Rkm$@AS`z WV;K{@jg$Q=d7nzZjMwI&=00Jb=QVFUe>6I~qdX#R5dn}yeDmXE=gnohP9 z2{on@9UJ+cr zWS!k DPX6BK=rcJZ+CQ}d_Qj^y|!Y9~%Stslyml|UR{Xr*Hp znpY-#nKrY2G1A>7ORhVdBX<7yBh)i8{m;7ET1_YpwYL3B(|wU@zu}L>R+lYs+{DGN z$
!fcXXadv%qWcPTbDcHR*AEcnb~z eL}2Tv)+NJnL-&TdATBl}15s$BEUYx?D-^CyP+H%~ap2&Tlx~f-q`@^1 z24&S?;R`rKLAz-^NEZ;7=$C~+^rV4G^qTH1FiJ5lx$*T(tx5caLD)8b9Fe|a+-1AZ zAf|t2fc34F6K>nT|1K$$erI@q6{n_7^>%k3ho0=&)daBCXwX*RBkvzai
0dfb#7o5>5Zv!SlFuTMW3wf~N^!k^ z6~Ad%Fd!03t%qAd%^#Ru4v;D@C;-4G8m3AG&ou%`Q>g!`ZfF*k_%z`C&sjbNz8>LS z0tG)8q+~$;fuW%xH%WU-%XVgHC_`8qL<*Q6#gYertM>$q(P*}pk3y>eqT3qW4l^d0 zK!NO6KlU;q*;JM>^=^l- JiyCigU@Eq?D5kh00EienM3(a zO?3w3!0B|j7gZpp8jxB*1`-MA8WVFP%?t*EBB6yGIpX@}tiyQdR!J9}DzxY^k1uh0 zDfjQ+H^0`Xm*PFsUmYO+Kt@+lQ!{vdW#0U!>^pbvfKkZSuu%vu`~V7dG&su5Ia^XQ zfN nMKbV` zqxQ#uM8ibS)6=utIbTdi3fx363B#Qg)sS5hcENnkkS)gHa_zIlX;6U*u-o`T tMnEZ%XDLE*ckFwhRfnxZZq-XkU# zPti+(?EwYsRKG81bee7>#{!AeikI{408b$-GO!*IP+*XK0S^Xh8ReH6n9#t%+}R>D zI5f2WmEQ#kk7TyHM|+n9L8J!VhV#I n{x4Ov}M%cN2Gvk> N(Q$wSO6jsmWC4$~c++exmMFVgdvE9`7n$!v?(>){adj}ZeH zx3Z?0;b9lX*xcM47@$6JO?Y!T(eV5C7bd!4M)Ehmz77i*>=`bAqXRMl
!adJ{gJbT+(>ietjmY~mm&eQFzaW4S&wq}eys0Ez*FS@3&` zv2IM}`bYbe 3?tT_2}K=g9i^rN YP6hW4tUp9a>J(#n)B|dqqVtwr?)ZZbuYLk)nWgmT?+(b8S|*C@~mBG1)3WZJwz= z0%Tami(z{{Zm%H!t#WHak*(@4!3nXPBBlVw0Q;k#iy?8Ky-c4E2Bi(iQc@vUfrAxQ z2+pxb^ShEAJ9f-FH3RaA?8kyu$|ODTU|{MTc;!kjXfN8nD{Ze$Wq~e6+B?9L0w<&4 zO_xCly?_56=7Z3u((9xcL>>n!?(*!A_>Y4o)D_bmRc}Q>7k(R%v<9BiqH-G+{Xp@x zx3|Ojju{Z`-L79Bfl+GsP6@@!{5dG+avK;L1>IK#dSO)#ZoL^tvpEaq6O@bSeJAr4 zmLNmHjBRkRVtECR*(j7RU7;-Ora51}{B uEG{mOe9`crO-+aj6v*G)#|QoO!FlFAv?Q~Y6tpM%@ SsCS3v=xH6il(~ktB$v@LiX0Bh(!cUbC#^R%LZ{ zPWt1Vb8tedi<4gaw4I%tRD;(+KEQz3o$$^jG&B^<);R-2wcRePfx`!0OryI_fLQ-5 ztf&^8a7{M`J6ofKxM4t-!P`jzG}v_gp7#nKin_T>WlffYH^^2)JSJgrHP0?fYimwJ zeJAjHFa-$6@EgJD1fkuh?R)%DN^MA=ICp6-71#Z>q{ybRW~~o!wlX*3<9oNO0o!OQ zYlevfO9^VSn(~))C%e%CWc&y!sm~eaiqMNxN+O3_y^2R$YlBkxCZGY(*PYj&DN*d- z6q+IoM3`M30Mn$we_e-%`yfEx^ap<(dV$Go3qXfrZ#oNtL)^OHmeu^x*{)mlps1>( zLf3MuB!Q+wNv0fDhHu$oEVx;%y=vSbC6XSH>Z?b0{DHw>Byk~S)A@fHre@ogH1*4? za kkvocUU&diCAR4r!RUzx~*s=Br`UAXR@BCRWP=#W~0<-{P_g$>v )C@w_%)>{mTRl%zZ5HE$;>de(o z(z;O~% Z3QC}6E`+FX|MJG2G%eRD7=pG0<90c8U_J_6+psyKl2X;`v-WFFIt@% z!B}$7(gfpoa($6YrBKFZIB|xl_0X3$H`aZmIvhkA;HJGF9@Yv!Pfa}($3kvPt@oPP z-sxF#U)3%}l~UUS3 |i4+Ce_R!^7bmIG^PL0FVZghpkjjoLKrAE(PS;=j*dZ*a7TjksG=R z&2-GumUH5Pr;Eo|WEKr$F~k@B?bdm)Wt1o-00UL4vryxp{iqh7c9#XWT92~&_8M3% zUW|EjMm~Sq@oF}A;WAhe&^9( h13L2GTP!R zkn=m`2j^F$<72{zkB=8Mq}bTnt~Ex75Wtz1@g=%bFUaI4X<1<6s4z4npPqwh2k;80 zgvKC)f$4(8@s6d46 AJ&wHX4H5BNts^)P5iEID_9kFB1w!!F~9R))`eFX*( z$MA(_c{nn}2nt=ur{YTqX$JZ3FaiW#B#v`Bd06!?>FWOeex%s9){SO# z0GVq!ze##VrEX@!y%8f!B5*>|8^G>WzB~xCR@IhyNO>rTn U^I(okWk%z zg4kg!$QxNwz)*s(aas!?KV-F&3)HQ3uxT)r2zEQX+fi7R%5OLsAM-Ckc#zP5Nmolz z0|nb1bL6D~=DPrRBTUdp+ov0XHab|4{;=uzA)~}Dmv_j7gE(%fq_5`N16>pdfw`nE ze{8)$jO6$ByCbFCZQmD|`S4ml9(@BR u*B;u-h^UI3yesmh6LQYs_zpN;9>wZ z9@Gt7EPRnI2ADCN)Gp@c`Xq#b;#F>?Sw8Ws?wWz&v-MTx=4zoqLFwD;tV8$nn!#eE z$L}W_rbbKQHs+d*eCsnC$cE2OJl0DwcWOkO=hgfC+R*s)(Ds~!of7J%2@m28Q|*K2 z*{TM2-HS;-0jb)Uh3Ed9j~H&T)V9wL^VxsT!%3AW-Fwr6ZA4BDe ~YWlL8Jwvbx_DvQ4-BPfRFMS zQZ_;Ho;kea2Nfq<9fWx~ASdMO4*RJxLMs0~2Yj%`H`^7AHSwQ+UZOKs=?NQu!(T}t zc_U@z`6~QNJM8$km(4P~EKG*strU4ZpAv{LSo}a@je>eb66FwpK0j`-=XN;Wr^5IM zpRw$hHQ@g$An;%udAsG?bz8Mb8(A5k^XZ#=08Bygzdm_Egg=uI5cstj{TKx40U8hl zD=0#cD4;2W76&vJ(7phb0PPF>f{6A7ei%?H#Sa5Y8oz}BEe>dLKyv}jh5vcIaC PK*-8F*NI>9A&A)$akF()FhQNti{OL59TJitZ`*qLw zFTV*0+!*{f!9$lqAdJQeiNb9Z3@8}T%79=1t)fU2&^CcY0R;m;3Md#*FrWky!2n9O z`I&%%0R;mpEfEZ$G8~Bl>N6lwK*7L|0tyBc45+JyU;uU1_?du$0R;o ?)JWlH0tyBc4Cw1g2nJ9i1&PA{ zsH^ti|9s!_dz6hJAxEhxKME)qP%xlu1i=7GP5GICf&m2sN=*?ApwtwJ!v82WMQu_f z#3&d276p`xqF_Mj2Z8~Vi}Eu81p^8Ol#3!5K)EOq1(b^-Q9!}Kj{*t?6b$IghkOj6 zFCQXdK*4~50e$%p!2oKc@G}7g0}2N8pY$RaK#de63aG1wL;(c@KME)qP%xmb8iE1T zNa1I~e;XKH|6lK0qJAAez9`K8dtrw9!2kTGFzAE`0oH$8`9haMafSYrNPewGE#+@v pK<5ic9MJg!9}OrN{@(+`_kUpZyT#*wo<_E&d(Kch>x{$Q{{_MB`%(Y^ literal 0 HcmV?d00001 diff --git a/output_images/page_3.png b/output_images/page_3.png new file mode 100644 index 0000000000000000000000000000000000000000..292fbca539a57203b3d83cf956e16eefa9447a29 GIT binary patch literal 40159 zcmeHOX;@R|x<#$El?v@qYn90!BUBNnA|kW4IHU+vK@l0^gop}Z3^O>?QtLpCA~IV< z5E&wZ3^If|F@wxt2th$+f{cL#!d*M`+~+>$*ZpzsbN}r8F@~L;?|Z-Xu6M0Pxbm~v zo@GndER~XyT1MS#d_YR-^9(%A`fMRyF_T|>Qc5a1k!rlt(kFV5>tArgp=fHvU(J25 zN_p~^b=0p~Pg?jl81Fh4mT>I{&6tE0iHnwA*~Z+xnX*y0D&f+;+llvIlqbX|cpkM< z{)e=VMw4)MWF|X2{Kc8H4>Lov;sI-chh1}^f#%p~Nq~KGVA6-KE($)Fc h!=BnOflq{v<%d*T02MGrcv9!kBdb@otEVt{BU$KOeF^SQTKPGj9wBL7vAgOUGk z>;9v0e%%p{>4lSTADD!92bTB51qZeJ_Eg>7d}4U$kz-BlblNq!ZRbwcC6p~U*Uu1n z2lMlK)@(if=IPmHuYsly4l~zQYd*4KwX $EgC8MC*<#tHG=Pr>|40yHD>I((kEZaPH{{Sn; zSl{jf-!WaUeoK~pp}v{#WUHf!S@c~BwWm5J pIK|CmK_%Xj!LgHC zg`)n{3t6K!Io05qkrL^zH?;_pHc33%j`%AJMZ2zkt!5uM(MX}b&34ucnwcutH_hRR z87L=(dY~v^8W*hGaNwjYzo*TkCa@>QJ5uZHHmAA-eX~ApzIU8q;0;4zFD_DGv>aQU zPiHVDBOGIO9IK PptYgMDa-GsjB;- zhQiWyp_LChs^g4|CT`uL D^^j*Md>YDwscp==%JRjPkQ(7QP6TI zzpbyX#~5sB2>E@b>J0_GNo=rfk-uag9XZC!7f)W=eSOWrhd+NCHr|wG6CS>yudmPf zZC2i#SY&Q6(O`S=w3(UN0+~HuZ?yc5ZNcCPc)@c$Msqq;=0Dc|q(3`ee}7MCb#=A+ z{`i;KCzh^K4;ZiALvPE?Fpb(~k+^R)8nZl1_3BF1ZMf-?r)Sh?MFp102lT}4sJ1SZ z>DKxBV7jfZl_NFDH0qAuOTMC~fa~pe@+5^iic_=;7 Av zg>Q^6%yvGP){r;w8_y_F%%4bp%tq-B;S77h6%4JTWz6+zHrWBfz9jSQ?|unzKE>0n z1tX}k3fw398@>7)B6PjZ;3BrLKSek(;62zf66?=z?Q5-{9_x`s J)+d=8O*B{l z3Am`ICeA2e>f A^u+HyxO zEK%&OPpaW-M4gFO(Dgixm-wtti7gb<{}7;CN-85XIXQHrQ >1j(p zoDskO{%(NF32Q}1kFK0Pl6`KvT$Ke1$pmhEqqhM1R UN4j zQ}3`F^N1}D1Fa?B{`jls(A%eH8Xw^>bVgn-&rygA3v0Z$^OEmaw`q*7*Ff;`if|3q zk*ED{pPmhoQSck9((dt=1uIy;`hBJB%&l;TiaS+hWz(Y-8YXu(<*@}41})x6UA|am zh4d=*Xv09i3rVt| p;^*AQ$9_bo-PvSa_xRWgr}{)^y$9Isx;;0d zzd!Z^W<^e6d!fJJuS-jkl9GbaIiUUOVKW)|tE)5&`MI5p0>fbO4Ej8DwPxavAu@UU zYO1Rhx18LYWEL}7TJN`jDE()zGd(UW+Jz0$f~G&L!Z~)`GB*@sNxJ V@CTMd9!B`s);&cx<4CH`4?AsSP_E$xsrfZCX0u+ 4T-yPNest))=Yi-i5ykfWoc z#^J{u_gvz&+kH+XA9(PojQrumeG$$qwxHb~pLd2=6v(d^35I!S_mR#L_Q&VajgJm; zuFB1~^V) pv~iKQ|ff%n#j6jizLhCff%U_zn9++qYEt`U$MzPSJpg5 zbn@@2>Am3k92YJ__a3T^WuC!gZCWct^G#r9G2ZR1eI`GiZFsmJ3<>7dqPGXsCz^70 zHC@{K?)l}ofYCA(Fyp|3pE&lkXP!;~|MfLm?s4J|;WTCH7O*yNmhT-GES|nFx8o>L zeW}UyrYp9eU!iWhJ#^<*DpNB34&d(GFF=kb9UNAkdyio>rWJ&dMQ6`4(vCc3XaTaH z;yh>T Y8T+veGsuGTtZ3ABUzbQy!&!F@Ol1DcKQj)XHVczra;(%S|k z;WPBKxjbCM2m}0Y4jICL4bnsxQK(0 N}13jnRZy>AQtfDzx=93V4_q|LC&{eVi zo1S>E2$dP_Sx3dd=4Hw)A}X*}%5+7G5oU(hi)GrIte+(K3;44lfrjP7H%+V}5kDV? zsN_GGk+&~yyW8>pyr)*SZm;-s 3F#L9@cvOh=__rqB-Yc>#Lf{I=_I z+WhgpzleoNeN2G_V^vgF7m0-fG{3$F&KfRnv-&WGa5Npo7oZLDhq5`@3Pjs}t#+i% zZy+tX^O9a9x|2!47ByNjo)0BN_Fh~p?I+;Jlx*My3hd4thj;)o7PuUF`17CO{Pon) zlzP#`fHvl!g_({+@0&mK*Nl~^#BH)K$hBhGgV($kY|G?1%f0g6iX}3J-U3DJ0rWn= zhoL^%`dYHy&vsyhJsTe%fA=E9D)n$i!1QQRT#z3&8>&BA3c;{+ IjG@U=8H*AFxvi(a|DUo1EO0w4 zEKIbz#CFA|#P0VU*DvP{>w76ralMImd+!NV3 _peGYh|e@UR5p#wa^^7J+}oMFYIh=`3R+uR0UJ@L(p>JI?C`L#gY2N$ zf%JU!VT+%_)eTOT{()sXan?RVr(#EkQV+X@4nC54l9?%J4)ji1roz4xl2ep3f! 8XCmVCubdXY4=}jur)~oSgiM&UpVqUG0cqA0v zn0>nTpTibVx}F^89A}#anNOamvu8#>UA86w)4`Y4^B~;5zbTCaT{@b g Sq~MeT-(6nCcv}6$p@KQ*|Jlc)+c7c3p%_Z!H!y!3a|Sh5E!Oot z7r#f|&3M7rONa$_Xq#buo=^~2-)^wcYxoF=Z}2yT>i!|jDi(E{KGK6;TeIb4X?yF5 zCw>$Cm!(%F8qR%uA?sTck5y5bGc#i~%a!-FG~Qh-{WUZUxWRvBY9xP6re|Lrh1!&E z7sYZ8h9+6GM5eN=tgJcJc@}RUE)u!)k2NG)NJsDTpvOl 2Ov00I<<4$2WeZMHXIQVa|Vy@%VU?YiIq#88ak8Z`TqLup$a%H_Qp_FtBs6S6Nr zcTGc&ia&-J5zRXN% z%R+sY4VM!ekh+J_6avKvJ-D{fI5RWTf1+Otr-zri&fZis@Ei1T!+V0oV{uECt??Yp zDB({z_m`e%ec~|JX(YbCL$0Q3iBiBHeoGty6>pDZ;5RmKvK11$a`>eS7lXCQSsP^> ztuqEaY_xp%n8o;n_~ae(c?Kz8b`)=h;zI{$Q<< ;U01 z0287Zp}Z0uTu-6?1Tlgp jp(DdeiLB**v zzHq4+8V9Cp6w=eyqe@E&7HL+%i=&hQ?vN#d*K+j1?)RCFHD=6{Rgqd?4sUghiApXO zwe wC0{Xmt@Hr&3uf%sxF-FiDTvSpMAA%_c;S|%$}Oc%1Y=` z!g-?@GXnM;H;2w!m>L%mG5yyPC3wX9yRS#li+rtKxVyU_IOe_w0?--48C^@DxC@Vr zM`p45dDfYyl50TgeRU5i%;?XCmOJpkP%mWk2Cb~%Nvg}rtf5FSFpTDA#(tDF*s39F z9e(oU31gxW*4%
x%+Le0s^DSyp2@biz1Kh0uvA^G+)PXecCC4We-QFq=| z^=GFCTQcBkouQKt9ct=UNTsohAZn;gOo(qyBcX&qXv%sroc(7GLG3~Lxj+7-meQ;& zMEk<6V{*Q}F4t4E*FJKy 2pSynF zclY~0;aQT62oV&(?G+8P&0}_+gEGbF5uzi8tFxu=q0(sowh>{+Uzb8;l`y)&jOlE# zut4K(L_{6{Mxi1JDoWaxN58FV#ecPm))x6N2kzST)TvWUigugpk4y@h(0_KK8K=bo zC0g10I$+<)$A|%=meWRLB!LBgciYm)?;b17fUXf!m>Xm szO!q3M_*Q$oz(gr9I &d6;S?ud+>rF-b{~jcLoLX0NU4Kh3JCg~HunlNCl4ox z@d`;+p}}r*eX-1&>(%_`&mW1z%JxQxOA_9Jm#mnSiGk)Ckr@Jyq=rDz N|mg!GmJeO=rfp~IQQ}m5RbmV zJglAW@t41WGNvQXrbl3WV+I=HoDgWx<%&n&SL+R*Yfk5CHQU}2Y$)`bIFjRHhksxf z5Z@g+@)m}Hi{3+bAp~&45lxGH^PSPWL}S2o!CQ*aGLr+%8iEl5C_pV^6)#9M1b`h( zVPFlzY1g}}6ujFuW9D(Kk3lIXYhTHx^TY@)+W8y^R5_R2W8#_Va65)IlLCL;YO2iz zMjqG~`lTUa^yW(lXoo&9*6iTuXe8{tuM*=~hb#juNK6hQ5lXk!nHY)_k0-&76d>M1 zq<{}s0;er?y$az^%m*mL>dq C}y)?_+j>cod+q(|-*^172Qb?*sp061EYt z11*Tbit iIY9qIzEt$IOB(ez1S^v_f#~Z>M&iy;qjW?wW=m4-3xyav#1eo~ z3o9a!c<@tL9nKn0u?#}e!o=3b@4C8T12ZP3kce%fwCT`K_>{Ba8fX$GND<6{t=poX z1BK(QBfH_PVcnjeU$E$a%2(d~NQeg;Q<{ln9XFs*5$M@M3v1TsXCl1A8Nx*&;8O~0 zITo@~!=6Z^lQ$qvXhm29^@xG_6exUkb(Ph_pWj`SR&Qxk1A1ezanKvC&voWxBX *2GXmIb(&IYHCAx zV%T|2b7?MJ!Y>PJjV}aJR8)Ep;1Obg{{s2b7ElT>q-LA@_^38O@{x!_V4&B9>bsZF z^F8}U!`U+q#pf4zx4D(D)StS(dw%T2uS5e*2Ns@&*#)_~6izfjI1hOi%h3zmn(e%+ zA~ciGUWDoczj;`v!85}6(_0?D%kEj5Gx2h{xhK3Z?nOukw6=#1Egx}No<|RU{}4eS zIVk9jefZ6rZgaB&^T@3ms7&6RSb!vAs&OuP(6WD@bN?6wXE6NeaG9MXtaEjRFkRGu zvz RG6L7NjDS zvjB;XxZfy>FpIZ0Sl|blomMz|UjSawr{e;vNcae*5_&B8P}*CT%RNF?8BQI=P6#rK zktwaL3_#Zs%>jGX{b7~Dc4(n7I41O;?z(mN5tX38MDl=N*%a!Xm66~6{mKF*B$_rZ zc@DBe^U?36yMz~l=_PCw_T&caBM>73C;S!!oFYWeB1XdFfnt2rE#gs+%n*Y8T+VZ# zl$F;V2`JxyqD5&Jx0j)zyKCa+CYos)=pi%{{AVYY2!T?BE8vM(cKHMqLctAja(FJs zk%?n25aJ#N!3!sbZU)tscA6qknL)-*3`OLMyDoSK?XX6Ih-ks^*z;c?8Hu16xFS+V zU#RKQZ$k!eP7LRE-oQ!JL}?G-wlHg5Cp~{~Ki3;y;Qd073h mt+nsK58*$3f-;08F${o87kA*9^9O3}K6)j?S{S*5qN=T?B|piiD? zACe@|9rx~ESt#FoswOt@`R6Kxa}@cnlQf3w&vo-Tg4Fp^#;E5W$%|6wzu&rl{@L0s zrjj#}lKO4matVP;N&U0_zu!V$MwE#xhy*MoLL_A%TSiib^Q9y?5QQMgK>`Po93*8R z$w5*Ek{l#uAjx6A3?w;_ +6 WjhkYFIy2!R1ono2r>1Oo{MQkoJN_`j5< zWHKfp8&ZDEmx0uxL>)*iDnSDY1`-V9H&F=;kXn?e0%=T$Dv)51RDlEo2?o-bNH9RU zRH6(d7)UUXUp^!-Kz vMOx literal 0 HcmV?d00001 diff --git a/output_images/page_5.png b/output_images/page_5.png new file mode 100644 index 0000000000000000000000000000000000000000..2f94ad2a0ccb63887cdd64942b5f82558d0b3bf0 GIT binary patch literal 40575 zcmeHvXH-<#x-A{lt2SacDk=)6kF8KDqM#sx&?;zK0tyI-2$%qoC`mGgR#Y0W1wn$) zq9uX^1th0dkswf#LlH!v2t_V(sykPC?zlhRyZ`PPZ;Ur~4IO|~)n5Bs^P6*ibMNx* z3C$yd%hoRw5D*YN`kSh@fWXq%_%`)FzQw<2Zdi0tKp^t)QPl${T_XBhEHXkmTBmpp zQWp20L>F&4dhh *Mas(#pVeZdUTLWy^lTQStcoL?g@X zyRY9182-71EDsOW=Xc4n@c7dr`s+8pUJR4``rXP<>S?G1RgkZ6pb)~Z1JyG8GEn5e zF9Ssm6gdb`y+HK>Wu?9n0o4otPkMpX@TJhV&3!2Me9LH8h=~oO{QaxTwQ;pC^=&yu z{1puwKDqmCe%ujp`FV9j9NNJy2;Is_f}j{aiyrGa_T$+3BNH`l@u9#50-6u3WZ| z^3>U0eeb!Eq5uW YDs@ zZdhlqXwf2;n^1vxao8S9f2Gl4>HN9T#O%SoPfrg0IMi2{V8~mTXDW0@T>oy#;OinW zLl1qQjm{0J7S;Ql`f4(+bo{e*wBbU4-$q3_hGVU+zTn!Of2oJcY&M?%bV%s&KBvoc z3*P)>)XsAUYvXj6i+i`<5>X!ebcn{78Rw{s*XZC)Xd_jI&G7~)w*^J((rw%N`>naW z=IsW_&rClC2X4`z(;j OVsZJb>en!>Wl&K-Wc{K!V9n&6hI$|K^B0|QfL2eU;y*`c!LUK5SxG{$#A zN_Nc|S7!TDj+X?B$=jUqT_dGU$8kOTUl&y 5R`ee%y3;Rr2+P`C0Gbzn2(Z5E94U z;0)^)Bz^fK-2L5JXTvYGWQ{ME&bhCBxjwO_r}C+<{l~!L%B~d(-OqyJ^plj$D ?U%nQ9_`x1-4+v6vA5$7!IUfQVY@Aohw^6EaMtiQ>&6ww#SM!Sb0?bAg*`j} zJYthSKXLlaW$TIHl!|?p_+b{u&zqlM;Wdee{ni`Wsi-Nu%+l)m7$SXTr3S6Vn>VlX zT>U7`$f;JhXoEwUe49tgV0wyK`95x$toKZBj9GbDE?)oUa_#9ftH%33AJV4t#!YzR zA^CHrxg+b+o9&OWOR^M)a=0y5+j1+NIQ2 EFpVdR?g~qYx%a;o-DnW2%^2w@5>aNI-gLyj%%cGve8hi4=Eoh` zt40p UHbSzYA+NSSIDl9JMXHw^}W8v!Y_QH7gBG*L{77*s0%EN=ZsK)U+2L zv`TMrF3e?&u`3?C&yUx~1Z~xepDNxI@PoLrl8Q?H`NDe~e{5$N+HvNibbhKe%Xw~U zWPWCRcBDug<>6H*4(-15>1<`Rnr__5#^K2pr+OnD`qRUHaRw>u!^{W4G#z${MAY`u zcTQ0rqb2IXx#M+)LMn5^KkzRK%T(t-AB$Cb>PI0Vc(no~QX!UwpsVu jU?n}eiQ|mrjlCOxgO>54yM3hHWmJ=r;BI2=gQ*2LoN&mUQ=FE3KLegKPK&D#s z*!M{n2kR18zb_T`-`Dp7`)OXGJebd0XaOXe-f$l6y6_=D96!${DJn}#56y9z%+gXf z(AEm2;exV4R3IDhAk18F{kx=`(b5M4&+O2TnzVt;?#RL!ZgaA|y?vZsf*ZQi`lTR$ z?ZfUdcfVzQ013@EnnxwLcfCx?3j-(KmDr% ~OUl(~1ZM8e?v5?kB79yAqLWvE}%(*SWvJ$>fMz;cERcPW=$@(f{emJD@yePzul< z2%_nH_+wr5v!j7;M9{1C$97~s^X4r)R=jEh)_iwc@Yt)+x29nrA*b}IGES(xZEMuR zSd3s2^UDnJf?=he~GiY)1zI0OIwmj{!-yB@uyy& zhXNI!A=G;0kF~qZ${t}u669Ia-BE4%-aHfvsIm6j66WeWnDj}N2-;TNxUm6NI(Ua; z><#n)ICj|5HD2yRt-0=FJ-e`sm?*C-=Yb}}D^I_|ZG}a2fvsAojHwvN8*F5ocH7Jm zYE`X@y|45W+qFGQ_od#${ttUB>sDFLv261_LEU40wVW(YBCF@x8mZIRm?X%v<;@;W zQhqByLbyxo>0wcSmCpNz`s$NNkCVk?VY$Vp>6w|C+-~Oae7dj{+WwHx{;@JyX3Yz& z3oV@GYql3xR4C(R%kuX-uw6=nXdvXdvEFLgfK7|Zim&~kv1&>Xe4+m1%}aC(Y%*VD zLuBqe4;mdEr8{@@)xPxI;|0C5%^5j-bFm;A`q2gdb$jhTw=GPhztMMYIOl`T*+0>6 zK_~qOQMq_5OF=<_blgax2u#N3^VYE|Awg>FTe0~Eh0AN2VOv(uzZlHQx;nH_bxaz2 zJzuMDvRd^UvZ7M~Tb5bLUMTX{puMqa$@+eB$C(VfzM5DX1GNeAlE^ 5$)NReb+v&O%0OwwipZeOIZn=M1*{%d aWsoGbjS7udC7)unRzFqk~7g{sg~1)wo+%f^w`jQ3%(QTua03ts~TQt zJ f 2fVtwu5 L+=j zH}w &(Ap#|oir@#e@oIpUFv p!GXksHh8uAy$ zlMHP#yJBM^$ua3UdhLqLh@}gY`MmidZ=U wb%kP!lJwBDVJaH&LDw2J~3q zMBHQe@8=)p#;T7KvzFsB^5c;WBlt-ihC{8bAZr=(on;%VDbvCHz$!kdzf`GSZ%ZUx zj^%+i+<+JOX6Gi07)B7W_b|B93`bavfi#wl;l(H33*4wePg66 A!c4gu4c>g1BCKOpg{e6&yAd`}U0LHvL4a#^kQaHg9+|mVT_ZDK^t!@@OHp zw?avLDj~gfW~w7#d8mZ2p2&_fd#`+XpHQPJ+pVfY-yA87paHKNikB-{(S?4?WV)sekNn*eA}UGzCC~4Tv1w5Vvyx%feAp)! -=pEWp zZjTutPh-GS28iu<)48x_`>FfdGiWj2Hv>csbxcgfBEq%fz)C;McCy)PR;_v#MCZy> zreJoU0nGd427`@nx5Mw&c)ZBcszcD2vFv5Fb8dlyY z^^z7?Jr1e_rz&GA$Fn`lO0y N-Yq>Th^$+m;u;9>YNr z*16lNVHh@sRr5$#b8kC_9_blbclmAAs`$0>RAt%fZF(1#`(M3V!7$h%tS4{Un&TQO zgpzG5-%7SzU~U(PZ0HbtFPTKuh0B@DAu!8u`@3y=@u%XCLMQUt3!#Zd-t*(=E0zOu zzx u3W51BQ|x{|Z@wxXwA|*6*hVT*hnlZDDnTv~dI-dH^`<&m&?A?i2l0%sDi%3M?!r z3~Xlmy0yr_Eh%s2GCdZ?1+(HwS_~P**ZdIO%d5C6W>@gdEg_b+#%}oW`?j(gsgOjt zqHPx&n(F=eEK-oQTkG@HvtUPav^9q49hm>fAz{wdX&T{j#N)yz(rFSrKu3oT!ODlP zTkaZb-X1J%VtgZeVVddvJV;Y{y7O(@bAvOG{ZG*KV+u#vo1d$xNStn#&F0XQ%+11j z$ow$%OTK*-U-3Ur9t18pFhG?cej=i9tHifCJ5Q9uYJgOq1qE+6r~+Aoh|+g+^C1hN zLg3p;Y_j2vbz6={=Cpaul4-Fpivv`lG6C9j!p5Zs6O42BF@mC^Or~D_0k(019k-}{ z&M1k7To|TV8O*GXdTjWcuu<~G61-!G_CDZZSyX3;i5IP0jE{yprL&-`RN@?JbdJxr z`-tzz?0oR#kWb?N b~B^AX9v c)*5>W`W~)x_$A@3BmC8TmpWjqE}#KCa_~pJijRDcgali(_wcrCPmbbU*k% zt;1i@#+eO6h*vLKz9#ij<@uSh-p$7zhA!!TZZguCiSZ?T=JMO$mxiYM$=Nh#+zID5 z+%+eR8gtGFH74E*AD@GVxc$RAdsHo9@>(ON`gF_s9o%V*-Ng|bq!O{erkaw*p5wIu zWB7Wxvjx`% RCR*f>!(zfG^?HwFQuLM<1 zux#6MT)9EosIUBnv?paoZ!GJ@RJ=UyDw;mO8@x^51^}aZbi&h`xDUJus&ZyoBa=vZ zD?y{negy gBbT&*3zrD44+;#_3ER&H&B}+MVfOaZsV_ieWOy&~-x#A2UI(A0;kVr| ztsm@)7JWE9f>xHUI|$}0k2qk3;V;xYavIhx$c(kwZmQjf7?5|I`PoTvnTx;Cd*RBn z$EuF`Dz`t_d~D5*Gmo?pvKU*)1uICL4vGsa3B>NL-g;89{2sWbNS3LTBBzzK=W@*p zpz&D{F_A&qB!Tgo?jkt?j2KgeHwU(rc{hmnh7e>yFd2 Z2OiJl!SD|t_bWBHzXGGLsV)Py2(+aZ5j%f)0gQem~jH-=h7Gk%DsF-W}e zhit{Ep)bfBZ8N)qgR}uin9=^AD$wi#Z0#J!gf}z#QTn*bJTU<#R|;3d*BaCGmyrGV zha5y)S0hx00Z#@`x?awz0T$nLv_#@+UyVh>t8+940y87$MpO9~$7*;=iQ|!Hibp<; z6D@fjZbPRbfzwiJD}j}WGMEI);h;RClsyqHvS6jlN-C|pFc#+a#l6&~L*~VIp8fTT z?N_oS^llN2xyZzO-f63*uvFJaRr#(k%fylm?i(>WqXp6@+`s_P-rFlShDAlGIQD$n z6rePE|Imtc`y6{lyFR9WkmCbuDz{qox=9Iahjdm?G+dLv*#4Po->rBgV_N#xft#d( zK}{t35; `U@n^S^O$GW8{M|bv9a;eU`g0qG!q#^{^=jJ+oB3)z~uG$LLA1_oX6w+6f9-vJl0bQd)89?=O%0} zk3^CqUkW!js4vYyFd!%@=YdYbtbIQ)usY3}<&;m7uO6u-u)V~hqYe-YSJaC{2o0|< z=+M BSXQw(GVS&7{5 zKA6H(Hk=iFN>m*$4Bu@bb9Jy;aWJC;^+IB?;C4Z-NfmOb;5ypb0bc+pD0Kzt0Q~NV z%S{hQI@K948nxM`(O7$%YxiS$MVF_{ig`#mQtg8FcRnF!$8&OWL~SzKaV=o0q~u<_ zoWw+BAI~qZ1T)0y#1MNFDh|li;AaR_$XO>o01j?VNst$q`x)ik53ziDBtT5j*$M x4`XO(2&=A{>(B$Nc6HhP{5XS>Hg~%dgCX(Ye z-iOqK =OJpDprK;d3iianX|Fz%uBEbaxQzAVKEFn zc=fZO#e(a{U}!fWcL4kok=npXlB^2$ SVa U5ZSh4F^GPliKr=F9R!e>kbEqe`9q8s|4r|phcI7Pe48d zH|}#puw&vmu3NHZE5aTu&;@6naCQBjrx=rYToqn*%<(Af`nePxFq1xpCV E z1c2)@fY~%jntQJ4gR?-iSYoMx`C}(;xxB55oTCv*H1QXgP%z{?_FLhCp +=aLj`dCGF~}Yu+A-9s;rk)7!j6j9t#LOEE7fVjeE* zhK+z7T)o+s-PzfUcb3kZI#2IKNYjUW#EhrY_=1eoVDxg2JTM=bG=Ea(du7s$!=mFz zuZaW3!e+3gD7(?v 5z$aUE%s9$B|AFit+W}m%deYJ3-T=sLA@NAq6>`1F zy6FriaJ=*O@_RUD`S(M(qF{vWVubQXl51 ?vLd16k5{q`(KB9?fLHWXmKM*M~aRm#b7a?)T8Tx(< z)B^WA)*a=&LsD|Bf_-Pxp+L*kt5!ARDFmH<>-RtnKY@kst=_igO6AMMtUi!PtYP|K zS*Yx>9In&V2S|EmT d ztZz0?Wcc~5lVyW?EI rJ^9PW-8(uKulbYAn-CEb$vPi&&XyPR< zPNcQ|2md#7JO2B|NKx0UP5gfp_;oFHlO(AGbx$B457a$@{4!AYe(=jc-4nMGjOiP`yBXkc2<5QKpeU#!;WWqCRB?PNW7XzA#W8iSkHPFHjzd@<^0N5}-a$ z_mv3##~f*x_u71k40+PcxrCvShlk0xcI>Zr$O>GOmH3y#j8M=bzY!4lT=rid^EcPz z-}EOSu-75_>+cFeh57ef3J6q0{L7M2Z^bVSRVz{k3Jeq&C}toSpjedO2^1J8Fi@U> zV1V*hqzaUQBvqimz^?)Y1_}(+Xh|?Yjp6)Gpuj+ZfeKOx2B;u~PY4tkC@@fQG{FEB zq>w65sT!#Q1qOZ MN a6vm8y|4P+<7q1H+sD^Z&OL5TIa2!Hf!T2?nU}mQ;bt>qr$SFz~BDfq?=8mDdpr iP~k1V6aN1P!=iP List[Image.Image]: - """Function wrapping pdftoppm and pdftocairo + """Function wrapping pdftoppm and pdftocairo, allowing page selection by indexes.""" - :param pdf_path: Path to the PDF that you want to convert - :type pdf_path: Union[str, PurePath] - :param dpi: Image quality in DPI (default 200), defaults to 200 - :type dpi: int, optional - :param output_folder: Write the resulting images to a folder (instead of directly in memory), defaults to None - :type output_folder: Union[str, PurePath], optional - :param first_page: First page to process, defaults to None - :type first_page: int, optional - :param last_page: Last page to process before stopping, defaults to None - :type last_page: int, optional - :param fmt: Output image format, defaults to "ppm" - :type fmt: str, optional - :param jpegopt: jpeg options `quality`, `progressive`, and `optimize` (only for jpeg format), defaults to None - :type jpegopt: Dict, optional - :param thread_count: How many threads we are allowed to spawn for processing, defaults to 1 - :type thread_count: int, optional - :param userpw: PDF's password, defaults to None - :type userpw: str, optional - :param ownerpw: PDF's owner password, defaults to None - :type ownerpw: str, optional - :param use_cropbox: Use cropbox instead of mediabox, defaults to False - :type use_cropbox: bool, optional - :param strict: When a Syntax Error is thrown, it will be raised as an Exception, defaults to False - :type strict: bool, optional - :param transparent: Output with a transparent background instead of a white one, defaults to False - :type transparent: bool, optional - :param single_file: Uses the -singlefile option from pdftoppm/pdftocairo, defaults to False - :type single_file: bool, optional - :param output_file: What is the output filename or generator, defaults to uuid_generator() - :type output_file: Any, optional - :param poppler_path: Path to look for poppler binaries, defaults to None - :type poppler_path: Union[str, PurePath], optional - :param grayscale: Output grayscale image(s), defaults to False - :type grayscale: bool, optional - :param size: Size of the resulting image(s), uses the Pillow (width, height) standard, defaults to None - :type size: Union[Tuple, int], optional - :param paths_only: Don't load image(s), return paths instead (requires output_folder), defaults to False - :type paths_only: bool, optional - :param use_pdftocairo: Use pdftocairo instead of pdftoppm, may help performance, defaults to False - :type use_pdftocairo: bool, optional - :param timeout: Raise PDFPopplerTimeoutError after the given time, defaults to None - :type timeout: int, optional - :param hide_annotations: Hide PDF annotations in the output, defaults to False - :type hide_annotations: bool, optional - :raises NotImplementedError: Raised when conflicting parameters are given (hide_annotations for pdftocairo) - :raises PDFPopplerTimeoutError: Raised after the timeout for the image processing is exceeded - :raises PDFSyntaxError: Raised if there is a syntax error in the PDF and strict=True - :return: A list of Pillow images, one for each page between first_page and last_page - :rtype: List[Image.Image] - """ + # 如果指定了 page_indexes 参数,我们需要重新调整 first_page 和 last_page + if page_indexes is not None: + page_indexes = sorted(set(page_indexes)) # 排序并去重 + first_page = page_indexes[0] + last_page = page_indexes[-1] + + # 验证页面范围 + if first_page is None or first_page < 1: + first_page = 1 + # 获取总页数 + page_count = pdfinfo_from_path( + pdf_path, userpw, ownerpw, poppler_path=poppler_path + )["Pages"] + + if last_page is None or last_page > page_count: + last_page = page_count + + if first_page > last_page: + return [] + + # 确定使用的转换工具 if use_pdftocairo and fmt == "ppm": fmt = "png" - # We make sure that if passed arguments are Path objects, they're converted to strings + # 如果传递的是 PurePath 对象,转换为字符串 if isinstance(pdf_path, PurePath): pdf_path = pdf_path.as_posix() @@ -124,53 +96,22 @@ def convert_from_path( if isinstance(poppler_path, PurePath): poppler_path = poppler_path.as_posix() - page_count = pdfinfo_from_path( - pdf_path, userpw, ownerpw, poppler_path=poppler_path - )["Pages"] - - # We start by getting the output format, the buffer processing function and if we need pdftocairo parsed_fmt, final_extension, parse_buffer_func, use_pdfcairo_format = _parse_format( fmt, grayscale ) - # We use pdftocairo is the format requires it OR we need a transparent output use_pdfcairo = ( - use_pdftocairo - or use_pdfcairo_format - or (transparent and parsed_fmt in TRANSPARENT_FILE_TYPES) - ) - - poppler_version_major, poppler_version_minor = _get_poppler_version( - "pdftocairo" if use_pdfcairo else "pdftoppm", poppler_path=poppler_path + use_pdftocairo + or use_pdfcairo_format + or (transparent and parsed_fmt in TRANSPARENT_FILE_TYPES) ) - if poppler_version_major == 0 and poppler_version_minor <= 57: - jpegopt = None - - if poppler_version_major == 0 and poppler_version_minor <= 83: - hide_annotations = False - - # If output_file isn't a generator, it will be turned into one - if not isinstance(output_file, types.GeneratorType) and not isinstance( - output_file, ThreadSafeGenerator - ): - if single_file: - output_file = iter([output_file]) - thread_count = 1 - else: - output_file = counter_generator(output_file) - - if thread_count < 1: - thread_count = 1 - - if first_page is None or first_page < 1: - first_page = 1 - - if last_page is None or last_page > page_count: - last_page = page_count + # 如果线程数超过页面数,则限制线程数 + if thread_count > len(page_indexes) if page_indexes else (last_page - first_page + 1): + thread_count = len(page_indexes) if page_indexes else (last_page - first_page + 1) - if first_page > last_page: - return [] + processes = [] + images = [] try: auto_temp_dir = False @@ -178,26 +119,28 @@ def convert_from_path( output_folder = tempfile.mkdtemp() auto_temp_dir = True - # Recalculate page count based on first and last page - page_count = last_page - first_page + 1 + # 多线程处理 + for i in range(thread_count): + thread_output_file = next(output_file) - if thread_count > page_count: - thread_count = page_count + # 获取该线程应处理的页面范围 + if page_indexes is not None: + pages_to_process = page_indexes[i::thread_count] # 均匀分配页面到每个线程 + else: + pages_to_process = list(range(first_page + i, last_page + 1, thread_count)) - reminder = page_count % thread_count - current_page = first_page - processes = [] - for _ in range(thread_count): - thread_output_file = next(output_file) + if not pages_to_process: + continue - # Get the number of pages the thread will be processing - thread_page_count = page_count // thread_count + int(reminder > 0) - # Build the command accordingly + first_page_in_thread = pages_to_process[0] + last_page_in_thread = pages_to_process[-1] + + # 构建命令 args = _build_command( ["-r", str(dpi), pdf_path], output_folder, - current_page, - current_page + thread_page_count - 1, + first_page_in_thread, + last_page_in_thread, parsed_fmt, jpegopt, thread_output_file, @@ -220,21 +163,18 @@ def convert_from_path( else: args = [_get_command_path("pdftoppm", poppler_path)] + args - # Update page values - current_page = current_page + thread_page_count - reminder -= int(reminder > 0) # Add poppler path to LD_LIBRARY_PATH env = os.environ.copy() if poppler_path is not None: env["LD_LIBRARY_PATH"] = ( - poppler_path + ":" + env.get("LD_LIBRARY_PATH", "") + poppler_path + ":" + env.get("LD_LIBRARY_PATH", "") ) - # Spawn the process and save its uuid startupinfo = None if platform.system() == "Windows": - # this startupinfo structure prevents a console window from popping up on Windows startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + + # 启动进程 processes.append( ( thread_output_file, @@ -244,8 +184,7 @@ def convert_from_path( ) ) - images = [] - + # 等待所有进程完成并收集结果 for uid, proc in processes: try: data, err = proc.communicate(timeout=timeout) diff --git a/specific_page_conversion_example.py b/specific_page_conversion_example.py new file mode 100644 index 0000000..3640ffb --- /dev/null +++ b/specific_page_conversion_example.py @@ -0,0 +1,27 @@ +from pathlib import Path +import os + +from pdf2image import convert_from_path + +# PDF 文件的路径 +pdf_path = "D:\\kaiyuan\\pdf2image\\testpdf.pdf" + +page_indexes = [1, 3, 5] + +output_folder = "D:\\kaiyuan\\pdf2image\\output_images" +Path(output_folder).mkdir(parents=True, exist_ok=True) + +# 调用 convert_from_path 函数,将所有页面转换为图片 +images = convert_from_path( + pdf_path=pdf_path, + dpi=300, # 设置 DPI 分辨率 + output_folder=None, # 不保存到文件夹,直接在内存中处理 + fmt="png", # 输出格式为 PNG +) + +for idx, img in enumerate(images): + if (idx + 1) in page_indexes: + img.save(os.path.join(output_folder, f"page_{idx + 1}.png")) + img.close() + +print(f"所有指定的图片已成功保存到 {output_folder}") diff --git a/testpdf.pdf b/testpdf.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dd9dd1a06d66c3f6aea16157d3f5cf8003d1a531 GIT binary patch literal 29549 zcmc$^XIPW#wk|B9pdv*P0f7W23W^lzJ(Q?`R1J!BDUljlh!A?mLbK5!A`&`C@1ZG? znn(*hAiahjNGJ#ATx-v{&$Yhuo$LJB{NjDuJI1)jJ;t3UxnXekzKFP}?1dXGW!NFc z3zEEdcwMa>8I_d8)DWKbt{%KMkB;@IR?K?buLAF!zQrpBc7?&9E}n4Sn}0pHS-Bwp z`riX;<>}z+a@Wce%6s#!g2WvODe*fJ65=va^5T-W@5l+>xg+>{&+m1A9em2@l))*; zDPCx#snN-dHWcaQ>S6oW(Ymg-|9>YLc(~dkY@jDLo@|D=B0OxMC%YV;J3wv!PX<5` z){amc&p&q=I(RytSbMVH(8J2j?PR0aeJf`;6a->~y4e1Xg!n&0q6Oi7{(G8NOkI~( zOwZK=X61b1ks7b~$pJ{Wlkt1ro*EF(-ysmQvEmi~`y83SBMWwQ@%%G{vL|DYc*S&~ zwhmV6uHL++cTNVR<)uX>dF7 kjw-Nt>{Jw*;=Seul?mM42a2IOh zYJ1{_4%EfY)1FscR`SG|3vka9_+X3|yi=huY8P5mFWw`ouf {l}gy%y^Q&p{h+aPP#hHTkiBVvyGO7nkI50qrd%LKg>5;Hwlt+pF*2 z3S2Z$FyGD4$R@q?5^8Z1s(JTZS46u4JtJJ0o6r2&6GC6zMxn)v%M~zQI05rtmj4@8 z>A&6nFFeG5gY-WR$e&jH-ykCMzatW@#t@>)5>9G9h?J) oyp`QM@b>bp z&47#uvzlE;(+^I?g)w>yXzS{>eHyHm#Oi;-;UDSuHx7TM?Ef?|#D81ye}#j@|Hh0H z99r&N3@51{fqO#C%PNb)`4-0LLg=L@nOS%)3OEA}sLv~^E&;Sa6VuVEIZ&Cc&3MBm z>?!`PuCv)XA$_cCPJW?JMyA+3l-}rl2AN1(m}>FJ`9tW9TLEyMILo*SS&1S4qm3c< zV&1g-HK&n5y)K9$cQMZ5*9I@o?mvAro2>cj3KEsWXC%@vlKgdh#D^4C JbJ$p7u@f59N}yBz(G)8S7m{@-Be{#~HLNa_=OcFnNf@rpWwGgO8UdPFlli^vtB za)6(IUq#jBi0eSfu5(e>%Tf{~3zR@~99GW {Za B_>D!himi_|_65{^}hJO|R|JgPn@!N|3HyHjK8%lq( z!G8RN4Hf@j1L9w7U~JNqNO6#F?U>Gtq!D=D@Yp9}`ZpVBZ 4c| zPHij+FNk4+Z*o}1Ny`on1srYkCy0urnGBz{Va^(UNBpiQp~r?{VQ8~yZytOlar=b} zIvMuVr~ORXcCw>ucv0TD1Sys8k0gly35I|7eA9n5gr~+Pyz+N=Wu+xVPl#gvZ*B08 z0- ?s<^v+4g@PA#iVsRz&v8h^Eo``peO2Ifi-gbp RXC<* z+-%Wb5*aM`D*qbU#D0z#t;#>ZCS!@v7#lA?YCiw*?2~w2w=dGg4FSu7Vfg&Y!cUdu z%kkF(SrZ=fe@oA-V*@dmdE$O `|kVz8joyMdtao zRUJL-hnp%Z5ZB$Qj$yR(RMPoIPO$qP?H;$;=|@vr_k9Lcg~$Ok7u#PI|EC0z`kM^; z9=1@A-!R_%H;gB0@)6X|;Y4tpC}Xt~6$$;VPZ4fz&d}e|nfK1$!2OvF|6 ^*s9