libtiff/0040755000000000000000000000000007462533626011214 5ustar rootrootlibtiff/text-start.jpg0100644000000000000000000005701707462533617014044 0ustar rootrootJFIFC    $.' ",#(7),01444'9=82<.342 $<!"1#AQ2Ba$37CRu%45qrDS?ʪ/Z:tӧN:tӧN:tӧN:tӧN:u/Υ<%UTk<4 1=HA 5,R^j> eHk ˄i G~,&-k+]$2Wh|G OeND^C^)㻟U-ӣB [oM8~W9I:xX]>{LFrnUkY 5c,Vk#8v BÈE?as޽>ipTOփ!*BrɸDU" bgN|%tӧN:tӧN:tӧN:tӧNjognGr[8Ҙ@iaO{҅ XDx{)`59f)q?}6.,&51?9j-T;zɭ_d~SxL͂j"xbJֽS)06ST9j*aPI܁G"YvFSx55<:+a,Q@*T b=tS%&[dp#H;D mvH{$ Qi`מ6C:qt`H D`?H :uO_)9i>NNTp<j=zvrSzrs&PA'3(?=ajI4i ;z2'zӧT-CG+ׯٿIZą#B#~A,O|J6RR%0 E,@zC^XY U"b oCL=~gsP99QJtwŨonkRxic$uGo߮tO%*Xdd{W'J}듂LNJRȰ]@u #z?gYwzrX qRGM,@ALte@o:@XXdqV ! gt^KV"HЅiӧX~ףb.LEp0XhF[rl xfQq&./y..K 14IAyO[l-ԅi,֪@pe%>?Lb4&Ӹ{Bk3+TyC_$ 2Cd*[97ꏺ;Ky\׳Kv"z%u L!Ď8T /v6a bM07<Ʊ Ȓ$YHY儐@1`LUC"oLxUM[<1DxU|@Y?l~G?͊sZҭHRxa\bH\1<\J&QzHkc^L|r>/^O2'ڋ ϒCd1%pIO4I`5Wv.H]wW cnhx/ _{u[vIefVv7 CĕVG}z&*(?姵b̾W@.ʣHf㡲@9|W}X#JVJ?N9iaq~CgH2/&nHF l3c"QIӷl׫<1Q$]'xڰ 7!`g,fTj۩4Op+$KxҒy'逫w5|ێn"B1)SĎEZvxc;-j JyBʷ\@7f\m 7ebVUH $4K$~N\wS6xU2^th#DF2)(tNה1}/JW]G!:`j@۠m%_6v yl43FtA S Ɏ* |>>;5ܨDn~ʚ*Na9[+ $;QgT1G['ٷW;k#k؀*~4I 1aLW' H_x w?|Ҷê2hNڰ<dN yKӽ c1d+h0?xV 頋1oܓVO4Ğ(:΀?ߺL1*e`,*a/9*q!! #NUQ)=kȩg(B,mAV % n;J-d]%a!,2\(< L}P̅+եX륵3+x@788 zG_ٖN#*Q F!k }ZpZER:m!U} c$`n,伣&)[ݛ)E4=cڬNK4H^p(Un¼jFKۖpUy8gX;_9]orJy ]' KZM+2K ce*O :Rt譇4RT:U-ݖj@KjG9;}kw>+vg{U-Ry`YXseʪx7LtnѮl "PE ْ@e݆K+roP1A$w{:ll9?lG#I*IA @t$ VI⢶ymܞ)Rȕ&IIB~=;{pY?'g)=qTıѕB3E}1;GOTK5i $Je^({XܯΞUjc7ԐK#N6l8]|}v8r7(@U Jj{4zŒU~sl$p ԏ'hFxbk(DiC$GE>Y.@t0ew+ekGگXM$}wZb*ARjHiؒ7|4S 2#X 6й 6=SkVz)DB1@IBO/ga<ٯj)܏fB`,hk|64Cu̥|$y%!KJCG'MUl;e)ح/8);OlhE}KA x[@ǒ$WĀD]( :ɢn>Bg(4Q8ïVťA<ݖ[Y9 B_L\ε^ƭ O=2;R^Mw}tČ}qPFOfmD̜al?7dfbeGN՗xW6*ı}w;\ԍX%:aER3/v- VOvTV$β,̱K陔s:_K%3;l^42I|X{֎S O4 V@GgbmU~g3bw)IWИxANS1tbUGL0E)̡4TaUosXKX%u:IbH|!|nm>;@ uVnvdc'%&b’J5'/MpD:^vL5xr=4dX즐^?"c1Am;K%o-kwVDݹ@T**T.;=fQPٷ-I)K"C#(3$/3sF$'  vԶr!\r%Y׹U޺3G8V+6#yY2$,L s7IJ9ġeVlg;CMV\uq JH!e~s'$QtWGysXzd;ySYPAY|G?ܽjhfwڬ ?B?f1ԇuxɭ?2T~نLo4@rV syJ' ^[GvzkBC5gnj* Op5(9e5acc+B >Ss2+6kB#Esv:ܲ7&N9YXh^6*wD@*GuW=c >;.fů3=<~ Bf$_g;9[MRP oNU= q2%ϬubZ1[H8W? LReAHW!e{?;um5zt`~:2K5ÐVu%HB&bK!Y?/;zG%4_*%IjSЉPҡf ͋)o_zgށ/q 8&EmTr,(9f-a0?G-)6.,GB娳)׶M#Q\ عf񯏅Kmm!צ}'N85~b(9"30C=L53SG5?+J#vt6ꞟxbEr8jW3Bp8tl|Z 5T0%u ! 7?Qe|~m"CnnmA ˲#&P~r m:gӒXq(-dbmUi<@_߄m;~U"D֖U+)n &d 2>Y KJX,3Hi`sp#',pc}̿ieڒVC<yRącuz׭U0y\"Ie-fN*6y!qbαxK_j4q)YM~$;:W>k֣$L#hNzv@ P܏u{.O1*Gc#c!0(P{.")wπ[RÍ!]Q[nHMIlt#o`osu|RZԳ^9t{S/6-q$ǖzڙ+Q\},W۔YZ rܕHWrEDW^|beXMbU%,V3Nl=\]Xcf2v0گ*@\=k@1tuB5&G1s#RJ3Kb-{]~!OoJ|o9Jh,gM.)??OÚ孍{Tw}Ó$Aa5z/MYVHO0$O:ӻpZyz*z!*dܧ?' Dohv[@Hv^c/)i x&yj+J5M5'B>k3 .Cvq4(,ds> bEzW׻񴫉,>:Dhıۋ5]k_̱Ӻ2PWjIY EKIֽ^ۘ|߂sxDhܪ%A'^z?bmUN:tӧN:tӧN:tӧN:tӧN:nڵ'T,I1UU,ĐI$ =i'kWw 6v U` ?QVctȿ f>6iƸ#= ;)jjvL{ :8C晭ߚJ'`FL-4Ni6VC$Kx#e#OC<|'pG񺇇N. ʭFk_3%cU{rXXXC)N͇wKS)*!%{'^Bv|_3|J#A.z KNŜn lՖDsHGb9 6vQ/Y%山+5^߀cf΂Fb䵅lKY<$.J8I ҈XHg^v,7k׭T>?˧fsʕ> ;bw&4gK X8PHsR47tb`Z?ş-IY!tf xqŷ'QJO9NX窸Y$<G E7g22]>R]wawmSIFtŁ#W;U#H t_aUeoQ9+Hr`Q\r e]h#,oۖ_FM=k'NX^!N[O7F>]Sݻ֏D2D1 ^' JI{ &%iP0(W䡉`qmG~bJ"jк,|cOzV۷cc!!1/ K:䮑/%m2,F 끏mOu5$ӤW`4@ O`%{9lXUTxc(ZnDHPWepTbCQQ2Vfg~uaa>|j5s0JHsn_)v`:x1\vb5iˆ X+G,Ix!t0Fz;9ටim/逳 b 8{~_JUz tr.jKj2) .3XB,^">F7@Xq}A'|)j4WP^kR!H 浠}65 v&ɕㄻAp'݂bTi\i6H G&J<ҪaS@(grvݹGGv$c#mq7k!*Z,?%gP:$(O"An`X=$bI[~Sb ]Ƚx̐A*Jȁ,E˹o~A>YӦ/yzHMO,}0R} Y;$k-C\W?bQ,ʈB{ؽ ޵#G ilA@*,~=Us7LKsگuZEmR9$?<]w-ɩo<{6\}˿ք2&OE^݀XmG@ 0kIYY`OP@t>9#F\s+s B`؀@?'!3züؙ<%15eI +OaRwʈޮ4r* nO*drA?&~/&fe[A=۴lc!LY#FQA3/mmO4 ,qhP3$߳ChI%N:tӧN:tӧN:tӧN:tO18܇bgvHvڃ"Ц>5 _=((hԒl* I&b3vr痬:ώuDFR$ v$E^a+ݒmٻb4Q#IZHPS܆=p#Dj[~ `b(̏hy}(]-,8Of9=}į8}Ib50`O|WvEݵAI+43G*0`䅤 hJ*W VJ.BȱN8 $LΝ:tӧN:tӧN:tӧN:t?jӳ,.X[Z\?P14 o{RU+yu,8eYQƼ vCr()vbL^kHB9뢴GVfOJZ`PdE={ xmZ'iFfm`! /_~,;^f6WDUc͟g(DP7`Ҩ$ |tv&Y3Y:ZH9V[0m30X؍c`e;Uuf;S@oL:G?IeK [%k6Ӣ=t!#AҪ+h83YBk)y,ntu8_^AI[+GW?\#~#nBFflfמXLBEO#)i[neeVbŇTy<|.K ;tTy+2xT,o1uq=h͈`IPcr4#eVB:t<3ܸ|4"яQd-XBS$ӰUCbdhqb\uޗ9y5[A;j6 )kb2ՀT/qv~L2JJ 2ԞQqM2HY?Ia$Q r{ݝG;_i䍿gڝ_;jږlRoPH:(;?[*t\hIkb h13`5|\KLtn*;ޘEVwMc'ȅjQll&xtJ5 [Ln4cư[I4X`bZZ]%>\krZ7C(dd0 Yj@GMQC Yx)1WZ! $W*XrZWvڪyB0fqk[Μd^HdD=ˁ83xr D(e!hk֏Ut1{Szib8,Ƽ$?U%P=l $FOLIZ, G8e Hؐ?:aⅳ 9^ [A'njߨ+6 [\P{q3$_{,kGJ<=DԄ"S@l(I ]o[ұ.>aMRg>8KWsRb$l *Og-o$88ZnA}ubkv1rYlI"%jcwȌh{툙,n@ܤ>NY q+bKXUE$b%UZH.%42o-lT5<ܱ33}[ȂT:̵j$ $rͯ@G_'i܃gDU*!CƞhF/PG<,JbDqem#_#?oXXp2,EKi,J-m(6ۑ VV.)+ =H0^HGP]YG"ʟ`N߿e(c%[ٜ|L$ؖI'28{/jP?ݸwڂWt sX )(JQlGg ǡيl\(2VK|?l}<^>#Xކ9LF 9;JW%i\p'K2PV1Wno$DeI2ˌzNoW Ո>}][d|LrWJ4+LW XM3ШeU[6Z*z6Ly* yf2b m+&Ӫ|I?!$IeE*4~~5{cOoKb9yrVkQ3)d_#kgE $^dw;Vy:QQVR|/PG;>3YRZl\y4QX,ŕD/S~cVJJ-j9rHD;V'd [7E6߸2S@]*eilzc0~x^|xGd 4lxo' kgx QqmOɐN{M:Bf2(sHr$}r99vWIN|{]ik4{HEh0?)jn`X=$bI[~W5E?-lf-.Q(o!mt#}j ^($ qUE@=uӧN:tӧN:tӧN:tӧN:u/Υ<%UTk<4 1=HA 4:˒l%שcryYY{v9S XG{4oQ,ü+AxKL\H̦HCQ仳)ݿj5c b[Ly@-f)/fm~mFc9s,'OHUVhY! w;1.>G5(&y髈1~-| YpIf\9R~DtÐ: lѯrf;z1(WZ(Wv>08OwE]A?+$ҥ43Y%% C]{q2hSC '4~SQi[Z@@H}B[jA=ybTa;D2A?7~g^Wg$hV7٢t%SrLn=Z<ҜЦHsI^2|(ُ;`Ա"d'IxJ鲣 |Xι{5&vaI<\J* P,Aȼ`6Z>\j؏^AIAG+FdpYY".Lb>tN-V3Yl汰c276O0iNIȇ_,h7%MVC9yI!$`C;N䓺#5mY'@$㕸EhsR}K/ikOv5?dB%dFǑ rؼLZGB꭯D cs>c+FewfPc5Y7F46 z-ZAIcב-dJڵiBF5i?ZCݹK|pbʐNЬ^(gIIbCtdžlw5Y.I*Abalhh:x{j*P]TJm\hC׌L#:N}Zs*azX^P[*xlIb59H@pՔ[ؓ\FXNw.BbWF&nl'Qn(T$|n'd#db9Dr#-4bHyBd^JbaotD&;nlPztHų3N_IroB7k%WLZi=o"<[}#޹,])RR|ȿV*jUK ͥCya'גG71H%yX{؞|Uf<]4c#v_b?d71YV fP4 [A ZWp8*ֺܔ4qj''*8 ]Ύ~ |JvɊmg WBHH%umv}% #U%W+hhFpi~GKJ3V%$qg6:GG1V!: ,qy՝_ǭ_ŃqW] NV6J4GFuf;V t\5vCR&3,6NCi6mfX+נY^*v~NNTp<j=zBSPϋ9[ԍ $_FVTdank,U&hILg""*xxa9(_`78ܽ&k~$=yW!ZUr=UMR֑5#ulo9if>h26=/$Λ 7&AŖ:S\ػXD)4Ч""p=*:1}hUЍ?X7ϿgggY~׽b^L- >=((hԒl* I/.&lpTy>&=$x28IvmAwwM9SnKm|s9Z"ι;'nd)^*]-p|X?>wS2U77lu %_ɓ)׫jՠɩv{1n0t׿MUcǵ;qTdKbݑk~A{xTI7ctcƂ2s2w:xa%uD|7HBk%b!B!B!B!QݳoP{PKn1Ǔktť%2ƬHIg0SJzy ȿ*mH Dg66x:e%9p֘;q 䎭htL` >D0"H!1?EgR䨬d_hBZLhG'y7gpqF2",a"`|2sܟxFξo5iI3Hhq5F;}qFiHSɐŋNpy>#U_H~Z:ycU̅ @CH8f[0h>pL 9hnOMxp0n &;0Nz䋈EI"p!4?)OX0~-t_?Ac]BMO\N?ա2)K=xVW7KssaY;pIyؽVkGj>ha n`\9-Ո=4GFG StM;0ёkB/4v*[FXGV)>ہae.D,d~'&}'pᢶEݬC&yWЅH~нhz0YfBP™cXЃ&Z#h58CHPju1rnZf2-hE ƎKqZ{ Y2 |r_֩)vB@MS"н\IXφtK-u";`h"`"};.m?X^1vg'8 HDJyMv҂sn"Sq 4kX=j_D|ho -!nmR($De cs,Y/"G=p@ ѿ4- Z7+ǒ^:"4XP cDsRGSN1& E #F篆QL?OKH hJ0Uv=}8֋ 4O&ypԵmɓ'n^=p>]!7郚βcʾ={OR3tE:x06m<]q# HL8ߟj)cւ_ qŢc 'FųWR9 pVc$5w(2R 遗G-R"ݜB= E1D(8D9<1h?h쿸ڢ'f>b6Ŝy2YfNq[#p¢o @汭jsWf"fnKlt_?P͸R `BOǹ.'5㯴&Ƥ ?;vz!ߩ! uEp餆3w]яA΄_N.\;ݯ_H-|ѽ*!dF!&ˈc^ ~ȴi* dZ}YE_~8>g!;B,>B& "6mT̓ p`OG[v7r/ȁrZFT (=&,Xy2cA;>RxER_";g&K ?nt48X/{%xZ̏L Q;ks"Gb+D@w FԟwE t*5;xȱٍ ocA>:5L[-CL!8}L}O}@1,h&M 'O/A7ui<#s'O 3U:^,h\,x׹ȋ/4`cDۻyW9߿Sibȳ4#nlƅ!8xOu*9*ػ`8sEL-yhLWu yM2X2 '}\I*BfpAl4.[tG 1|ɽM{s"<$g%XҳժkR qh>E{δtE#H5dIjrj?A7G>,cANON4EKr(t$+w/DiWZpz/SJ5ĚP:zƀ/\JO1A)䳠(H]/wFk#ٌr,rG c:2.wOZ3Dڷ$M pq,>MN,ןn-4`YG:#ؑn):(57 vbAȰ!{ 6CnsE^_H)7M0mI"oȃ^~AKz,HUݎT߻nn؎sJL):+QHmr 5H7v_ܗ$WOKdVbhBXDY {'N'zzڕY S%MT9Mf;1N ' ՙTf`y;P=6H׹w 8ъPv>-dևId]ܱyP3cM@ xqEs.2**uPNN*Jdje7>qپZ -lu#|Z4X5kEYc_?Њ}'r6(󟏓DguM#nu`h0nOԱ}k΄} 㤫-8xtG4SI"` h> np7n%vI(5kFuE* Ndi'vCp d8 j|Ee-Iv1CDص BB2 Md܈ҩV;du,工?zK;bDvw%w:w] P>v=-Be'Qю0nl }=c?~Җ̏;>r!uZ%[Ҙ!^5ωΡO%Pঠ2N D*40ȁc ÃF Nuοr/c !P̅$F2YH>GXb̏&NoTdF?ӿs.,W`7t;/䁯iÏi ?Enc^5kF1"+û!!yD`A<AxthGhEh3"#4zaO[1ϵCMKAkD!7`ۄ |v_Mv7np7&5kEf/orXCi|2Di 2vd\Ѕ\EtWL[CXNO)c3?c~ :x#S -m[ ΌnDjo!wo"cFOߋU~`ߴ#"ёN !P̅$F2YH]jmMniԉr6MyB|mHv’!N]8]jmMniԊUR5$v.ל%Ե%zR@1Ax%_G)f3fyۀ!>ΟčV5ugn lmd!&L0!cwCqM8dSgR*[?~ѩ;!8y7p7HXZ"ocVvCLkϟs%';#lmpMcB&"ƴE>~L3Im$R8R.D!5 M/wOSZ8myb8}D2!  $#W:O~h=ϧeG*;~98Y$}H:O2 h8? * + f(r۞KZ6$nq:F&R"i vI,s=6xNۙ @Sp-::}w=i1( j=M+'d! :=yס*#҈ 3S'O%urdsp=hъhvF:k!M{rzh^D)&( ~qtmtku'r4B5/`ju 3H jNݑ `DLy}$?"7zиFj@uV%6uck2,^uA*hXt>DЅ%c՟p~=V<ݎT&ҊTWIk!0h^y=>u:Wѭԝir\>DԾ>4Xݝ>q2dYWÒY߉X=civЍǝv#V V&__lrЏF݌!B!B!B!B~?4n`Lg`fC8cF>r 7ı8d'!piS<@s&B/"Ҍ *|AocB2pOBNrs1=:p uWqy, N rX%y8A"+M4AK}BE!E87%PN8g.#w5lFE5 NO40,e[f׍k .-! uWqy,!t)6dD1cgpdVɍ8i: H"kq?!gX4RW-逽Qm%;G멞Q[&nizGMܿ>wMm#8AXMhqsY;=s| &!VaL'B:h̃IǹO>4֕5۷p4M0K'u1h AAWi&'u 'L}EԎ$^G3YBUFF9βMx1H5y0yw)Li տfpF@& 3$}M̟jMbUiH#ZC w'N ~Y8.Kغ`I^=~ ''Cz硻hܼA$u %|7}hxWVDW#Nȇ:c2+'ňI,dY2gcn& Ld u kc紏 ]Nt6zgDq2Љkz,_MqSj}a n 1p0xh;--q$Zc{+ǿpzȄ_8U3?:[L$BV-y5ןi** &t!#,~ DWl_Um݃<kǓg7-lMw-:up4#v!I<#gZ y,h=_'~2Ml>3y??inMso}dhG7Ǜ0x$ 1Bw܊⵫bn!! OVLdȿ?=i;8e" 629BdBD,hDӒ[糕~+S` ە$,Z,`N'Md^OOJEm`dvA8n@._fHQ`TmSr1D7"Ə 629BdBD,hDӒ<"[-^Pt767X >vcUzq΄ F2._|>#.v/ْ, u sZqXa1?kr7\c²vdZ8kG~HM'Y]CZfX %8_=q:<"3!ȅ>~'OskqNA1@g_=k=A^AyL)nL\aȵ\r57DSߏZfA?h?ӎ(/ ">ZƉM ?>?cnuGX!y=Eb4[c&90ο /'!;{8J&fȉ.-4Uh+ TJ=O$QCΞ1̊:HVp?!s 2*z* C;ݠ]p5h 5#Ua7 1[iKaA0/xXO~wh@ߋGt=SdF 7@7X0u=G#  Saͭ#9 Kɸrwf'~y줖r&8D}S-rTۓ"|NN%O+3#sƧwkF}Ů*hb¶ou&dg,Gt8fZn,o5>~N0*ֵ&5*^Gm.e[!5wb{:8ǎOW0DP$C M؋ (ݵL@s"N_} GR A1dၣLGՎh+&7D  ~ 2v#߱>xEP:aνl~7C"{eA]N񣳻nv,JH2jѻ|vrcY˓B9;Nj $6YN>"2d_ b{/)ްnGtAF^3@)f}kNNwȜ>MY44S&g&5̈Zc KTl]( 8kFDA.Rpnu9@$y^Èh^GEBߟg q~ TwRv2V27i!i_zٹ;HPM€R *Ƶ谛9HV*{[]m6GoD!$8M},܉5S5%ӑl:X)KZ<]}Bl4);"65>/&ri_Nw4׃r}׍:yCxCB`2JM^ 5!B!B!B!FF) _fF8)m܇?ٍbXG2&EПy# #B5hG}piOgOpR7h,Er'G6`QnrBxB!B!B!B!hGy?DiaB!B!B!B!Gh×F4vȅ('9 umOK +´cBΦBy}9L[-CL!8}L}OVSO$qDoH'JۻE=3 8hX&q;9"%:hABrQjQ,+Ƽ2- ]'#&ޓQRB3$B!B!B!B`(vM` dDzp:"ݘT=v!5/A`q&6l%=^IÁ>կߎSV dI!%prZLhg̅:ȵ(@|vd Z9s{2vd܍"Fɹq!Bp8޷gnANQQVFN'`qyB!*=G(<o[3 ' cHBrx'#@gEE r7ېyAŤ!~gC@ѓ?^B<]xLhnI q}??tcǭ }SL+&&D~;:@:>D4?nCroy0cG";]䗴WիO֪Tb %1n"t,|A!>/*S^&ѷ&FWLDǭ=`۹3Bg!H^\^|tDO'\V*Qp)H7]F9S^iH; f#H_?@?`4$܏ o%rC 'Ly77<_ɡ\:tKAsuZ8MAoɄX&4,4e}gWVhsP@ލ 3uC밍?>">p*5r3@c-7Ǔ>$?ďnԯL|/1n;νzm#uSvhq mA;"5}>#H_?@?`4$܏ o%rC 'S,Zc[u"F]QBlXDXο_ ܉h! `/Hb#c}ÎoK* uhp^2G8 ?tW$`38@E%^IHGد+HDAg[3XT3=ZEF;-2FCElƷ{Z " Aȿrt*-v;".mr0`ۻpA%ą֨並F$|H7tʅ0c9 דX@aP KtD-ߐ1:ֵɯs_zh YD|xʌw}GDqS{zB>)gFL܊F@@ ! f}>#4VEndA9wB展1:DГ8 .N 1hɟ<9ZOiıʛB-5MIÞ3Od!?̉n, v9`sk:Ȇ啺Gcnݻq'sq&"* oFdǒ|Or/X?oTf7l\pr#sD h"tbS*hv:[AC^w>Un4hCTI@w|~1ԊSN婍k\ =Yr DX_b=z fᦎcu,GSFDѮh֎?$TtVPqVlw@<)kEBВa^KXnk^j -1!v+Ȇ!cAِcHU*OI-y݂A!Bwƿy#Z ے` d^1F;lKi&2-`;?gĐ+ɄjJāׯ;ɏox:K1ف>Wa}2jFzqEѰ`cDM4Wi-TSHu B7'ak!b57ξnr{2G+J)d8?5d?ψb$*Id"&ϸ9՟]J2 'px<ȆF*iEh`S*+LZ4/W̼s:ՎT܈~nόog_2{H~lo,2SČݣ nЇ&4c:ɹ|8^9wqHudȹ"Bc5^ʦEɹҡd B"19䱤} ێ ;KXǫ>g'>Z J#7BԩiE:xÊS^;Hi>gȹCy=]Z"XhJr5q~1cq~ژߐw1׈UM/!8Y"L~W8Zj7+#%xh;ry<I(oSov6,}_G}~N&r+J:KJB( `2Bȡ^LTcQ~i9 gT6{8h}$B `/q[p?t~˪}";" gk%dqANUHGbMwhBK>Dh*4; 4Zq'VRsl_?z`HWCpwt!j]kƅ b]f֬[L$,}4 !/s!B!B!B!BV`F>)ۤx!)k׾Bd_!O>M& gZ7<:GUDVٙ! L"?E]JEACdŐ$D- }Φ.jT6; 1 ւ =ŏ|q4V!0k1r,߽}cB!B!B!Bքg3g4F!B!B!B!Byъ 2)m n9zŎōnO=E@eS ϫC^h[B-Xrh2 &;pv{HfHg/xmn8DFd8qzFG;H[ ZȅXr^g?FJXg]ht֍}~5/ B!B!B!By I& )mw$ t{ƸS`y-Οc\d:\8v@Aoƃc'Q|< ky 8A brÿ :o& _BqcC̊42;v˧"9Ѵ͖"~Z濡ban6c1|4-!B!B!B!Bl7²zcD3Lh9=wouV0jNGd"37:=W AJ 64?8~1,oLvP;[VfhHY!ѮdF̻ε@&U@OqxD^?eW*pt:l`F %Cr9"]ȨzIL;Wm pA5?vL~o?V@΋M B.s=s~\7tǘg3Xݍ<|@$ ccsTrS`[ Y"N[ Xc8>7^1tƃЪo\qWnENK@D|q3lFh7J1²IdA/ x:۱6thf&;b׹ɹ B/߼r)/*=GZ%~/_s_s/܉qoVT "C2$/Q<.uzlOy,+'|E~'ORsLacv6X,&cϿ:j`յ'[ƜV!,q|7MăR[gy9k;2XƲ i7$j^d#rHcᐈ11z?[rG4uZXG Ø@"̞$U]ߑn5R p{['}wNmޘGH\H Ж;5s@;7Hca;L=_Fh5=1vvD,XG:=p羾O]RNWҖ$N~"]+#)R*!Ƃ)ٍ`v:~>(꾑FSlq'hF">'ֽVwRAt;ASB57b5~=f:EAC'DPVWPom$*v] `y+SPFmgxB2r_7T@VбeeL9猒'P^AƒѩAYjm5w1f4 co& dmHW# &M/sĉh)`%= ȼȌd_΍*HJRBG $-sָ%9X!ݢ`pIEGx}GB23'1N4_{N~ru=ZRNA!\W1OMqg!8h ͣKZ16vo~}@Ǔ~q,&:N  w 94O 2i x7l۸ɍS}NR.l07c V}#qL&BN|>  B'לnjr7lFb1Ov *lɚ&6hFLx|w>CvWSf~ƴDIȋйc!ё %h#L~3{Un8pםODՆQZ Kg@I3̞2/ڿHf &FlƆ{=He+`>  !'> ?׊ʋ*{B73=E惰@Ǩ-d!<5!|"eΐƲ-gƲH\p=Cg ,D\>2qg]#r<ɿq"u gpݷo{q _#jp`"佳?k'ɑqݣDM=:<&;% 4H-2i> Z"Cs'>͹8dP`?HH*Cnkwb/8ׯ"4&Yz1vvzH6vmvǍ7-w'%?0aFۻǴ;}AO ^#d ĀfȻ؅.(3o[hx\x~;яܳ'=!B!B!B!*4u_GUE-qˈ`DMSL#B|EϠGCh=v{)&;18hʻy L65#XD&?G:%[ʬBxt{ٮ4 v0LDryv x>B. "r7 ՌΘ!B!B!B!B3ZhXB!B!B!B!Blibtiff/picture-start.jpg0100644000000000000000000000625407462533617014530 0ustar rootrootJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222/9 d!"1ASaWg#$2QbC;b!Qq"2cR#31rAB ?i}}8)KǙR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR6[Od2k #S/pbUTCs8 ?&Kg!GOpkE1sG߅+k!3"|%I ) )L|-̯ sFzxZ[W^A?gK40վD ؾqrRe#H8vatE=sG߅+k!i#=o ]Z4u*] KA0j;w 1qBu'WvTw\*>www6-į '1*"?9 ཙop8˺m&4wR7{˘"Sev)KLs-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR F>L 9]L w.n]RodQۤdQȂ[ꌏ _7ĸQ7leނ쥃0\k*\s];H<_MOgG) :}wȶ1!:;.Ќy5ߊ'|2×فᄳOhij)?Xҫ!OukZ8|1&7H;{۬4eO)^İfrloo]ǥsJ`e)6ǎ>5 18X RD ݦf8W"% 鱗x0[X~\d:ѦÒEF 3;weW`bŰbx[IE1~ƹf<Ӿ#1)yn}-yLp%#٣}MڰRLs-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`SevAJX*\i삔&TM)`Ls-۲ RR6[Od2|eѣlr<yN]v=.`~%IF3j̷Kop:nwM˽K.`(#BT璻=}w0:y{$<%/&xpfRtmbB0zr |d'~M˖k_53G-Ա)( JC!R>=î2< ?=<12a;X8#@ߧ窻?yIJR/ R>mb}=9H>pns!6{G8@$NbU x? 1][Y}Gg˵C^M$0Kb و2>> -m509~D/K͵ۼeO)ؗ|frH^?|G.Q׆K3G'-S`2K 3\'Wz%yԂSa0 y624X%ZiOۘ8ev)KLs-۲ RR6[Od2 ln)KeKm>ݐRʗ0)} , .`RMiFYu--p*P ֲp%|O -ĢŀMV TCs8 ?&nB|MjۉCCO4qup?p *WO0S~\xݗni 2\=NSM.p?pt:Mf.B.;Oo sQu$P*^F@r@G}6_iG- Q(#?''Oc$b.E`JsL8kDx! y~8G"SKWjXP҅]LBE N?ό>eph]!Χe8| gp[IL҇T/L ggtlN͝]aޒ?ObQ@l9tvN]@ 秝ìi>^#U\NRMjFYu%-p*P ֲp%|OJ7_a]nڏC& 27Z˭Q?(|Da}FYuj>'/k.[Glibtiff/picture-200.jpg0100644000000000000000000000360207462533617013666 0ustar rootrootJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222/"D  T!"#3Q2CWg1$BRSq%Aabr)!QR1A"aq ?T24fSl`mW։ycvdY ].&5zR\L%;[ 6:11sQ<0٦di1#WD dy!|a=]Wؙ6֮163Oq"(ST92_-v < 8\b2-LΣy?#]bɣ3+׹=) X:脛kW}H0\Q<`<&&Q-/,~HNZ^B/ roFy?+g6 M/IaW>(ਊQW0 y6I=$4fSl`m3s)Kme0im̦ -ٔ0 -ٔ24fSl)Kme0im̦ -ٔ0 `mL[mG=C'#sh͇̍8Rز4fcsfFB%$J[㈡q{0Y(\Q$t>>OO\,IFft`8gS\c&/#?dڼj\&-LΏoKzq X^ E8Xfuw'|.K2+{pW}?&#AF~*X\, 1lߗKcUH9V<9 %6R$ |ٌCIaq$i{_U9.OhՌkK5*z3#f()9gr5J.!zDY 9=z|.$^JLz"^-yɯJ2*=9*KJ[m~I$4 1"x%"aD9 `g#I#< Nijӛo3Y‘w@O돓`S=6(I_)/&QH4#8G"PuH5ϽRm4>)KUXzeq: +L4'r?Dr`5 $Seî=wb')Iz'L[m)Kmh#sd^$}z l>dspe0im̦ -٣ďAx9362)lYL[m)Kmh#sd^$}z ͇̇ [libtiff/write.c0100644000000000000000000000230707462533617012511 0ustar rootroot#include #include int main(int argc, char *argv[]){ TIFF *output; uint32 width, height; char *raster; // Open the output image if((output = TIFFOpen("output.tif", "w")) == NULL){ fprintf(stderr, "Could not open outgoing image\n"); exit(42); } // We need to know the width and the height before we can malloc width = 42; height = 42; if((raster = (char *) malloc(sizeof(char) * width * height * 3)) == NULL){ fprintf(stderr, "Could not allocate enough memory\n"); exit(42); } // Magical stuff for creating the image // ... // Write the tiff tags to the file TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(output, TIFFTAG_IMAGELENGTH, height); TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, 3); // Actually write the image if(TIFFWriteEncodedStrip(output, 0, raster, width * height * 3) == 0){ fprintf(stderr, "Could not write image\n"); exit(42); } TIFFClose(output); } libtiff/recompress.c0100644000000000000000000000426007462533617013541 0ustar rootroot#include #include int main(int argc, char *argv[]){ TIFF *image, *output; uint16 photo, bps, spp, fillorder; uint32 width, height, *raster; tsize_t stripSize; unsigned long imagesize, c, d, e; char *raster2; // Open the TIFF image if((image = TIFFOpen(argv[1], "r")) == NULL){ fprintf(stderr, "Could not open incoming image\n"); exit(42); } // Open the output image if((output = TIFFOpen(argv[2], "w")) == NULL){ fprintf(stderr, "Could not open outgoing image\n"); exit(42); } // Find the width and height of the image TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); imagesize = height * width + 1; if((raster = (uint32 *) malloc(sizeof(uint32) * imagesize)) == NULL){ fprintf(stderr, "Could not allocate enough memory\n"); exit(42); } if((raster2 = (char *) malloc(sizeof(char) * imagesize * 3)) == NULL){ fprintf(stderr, "Could not allocate enough memory\n"); exit(42); } // Read the image into the memory buffer if(TIFFReadRGBAStrip(image, 0, raster) == 0){ fprintf(stderr, "Could not read image\n"); exit(42); } d = 0; for(e = height - 1; e != -1; e--){ for(c = 0; c < width; c++){ raster2[d++] = TIFFGetR(raster[e * width + c]); raster2[d++] = TIFFGetG(raster[e * width + c]); raster2[d++] = TIFFGetB(raster[e * width + c]); } } // Recompress it straight away -- set the tags we require TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(output, TIFFTAG_IMAGELENGTH, height); TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG); TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(output, TIFFTAG_JPEGQUALITY, 25); // Actually write the image if(TIFFWriteEncodedStrip(output, 0, raster2, imagesize * 3) == 0){ fprintf(stderr, "Could not read image\n"); exit(42); } TIFFClose(output); TIFFClose(image); } libtiff/read.c0100644000000000000000000000224607462533617012274 0ustar rootroot#include #include int main(int argc, char *argv[]){ TIFF *image; uint32 width, height, *raster; tsize_t stripSize; unsigned long imagesize, c, d, e; // Open the TIFF image if((image = TIFFOpen(argv[1], "r")) == NULL){ fprintf(stderr, "Could not open incoming image\n"); exit(42); } // Find the width and height of the image TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); imagesize = height * width + 1; if((raster = (uint32 *) malloc(sizeof(uint32) * imagesize)) == NULL){ fprintf(stderr, "Could not allocate enough memory\n"); exit(42); } // Read the image into the memory buffer if(TIFFReadRGBAStrip(image, 0, raster) == 0){ fprintf(stderr, "Could not read image\n"); exit(42); } // Here I fix the reversal of the image (vertically) and show you how to get the color values from each pixel d = 0; for(e = height - 1; e != -1; e--){ for(c = 0; c < width; c++){ // Red = TIFFGetR(raster[e * width + c]); // Green = TIFFGetG(raster[e * width + c]); // Blue = TIFFGetB(raster[e * width + c]); } } TIFFClose(image); } libtiff/source.xml0100644000000000000000000005703307462533617013243 0ustar rootroot
[Optional series title] Graphics programming with libtiff Color Michael has been working in the image processing field for several years, including a couple of years managing and dveloping large image databases for an Australian government department. He currently works for TOWER Software, who manufacture a world leading EDMS and Records Management package named TRIM. Michael is also the developer of Panda, an open source PDF generation API, as well as being the maintainer of the comp.text.pdf USENET frequently asked questions document. You can contact Michael at mikal@stillhq.com. [Link 1 to related content] [Link 2 to related content] TIFF is an extremely common, but quite complex raster image format. Libtiff is a standard implementation of the TIFF specification, which is free and works on many operating systems. This article discusses some of the pitfalls of TIFF, and guides the reader through use of the libtiff library. This article provides examples on how to use libtiff for your grayscale and color imaging needs. Did you read the previous article?

This article is a follow up to my previous article on black and white graphics programming with libtiff. This article covers grayscale and color imaging, but it assumes that you have read and understood the code from the black and white article. It might be helpful to refer to that article before going too far here.

With this article, I will discuss some of the theory required to understand how the image data is stored for color and grayscale. This theory applies to all imaging formats. We'll then discuss some of the specifics of using libtiff.

Terminology We need to get some terminology out of the way before we can discuss much. Images are made up of pixels. In black and white imaging, the pixel has one of two values -- 0 or 1. This can be represented in a single bit. For grayscale and color images however, the pixel needs to be able to store a much greater range of values -- if a pixel was to have 255 levels of gray, then we would need 8 bits to store that pixel. Each of these values is called a sample. TIFF expresses the size of the value in a tag called TIFFTAG_BITSPERSAMPLE. This will be 1 for black and white, and some larger number for grayscale.

For color images, we need to store even more information. For each pixel we will need to store a red, green, and blue value. Each of these values are stored in a separate 'sample'. Therefore, we will need to define TIFFTAG_SAMPLESPERPIXEL -- this will be 1 for black and white or grayscale, but will normally be 3 for color images. We also need to define the size of each sample, so you'll still need to set a value for TIFFTAG_BITSPERSAMPLE.

Theory of color and grayscale storage The first thing that we need to understand to be able to support color and grayscale images is the format of the image data within memory. There are two main representations for color and grayscale images. I'll explain these by describing grayscale, and then extend it to color.

Direct storage of pixel data If you think back to the way pixel information was stored in the black and white images from the previous article, the information was just in the strips. You can also do this with grayscale and color images. This representation of image data is quite inefficient, because for the scenario when the image has a solid background (for example), there are many pixels with the same value. If the pixel data is stored in the strips, then this value will waste a large amount of space.

Thankfully, there is a more efficient way to store image data. Imagine a simple four color 24 bit per pixel image. If we build a lookup table of the four color values (the 24 bit values which represent those colors), then we just need to store the relevant entry number of the color in the image strip itself. This can be done in only two bits, instead of the full 24. The maths looks something like this:

A 24 bit color image which is 1,000 by 1,000 pixels will take 24 million bits to store. The same image, if it was a four color image, would take 4,000,000 bits for the strip data, and 98 bits for the color table. Neither of these numbers includes header and footer information for the file format, and the numbers are for uncompressed bitmaps. The advantages of the lookup table should be obvious. There is a name for this style of lookup table, it is called a palette -- probably because of those things painters carry around.

This concept works for grayscale images as well. The only difference is that the colors in the palette are not just shades of gray.

Compression algorithms in libtiff There are several compression algorithms available within libtiff. How do you select which one is right for your imaging needs?

Libtiff compression algorithms Compression algorithm Well suited for TIFFTAG CCITT Group 4 Fax and Group 3 Fax This entry is here for completeness. If your coding for black and white images, then you're probably using the CCITT fax compression methods. These compression algorithms don't support color. COMPRESSION_CCITTFAX3, COMPRESSION_CCITTFAX4 JPEG JPEG compression is great for large images such as photos. However, the compression is normally lossy (in that image data is thrown away as part of the compression process). This makes JPEG very poor for compressing text which needs to remain readable. The other thing to bear in mind is that the loss is accumulative -- see the sidebar for more information about this. COMPRESSION_JPEG LZW This is the compression algorithm used in GIF images. Because of the licensing requirements from Unisys, support for this compression codec has been removed from libtiff. There are patches available if you would like to add it back, but the majority of programs your code will integrate with no linger support LZW. COMPRESSION_LZW Deflate This is the gzip compression algorithm, which is also used for PNG. It is the compression algorithm I would recommend for color images. COMPRESSION_DEFLATE ]]> Accumulating loss?

Why does the loss in lossy compression algorithms such as JPEG accumulate? Imagine that you compress an image using JPEG. You then need to add say a barcode to the image, so you uncompress the image, add the barcode, and recompress it. When the recompression occurs, then a new set of loss is introduced. You can imagine that if you do this enough, then you'll end up with an image which is a big blob.

Whether this is a problem depends on the type of your data. To test how much of a problem this is, I wrote a simple libtiff program which repeatedly uncompresses and recompresses an image. What I found was that with pictures, the data is much more resilient to repeated compression.

Figure 1. The picture before we compressed it IBM logo
Figure 2. The sample text before we compressed it Some sample text

The code I used had a 'quality' rating of 25% on the JPEG compression, which is a way of tweaking the loss of the compression algorithm. The lower the quality, the higher the compression ratio. The default is 75%.

Figure 3. The picture after it has been recompressed 200 times The IBM logo, having been recompressed 200 times
Figure 4. The text after it has been recompressed 200 times A picture of some text, having been compressed 200 times

Writing a color image It time to show you how to write a color image to disc. Remember that this is a simple example, which can be elaborated on greatly.

Writing a color image #include <tiffio.h> #include <stdio.h> int main(int argc, char *argv[]){ TIFF *output; uint32 width, height; char *raster; // Open the output image if((output = TIFFOpen("output.tif", "w")) == NULL){ fprintf(stderr, "Could not open outgoing image\n"); exit(42); } // We need to know the width and the height before we can malloc width = 42; height = 42; if((raster = (char *) malloc(sizeof(char) * width * height * 3)) == NULL){ fprintf(stderr, "Could not allocate enough memory\n"); exit(42); } // Magical stuff for creating the image // ... // Write the tiff tags to the file TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(output, TIFFTAG_IMAGELENGTH, height); TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, 3); // Actually write the image if(TIFFWriteEncodedStrip(output, 0, raster, width * height * 3) == 0){ fprintf(stderr, "Could not write image\n"); exit(42); } TIFFClose(output); }

You can see from this code some of the things that we have discussed in theory. The image has three samples per pixel, each of eight bits. This means that the image is a 24 bit RGB image. If this was a black and white or grayscale image, then this value would be one. The tag PHOTOMETRIC_RGB says that the image data is stored within the strips themselves (as opposed to being paletted) -- more about this in a second.

Other values for samples per pixel?

In this example, we have three samples per pixel. If this was a black and white image, or a grayscale image, then we would have one sample per pixel. There are other valid values for here as well -- for instance, sometimes people will store a transparency value for a given pixel, which is called an alpha channel. This would result in having four samples per pixel. It is possible to have an arbitary number of samples per pixel, which is good if you need to pack in extra information about a pixel. Note that doing this can break image viewers which make silly assumptions -- I once had to write code for a former employer to strip out alpha channels and the like so that their PDF generator wouldn't crash.

The other interesting thing to discuss here is the planar configuration of the image. Here we have specifed PLANARCONFIG_CONTIG, which means that the red green and blue information for a given pixel is grouped together in the strips of image data. The other option is PLANARCONFIG_SEPARATE, where the red samples for the image are stored together, then the blue samples, and finally the green samples.

Writing a paletted color image So how do we write a paletted version of this image? Well, libtiff makes this really easy -- all we need to do is change the value of TIFFTAG_PHOTOMETRIC to PHOTOMETRIC_PALETTE. It's not really worth including an example in this article, given it's a one word change.

Reading a color image Now all we have to do is work out how to read other people's color and grayscale images reliably, and we're home free. Initially I was very tempted to not tell you about the TIFFReadRGBAStrip() and TIFFReadRGBBSTile() calls, which hide some of the potential ugliness from the caller. These functions have some limitations I'm not astoundingly happy with. To quote the TIFFReadRGBAStrip() man page:

   TIFFReadRGBAStrip reads a single strip of a strip-based image into memory,
   storing  the  result  in  the  user supplied RGBA raster. The raster is assumed to be an array of
   width   times   rowsperstrip   32-bit   entries,   where   width   is  the  width  of  the  image
   (TIFFTAG_IMAGEWIDTH) and rowsperstrip is the maximum lines in a strip (TIFFTAG_ROWSPERSTRIP).

   The  strip  value  should  be  the  strip  number  (strip  zero  is the first) as returned by the
   TIFFComputeStrip function, but always for sample 0.

   Note  that  the  raster  is  assume  to  be  organized  such  that the pixel at location (x,y) is
   raster[y*width+x];  with  the  raster  origin in the lower-left hand corner of the strip. That is
   bottom  to  top  organization. When reading a partial last strip in the file the last line of the
   image will begin at the beginning of the buffer.

   Raster  pixels  are  8-bit packed red, green, blue, alpha samples. The macros TIFFGetR, TIFFGetG,
   TIFFGetB,  and  TIFFGetA  should  be used to access individual samples. Images without Associated
   Alpha matting information have a constant Alpha of 1.0 (255).

   See  the TIFFRGBAImage(3T) page for more details on how various image types are converted to RGBA
   values.

NOTES

   Samples must be either 1, 2, 4, 8, or 16 bits. Colorimetric samples/pixel must be either 1, 3, or
   4 (i.e. SamplesPerPixel minus ExtraSamples).

   Palette  image  colormaps that appear to be incorrectly written as 8-bit values are automatically
   scaled to 16-bits.

   TIFFReadRGBAStrip  is  just  a wrapper around the more general TIFFRGBAImage(3T) facilities. It's
   main  advantage  over  the similar TIFFReadRGBAImage() function is that for large images a single
   buffer  capable  of  holding  the  whole  image doesn't need to be allocated, only enough for one
   strip. The TIFFReadRGBATile() function does a similar operation for tiled images.

There are a couple of odd things about this function -- it defines (0, 0) to be in a different location from all the other code that we have been writing. In all the previous code we have written, the (0, 0) point has been in the top left of the image. This call defines (0, 0) to be in the bottom left. The other limitation to be aware of is that not all valid values for bits per sample are supported. If you find these quirks unacceptable, then remember that you can still use TIFFReadEncodedStrip() in the same manner that we did for the black and white images in the previous article...

Reading a color image with TIFFReadEncodedStrip() #include <stdio.h> #include <tiffio.h> int main(int argc, char *argv[]){ TIFF *image; uint32 width, height, *raster; tsize_t stripSize; unsigned long imagesize, c, d, e; // Open the TIFF image if((image = TIFFOpen(argv[1], "r")) == NULL){ fprintf(stderr, "Could not open incoming image\n"); exit(42); } // Find the width and height of the image TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); imagesize = height * width + 1; if((raster = (uint32 *) malloc(sizeof(uint32) * imagesize)) == NULL){ fprintf(stderr, "Could not allocate enough memory\n"); exit(42); } // Read the image into the memory buffer if(TIFFReadRGBAStrip(image, 0, raster) == 0){ fprintf(stderr, "Could not read image\n"); exit(42); } // Here I fix the reversal of the image (vertically) and show you how to get the color values from each pixel d = 0; for(e = height - 1; e != -1; e--){ for(c = 0; c < width; c++){ // Red = TIFFGetR(raster[e * width + c]); // Green = TIFFGetG(raster[e * width + c]); // Blue = TIFFGetB(raster[e * width + c]); } } free(raster); TIFFClose(image); }

Advanced topics Well, now that we understand how to read and write basically any image format we can think of, there are two other things we should quickly discuss.

Storing TIFF data in places other than files All of these examples that I have included to this point have read and written with files. There are many scenarios when you wouldn't want to store your image data in a file, but would still want to use libtiff and tiff. For example, you might have customer pictures for id cards, and these would be stored in a database.

The example which I am most familiar with is PDF documents. In PDF files, you can embed images into the document. These images can be in a subset of TIFF if desired, and TIFF is quite clearly the choice for black and white images.

An expanded example

If you need more information about hooking the file input and output functions within libtiff than this article allows, then have a look at the images.c file in Panda, my PDF library. The web pages for Panda can be found at http://www.stillhq.com/cgi-bin/getpage?area=panda&page=index.htm.

libtiff allows you to replace the file input and output functions in the library with your own. This is done with the TIFFClientOpen() method. Here's an example (please note this code wont compile, and is just to describe the main concepts:

Using TIFFClientOpen #include <tiffio.h> #include <pthread.h> // Function prototypes static tsize_t libtiffDummyReadProc (thandle_t fd, tdata_t buf, tsize_t size); static tsize_t libtiffDummyWriteProc (thandle_t fd, tdata_t buf, tsize_t size); static toff_t libtiffDummySeekProc (thandle_t fd, toff_t off, int i); static int libtiffDummyCloseProc (thandle_t fd); // We need globals because of the callbacks (they don't allow us to pass state) char *globalImageBuffer; unsigned long globalImageBufferOffset; // This mutex keeps the globals safe by ensuring only one user at a time pthread_mutex_t convMutex = PTHREAD_MUTEX_INITIALIZER; ... TIFF *conv; // Lock the mutex pthread_mutex_lock (&convMutex); globalImageBuffer = NULL; globalImageBufferOffset = 0; // Open the dummy document (which actually only exists in memory) conv = TIFFClientOpen ("dummy", "w", (thandle_t) - 1, libtiffDummyReadProc, libtiffDummyWriteProc, libtiffDummySeekProc, libtiffDummyCloseProc, NULL, NULL, NULL); // Setup the image as if it was any other tiff image here, including setting tags ... // Actually do the client open TIFFWriteEncodedStrip (conv, 0, stripBuffer, imageOffset); // Unlock the mutex pthread_mutex_unlock (&convMutex); ... /////////////////// Callbacks to libtiff ... static tsize_t libtiffDummyReadProc (thandle_t fd, tdata_t buf, tsize_t size) { // Return the amount of data read, which we will always set as 0 because // we only need to be able to write to these in-memory tiffs return 0; } static tsize_t libtiffDummyWriteProc (thandle_t fd, tdata_t buf, tsize_t size) { // libtiff will try to write an 8 byte header into the tiff file. We need // to ignore this because PDF does not use it... if ((size == 8) && (((char *) buf)[0] == 'I') && (((char *) buf)[1] == 'I') && (((char *) buf)[2] == 42)) { // Skip the header -- little endian } else if ((size == 8) && (((char *) buf)[0] == 'M') && (((char *) buf)[1] == 'M') && (((char *) buf)[2] == 42)) { // Skip the header -- big endian } else { // Have we done anything yet? if (globalImageBuffer == NULL) if((globalImageBuffer = (char *) malloc (size * sizeof (char))) == NULL) { fprintf(stderr, "Memory allocation error\n"); exit(42); } // Otherwise, we need to grow the memory buffer else { if ((globalImageBuffer = (char *) realloc (globalImageBuffer, (size * sizeof (char)) + globalImageBufferOffset)) == NULL) fprintf(stderr, "Could not grow the tiff conversion memory buffer\n"); exit(42); } // Now move the image data into the buffer memcpy (globalImageBuffer + globalImageBufferOffset, buf, size); globalImageBufferOffset += size; } return (size); } static toff_t libtiffDummySeekProc (thandle_t fd, toff_t off, int i) { // This appears to return the location that it went to return off; } static int libtiffDummyCloseProc (thandle_t fd) { // Return a zero meaning all is well return 0; }

Converting color to grayscale How do you convert color images to grayscale? Well, my instant answer when I first had to do this was to just average the red, green and blue values. That answer is wrong. The reality is that the human eye is much better at seeing some colors than others. To get an accurate grayscale representation, you need to apply different coefficients to the color samples. Appropraite coefficients are 0.299 for red, 0.587 for green and 0.114 for blue.

Conclusion In this article we've discussed how to program with libtiff for grayscale and color images. I've shown you some sample code which should help to get you started. You should now know enough to have a great time coding with libtiff. Thanks for taking the time to read this article.

Source code used in this article