From 2c053c325a24515122ff348b60d6514151f1d299 Mon Sep 17 00:00:00 2001 From: gitlost Date: Fri, 19 Mar 2021 13:09:21 +0000 Subject: [PATCH] tif.c: Use palette/bilevel/LZW to reduce file size, alpha/CMYK support --- backend/tests/data/print/tif/code128_aim.tif | Bin 47580 -> 470 bytes .../tests/data/print/tif/dotcode_aim_fig7.tif | Bin 39946 -> 626 bytes .../tests/data/print/tif/maxicode_fig_2.tif | Bin 270476 -> 3944 bytes backend/tests/data/print/tif/qr_v1_m.tif | Bin 5496 -> 322 bytes backend/tests/data/print/tif/ultracode_a.tif | Bin 2232 -> 422 bytes backend/tests/data/tif/aztec_v32_fg.tif | Bin 0 -> 6392 bytes backend/tests/data/tif/code128_bgalpha.tif | Bin 0 -> 3772 bytes backend/tests/data/tif/code128_cmyk.tif | Bin 0 -> 3962 bytes .../tests/data/tif/code128_cmyk_fgbgalpha.tif | Bin 0 -> 4850 bytes backend/tests/data/tif/code128_fgalpha.tif | Bin 0 -> 3772 bytes backend/tests/data/tif/code128_fgbg.tif | Bin 0 -> 952 bytes backend/tests/data/tif/code128_fgbgalpha.tif | Bin 0 -> 3772 bytes backend/tests/data/tif/daft_scale0.5.tif | Bin 0 -> 158 bytes .../tests/data/tif/hanxin_v84_l4_scale2.tif | Bin 0 -> 6308 bytes backend/tests/data/tif/ultra_bgalpha.tif | Bin 0 -> 702 bytes backend/tests/data/tif/ultra_bgalpha_nofg.tif | Bin 0 -> 702 bytes backend/tests/data/tif/ultra_fgalpha.tif | Bin 0 -> 790 bytes backend/tests/data/tif/ultra_fgalpha_nobg.tif | Bin 0 -> 734 bytes backend/tests/data/tif/ultra_fgbgalpha.tif | Bin 0 -> 788 bytes backend/tests/data/tif/ultra_odd.tif | Bin 0 -> 350 bytes backend/tests/test_tif.c | 158 ++++- backend/tif.c | 599 +++++++++++++----- backend/tif.h | 39 +- backend/tif_lzw.h | 373 +++++++++++ backend/zint.h | 1 + docs/manual.txt | 3 + frontend_qt/frontend_qt.pro | 1 + frontend_qt/mainWindow.ui | 4 +- win32/libzint.vcxproj | 1 + win32/vs2008/libzint.vcproj | 4 + win32/vs2015/libzint.vcxproj | 1 + win32/vs2015/vsx/libzintMD.vcxproj | 1 + win32/vs2019/libzint.vcxproj | 1 + 33 files changed, 983 insertions(+), 203 deletions(-) create mode 100644 backend/tests/data/tif/aztec_v32_fg.tif create mode 100644 backend/tests/data/tif/code128_bgalpha.tif create mode 100644 backend/tests/data/tif/code128_cmyk.tif create mode 100644 backend/tests/data/tif/code128_cmyk_fgbgalpha.tif create mode 100644 backend/tests/data/tif/code128_fgalpha.tif create mode 100644 backend/tests/data/tif/code128_fgbg.tif create mode 100644 backend/tests/data/tif/code128_fgbgalpha.tif create mode 100644 backend/tests/data/tif/daft_scale0.5.tif create mode 100644 backend/tests/data/tif/hanxin_v84_l4_scale2.tif create mode 100644 backend/tests/data/tif/ultra_bgalpha.tif create mode 100644 backend/tests/data/tif/ultra_bgalpha_nofg.tif create mode 100644 backend/tests/data/tif/ultra_fgalpha.tif create mode 100644 backend/tests/data/tif/ultra_fgalpha_nobg.tif create mode 100644 backend/tests/data/tif/ultra_fgbgalpha.tif create mode 100644 backend/tests/data/tif/ultra_odd.tif create mode 100644 backend/tif_lzw.h diff --git a/backend/tests/data/print/tif/code128_aim.tif b/backend/tests/data/print/tif/code128_aim.tif index 70c67f0c1e4f0d680a160ca82fb9c11e8e1ff9a4..5cc663a50dcd6c3d249348bbf861b5462c9ab534 100644 GIT binary patch literal 470 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 diff --git a/backend/tests/data/print/tif/dotcode_aim_fig7.tif b/backend/tests/data/print/tif/dotcode_aim_fig7.tif index a668466ecb85a1e60f07a24b61b319818eb531e3..f518d1f96bdb987d92eb5b6a9054730a3487f2b8 100644 GIT binary patch literal 626 zcmebD)M9wT$iUFRpb%i8BF4hfD4;N5g#(iW1Aha9K8K8-qEMHM`wIr?N9?i;ZchYv zid3;G_qi`l|HdHulX*IW>SW23Y4%!EP6P;N+B^yr>~>gmh2sR1G*{!{hgUL8&E_z0 z1ixHU27;?cjqcRVi-ld5wWeA9u)JVl|tjptpVX zo@ZeP8c!P--K@Fx(`xT2y&K(c{&5y`UwApe+RtxldS`H!f`oxQBkQX41q;5jMlde9 z_%hq7HgumR3&VBiUq9p)hi|*}I{ViNy>17F`>w^2bB@~G^jsdZBHBae1Ea#S&$|RN z=j>xOd~q&)%eyJFcu(~N@AxoJpZhH9im#vl@W=3-+|!t6UN4(}iZ$Wp>jk@I&wmg5 zWq(5Hz=Iw7#pfQ`@@s2tbIjOv@53gJ%Y1vBGVf?j(a#ZLd9}E!L76T z)+6KG=2NG1i`Im*>lr$$3LbiSWT$|7z!j^5%i37>9Xowt&4Jz{7phgoTzz((7q`_A zd9~Ryzh*|0?Z-Q;_9sP{-(9!wdZe}Pg8p1~my0FYuC_t^ChtA>tl;2cU|?is07f!H zGY~UE*{MJ_GnCB=WV1opKqiAABMVqP2aqiWWrNgVz>42I_=A)-P;f*=8+qCnh%p4@?!o|={li3>#G7?hM$oPe5RPyl|Jmz6c^ zcs%>>tY`M^qUd?Y{{4UUESHzB!^L$7|F);e4Fuq75G}F{#J52$A@QeZGh9eCZ>b#)vlCTq!_&8`lz^GPs^Xw0dVfi}?1a)wi)_d)WZ; z?e#Ka*t6yh=8{{3KrGye$uv>_5J?47^sh?IPN_ z+2k(T0Xt3-x{l)n4_!%F*)ZF}@Zm@Qhdrs^#ychR^nva75%TTp2^J^CWd7Hv{fY4hW@ zJ^CWdMlF?%ceTJtkG=>qqFvxRHVfkhdb~%38POV7T3SX({3(^Y)N^2pix?1Xkx@}` zLKR<&IxJs|FeBQklQs*cOpP!jS_KJAiB$0r>|9TdFeBP}6UELVTWwRYKf;V?L2O;# zESQ3gFe6$8X_i#NHcQXiO%P^8TYE0*Pk0Ns%xi%#BiebV*t#9t29R$L(IR{H@Y7p(vWJ2KO zI{~#+LZg*RhI&LhG?@^1`A$IHB$YPc^$mFWB5SO~Ol|pt5Ef~lN$2>w zz?fdX$Y@oWt2S4r_VQJbvZ;E^V&{06r9uk4d|PG~cY**LwO+nPJh7}QbJgbJIPuWS zS3%0AYBMMOvpjPZc=;my3ow%fLO5CL|j3;;v{BUoWjPPBx`8i`jUX?Ti#4zFyke z^NMpJrbaE|>!mf0CYEKHvjt*X{1EZ=(jrq^n3EdBu1JgcdTEOWOp1-nRF(*rc}0A^ zw8&-F9(@sJT`OkeVWs`YwmteH z%oeR!Q}q^+=;Siig>qAlhtmrC_bT;#|recnZ<-KBe(0eUYIMZRzrP{aSsKx%kN07|~{%D+Md| zrO}kZ^%SDjJL}nF^VPSpWwRRy55nJY7IwG)k9Vgx@h5uU9pd*CpHO^Czdx=+I6a*2 zHRp%;gyM(0vv5woKdI*N;e4;Tp!0q0Bl>%CsQFDbPj~lj&i_#S>=2)P4dFTK|BCe| pdANW07sB@!A$)if!pnCd{Q4Nem#YxI(OLTUnXKQEa!+vk`yW>RKnwr? diff --git a/backend/tests/data/print/tif/maxicode_fig_2.tif b/backend/tests/data/print/tif/maxicode_fig_2.tif index 56603e78ee0fb9230e92c07b6488a4116b7414af..d18f02eeb23e139f266f416e4a0c087af4e126fb 100644 GIT binary patch literal 3944 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 literal 270476 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 GMgsuieo%M- literal 5496 zcmchbO-ch{5JYDZm8=B8D5wXJoWxwil}iui((|cbrYG>AsHW#9Mi|TL>Q_BkdORMw z@B41T=XdzTLTEblCqT<`#8in53hA?9#6|Ig_+J zS?SVD&Yaqw^Yf|e;uf!^A6lI}&*@t2dWn*GCvQ++9Y59${WPx2SnT_&QZbx16I)N7H05UEWQZ zSEf#RIhowmEl#;bUCI1Ud;JoZ%zeH^Br?s6$baZNqxRAr}|#JFrSi>>&vz4g>>?F z;Z@wK_)Ey_a-7`fG&G;?e$CV`;cjTQa7thK+|?-^a>yqk_esl>WU`k8^>Ze7^W^2) z*~|NL-z9k`3F<3B9o=#cyMp7MBxr`y3RCmSq{BS@(45X|=a$oXm)ly)zeM|O_tRZ< z{rSXxJLp6EyNBL1y=~t6zU#K5f7-bj^`_~&J~+Fk_oIK>c^Lf@^KsN)?Z2c?{q@lG b(U{Mp{%raM{8#YXdbb;X-kLhKpMU=WR>|Sb diff --git a/backend/tests/data/print/tif/ultracode_a.tif b/backend/tests/data/print/tif/ultracode_a.tif index c94499366cb988760d28979534164b37259cf3a5..554d06f92ad488368575bccc4383b52095916a93 100644 GIT binary patch literal 422 zcmebD)M8k`z`)QT`yjwVMU0n?LDcU7v%xu;P_34PfEh7n@`8;=8kjA5OwOeB9D3X+ z@uf*yl;eo1!AcvWaP7uJ3)K>OmPs47PEDJfILEJwfurZ~Mb0mJ&Cb)DUOI5a2+j0g zcI1f&m(4X*-B}k_U6QzQu9)yMY`61Rg*PV#4VE|3RYv e!2rSnkq7{ifbbwJ7!RfbtP!pTWD-mULIVH~vt>^J literal 2232 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 XxN~QOdVJK|;1JlgYcwE6atHtbYFHVw literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/code128_cmyk.tif b/backend/tests/data/tif/code128_cmyk.tif new file mode 100644 index 0000000000000000000000000000000000000000..ff83c6e77199ece19055d5f2a091207eebb83c16 GIT binary patch literal 3962 zcmebD)MA*!$H36Qz~bV-!^OdnV8H&NBg9CYv-QA(jT$9kn&Qnzl>{@+l&Q-#yFUqx zxRb;!J?VtXCCQXU(s~`ImIYb1YzjATKATz`dF5QL!aVPXn>%IRwel}MsZqk^D>c!- zFEDc|=bKBj?RrCBh3@dFj4Te96>WE( zekA(ib?AZ{$8X8L|W`x_sDE$>pIhlPY&? zf{Zi&$-ph1DjSM&YIz*j&+*oB4Jv8ZI4Sh|qR#fuGNKw@n^=~;cbjHL^PH z#!F6HdI#=VuY6v(rQ7z*#UtUZP z7ldu~ElynadGB?|R3+Kdb<&ni|IP}Aa_V_Z?e+Eu5qTT$aP9Jy+dgL|CEty5|C;L@ z9%LHw+AgAWPk3_Z)>M1nlVz#3Y1c#lmYZHK3!R*Gq4eoygW$`&3lm(f^{y?xHDPOT z^2Orbtuc4Q_BQ(lU0HfE@@kpR$H2SgKL0cQ%2~O~?}e}JG>e_iCz^ZD!pAZ=c=|cP z#NZvN&#M!*xju9b+rh@){rHEOqURHHHqZ0~Q#)JtN8xhDfl+0(r>mca-%IZCjb!uB zPbfLMapu!qY_jv?f5}PbJt}o8tjo|)Vj4}tqe*x)36GY-qowd@DLmSc7;Q+5HY7&d z!UNS7p4`h_dQCj{YI*ec+NTxwrUTo!aobxz*4__)`@TNj{2yz>gXz!Mn-g}h3AR3r z$m4HMw5U_3%QT;PE-iTH zmRHp_a{|<_Nd6V;bewvjL1dOG-(0U{S2Vu->J3{Sv?}z~)mcxI_WCUG(!RP|HtTHc zrl_26(XQ*R=I#huBfNU>?mr1FDw^s2&73;E;jgG*GY)XmKD11A_=R1H(#Q28P2xF=RXy$o~w~=K;hZdto#H DW{w!2 literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/code128_cmyk_fgbgalpha.tif b/backend/tests/data/tif/code128_cmyk_fgbgalpha.tif new file mode 100644 index 0000000000000000000000000000000000000000..632e355ddaaf16db40bbedc1c978615223bb7523 GIT binary patch literal 4850 zcmebD)MEH2$iUFRz~bV-ZN$pbY#_n>;RNUDXMdR?XV&z5eQ3F=^GLs{xzu=$dkup1N7M;BHp9 z_1S&jb2dc07rXtnXs+$PySf!Rwx1?89DTS+V)Zs-_4|jDjCbRTsrJh#+RKr&yJg>U4L6FbvNyCV&~oWE2D3zmAN)w{a{>uj$b^t^#w zubQ);|M7!2d-PwgyJh3|_|@Ot0n&@UI0!^v`gtIC_rIG5{A&1F4xCSZb7Sv^9$^kU z{XK$w2PW`1^SDfu(Pwo%ul<+HMX)B2&9>0{GuN>Km#DW#3;smP92elpmpf*7$CTgk zlgdP~lN+aGi+WxZsTcMLI@7Fhf@T&-sgAxXmtqx%1len9yEPCqJRPlFp}$&zf3#hm-~y`jsqIR=+CLnycmg)z>}r znrLmgpTEf-^}q6IzDtFvOmOpj;oy>>J+|Mo`Li@~?db0e$b%XOE=Cz!FGtc=?}cW-&HMDFG~ z-x+f9-Em*GzD>PzqqVX%Y-*WfS4_k|afip({hWKBhWOeh#Y>9LoP6I>E;#0%Wb6C- z+hKf_^HQdW-khB*Y5K9}$`0MNi&B56#dg2Eti&{$jz`n+XgVG(k4MYn(eik-T`}6O z7;RUKwvR{K$D{4z(SF|G>*p0bneokVa_~*N&?!%+AM>92^rl<#jMSfb*)yNroR&ZL zdE~py`RSJbS{J;SHVdg^=kQ=dMU0j(N1OA*jT|Lzx}rU<%7GS7yllmLk3TlN$uh}Z zX~M}=p-i87q59K(Qa4+sTnjg!;j1pJx#d~4&D?X#uSovoYII%__%b9bRcx-yilEG` zQn7YR!&Y6@Dy_Pjv^{cNM2?u%-)Vc(*WJnq-NwvNHRgqwHEF0-Y8-H&Fpvou@r+FZ~DU3Cml*Fn#L1Xbhq4qM`_H?s%FE~Peg2`!=HC4D^>^3bEZF-`?)vqY-@n%Gx9`shKlQ>+ z|M9cG2m0Tz{B^jX!`5v7#)g^IQ6NT@=GcG3CLyz(hGzb7?`2rAU+!sTab~3fgLEe3aCaDNn8vl z4l)xsti&J=RdWoeMv9RYEdB_{mWHxl0ofW*y-Yy$K~OeGKL~IjK?a5kKqWJP&Pd<@ i>f&Z#_yF|4N&yCj6F_lvyb~xE0yM@0XbQ+Q7!3dr#KbKC literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/code128_fgalpha.tif b/backend/tests/data/tif/code128_fgalpha.tif new file mode 100644 index 0000000000000000000000000000000000000000..e2a6b2327c5af95a990b5d206096dfd7453af229 GIT binary patch literal 3772 zcmebD)M9wX&cM*XApb#uD~+4o=fHvq89scn+)alTezcgPq|MXmmUy9KOOU#3uj?bj z9Vtz=0+SA>7~UU$L8p_6072rS)=;z>s89g88fz=da7HJQ>J%x()oMYJLX*d zZ63KM`EkV9Huq*PxG6&8-50V^s~#UR9avblybfXW->ecTJt0^S{PwUo$rOA06=3 z=f9&*>DO}Ct6QIPCR{B!%g%Z}m^IVxnz5~Kly8{q?6}LKt<%HY&Grh1M3+u!&+zy* z^>|i{xoLjkZR5SClg?kW^>)4?I`?5|?6q2(?=}^@Uu&Ybzx~X0&n&dlIpVr%xy98V zCiCk;L!KUNyYf9{uleH{Tj#dkzHxMU)5A^Me2X4!U30rB#jNyYY-EJZ^On<}=I%^+ zY^nNs#?u?~a_gQ*h;dJT_)E5a-m%D~wzdyv-YaHI+3`+xYD`${#g43sD{tpzZT8d5 zO}@D=a$)Rmxy9AFQp*}EUv68sbZwfH+VZ8E92}!*el*RGruorwp4R0&o9!i)UZs;l zHd9qjPKueUc1oybsm7^EbJl8|7TU8_=k%mId-cu;{W)rIX0ps#qf-WVE*hVm9CPQy zqR%x?&CX4pCAQG-@|v$Ur#G(oX?sEV&useu6J1tk$KEBJ&KIY++;vgD6xSq(=-W4l+{qF|vZi*8thlQ1%ue zTLVe21CR|ebPrHG2r3RT3j}~d41a(Yd;mJ+3y=okuRuu;pg2ekjQ;lz$QcDAHU#e6 U8L?g;^*AsDcI_GshLIcs03HMw%m4rY literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/code128_fgbg.tif b/backend/tests/data/tif/code128_fgbg.tif new file mode 100644 index 0000000000000000000000000000000000000000..77c66a684c6153429eb68ebb67174c60994d5f42 GIT binary patch literal 952 zcmebD)MD7g#K6$Nz@#W4z{JhgbWq`fg^QLjUz^jz2_8Lu;v6l9lLT&vIN6Hy9a-?< z#hEUB@s1NoK^$wE_%(XnRRv#M*(549{bXv;k0qDF`6v257J7LnFW9}?JEg?(NnX0) z{PP(`l`XR>UHdPnm}ortwccaawdF!ys&c#I8qcmOo~>)OHDYVntI4ZP?bc>)^jyEu|W$Pu|pOyc)v1VDj?!+6PcJJ-i)4%!RQ|h-re*Krf zJlWqr+vWeR)rXJ$x8uLPad@V{bz(39CKC+o!e)?qs-zg5Pam{fr2?)-?sJ5 zzIJlIz~e-Ihl|Yj`3_C^!zzBXuqRsb(8o3IB1a5c%3dGec=@pO;Uex_X_r3cE5BWZ zSTdE5f3WF!=uzY&&E&Q5$$TxFPbI|~-bSB;4ZJr^+4k0FW66F!yU)UXAAAju95?ga zY;xVick`C#Hh!B!zFYVkf4MKbW^wSY}J=NeoWukkVA`q$}TKi$#5=@Tw+8d@h}xb$#2Oi7BDqN_Qqlmu<~2xNR=8*fBcXcDat9 zY3RYy*z3NPB{A3MUKfnJ-ut@jhI#6eNy-v@tc?$5=~28(UlJq;4eOxqvN_-5bs#8OU%VL_#sZ)?iVIPqyuZ}=t7c<^&x=IrMZMNB*l z42;YSj0_A62|&yUWtRZiOi(rpkj)HbvjW*{P&PA=Ey&0M*2@88i$U2Sz2Z>zDqvoa zVq^uY@c?R&hOz^IYz?S6KqU+gK(+ypjsO`71Rg*PaubYx_fAj{B#sN*y{n{zOAaJ{ K=8Um1K6wBw!cas2 literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/code128_fgbgalpha.tif b/backend/tests/data/tif/code128_fgbgalpha.tif new file mode 100644 index 0000000000000000000000000000000000000000..194e8a43a8c1db59b767516048ff394c22f2b49a GIT binary patch literal 3772 zcmebD)M9wX&cM*XAUQ#SD~+4o=fHvq89scn+)alTezcgPq|MXmmUy9KOOU#3uj?bj z9Vtz=0+SA>7}R${}Cf66aIEn_tdJxP8-jz z+0Gq0X=3b-d+)#B-n*LFV{`OdiB)mRtWo{<^(tlLj2T-_J=HDADbqVT>HNLy9doY! zHjiAB@nPqg*2n&<&S$UNKIiT0DQXK_Ua3_&$}G_WzIS?>B>#d zo_vq)tq7mppy^*O&Xc z-}fK+yz~6*x(^O{yFYxjUdw#z-}e6IyoWaDPyhR|nLkD4%z?Mod)W>ZRGYls@j->* znzJGIg*W>rGSBBa8X)5KXy5uJx-8BDA;J=eKgM|S9SPV|&F`Xr`>lkl0FR`i-Nz@< zOoxn^SE_hUyj`s9Sx_9U<#DmbS8X@n?=Q!X8a-}S^2~p-Rq@EDmUyAlf+dyOUK^Gy zl|Q}ViLIFv@12FhXEvRAYUDln$YKYpz{}1`Ck>B0G;y86lPl#MQmZUu{lR3aVc_Js zI$w4N?n(DNFlDW*YtYB3=2ij0v8o1Vud2*-I&UKLGw|}KyQa?0`CntTuNj;Cj}G|i z^WV{@^lQ26)vZrC6Rwt=WoJDf%$jL;&DhpA$~R1QcHCvr*6CsHW_yK0qD!Z=XLx*@ zdORz}+%&)Nw(;K6N$0QGdOP0`o%^sf_FApYcbf{{uQk!z-+t!0XBOJ&9C2N>+~VpF zllgU_Ax{ssUHP7}*ZlE}t#ey%-#EIw>EWhrzD19=uDRWmVpjSxHZsEIdCTcfb9bgZ zwp4vRTPwR4?&GwQ?uhK~& zo2e=%C&kQFJ0(=JRO8g7Icv2}3+>seb9&O9y?SSa{v0(pGg;=W(J6yF7md$Oj=6JU z(dU|{X6Gi)5?knZdCgaw(;L_Pw7nqwXSRKSi7u6LZ5Br;dk z``nbZhQ60Bi<T# zt%0Q10mud!x(6s81QiFF1p+`JhCe_HJ^&r^1xSPNSD>T^P#mNNM*sT<QB nA+g1wY<8fy6eBBGO&^dg4P{RQvNfRQFag;h-~q%Sdto#H%QOV? literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/hanxin_v84_l4_scale2.tif b/backend/tests/data/tif/hanxin_v84_l4_scale2.tif new file mode 100644 index 0000000000000000000000000000000000000000..c908cb18b5db858d022b3b76e108f8a396a2c616 GIT binary patch literal 6308 zcma)gXH=72lx`3ZQ9}=ifQW$fnuK1YL|Q^i0!S4h6eH3>nuVeuU?>SeDJn%!ih%Sg zy@nQg6=~8tC`BgU%r`Ul$GvOacdh;I=j^ji`LWmY?0xj~L;<}V0KjwgA4Y)S%NNg| zXxiWTEq?v#HUPl8BNXjf*$j82G`Cn zjB($-awVbNcJnRwh|_s=@8T`#RKc$@ANrP|@-}LDj2VgFSISgBjk;A#J+?OydED*W z@WbPYRi`$;bJK#?6F*BDEkfTf_unbC7v%-tCHn5w<(+#o&d`nWdvdjh6^v~hE7upE ze{0TM4G5We_TG8z@c3uY4JjOX=}gs_dVorqiC;UmvNr}qo0FTxw5$;q!$Bv=6fStB z$~c3SrkQCi376N`{C7`cM?m}NPWQtoxsC_QK-BGixbw5KjjtaDhahD>q=jZW$yUueMM3?KD-%>U_`am z!N1Xv*$j5pOjtXRF>7FwfmO4Rfo#_^)o#{xf_f<)M5}3phrCy>0|#&E81&T$-6aj> z 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 Mg&sgQNDM{;0REjY*Z=?k literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/ultra_fgalpha_nobg.tif b/backend/tests/data/tif/ultra_fgalpha_nobg.tif new file mode 100644 index 0000000000000000000000000000000000000000..e87a4fdf02922f40637a20f5fa70ff77e0ee6345 GIT binary patch literal 734 zcmebD)M8L!Vqj>ne-L0Hz{In=nL$yY!beY(x5HT};Kv**UBNE5q>m9t@=Rs>4ypv1 z|7o&R??0t{X{X7uSe>cf;YFTHrfD%6`=RU}fu+CL$Pe1&q;5wIU(@W;vjvq>1-F>#RZutYPpL3q&izgq=Fr2=pMqJi% z)2otMy?n~{>n=uYx~^SzYHjQB%%WXq<=!=JyirhMwdUJx_jz|7f3ng2dYpOh?UZjd zf7!(oSDkvd%;2opyxm(~6dKFs_)oUK@#L=M&Na)cd(%EWEVJ>>_h$XN{@9kC{NNYzKtM^tb>>Sgp2K*V4Ur6u1Kfez^mZ4s;d7NnR%ZtUV3xZ^w^{+xo(#>+Ay>F zy_;*X)!RV%*qxxuPYqU{3(j82eAO%0>C=_st6sAludZ1c9TnpWVGIg^PosMeiX4M~Ip@Z=3U@fEP>Lv;}%x9$nmVCeBp0&;9X- z3>`jimPsCqFYV;n9d9M7eO<$u1G+t#1I|Ka4DbB#_58Z-)4#cEBq zTk4Wo5+y1$)qeF=ttqck?e>Ol@OU0(=`zdSeM`v8%_qOgE%sR%{`T9itA3j!x5i{| z-}Urby5*(^k&`oO`I_6N-zxZC6K8fX>R9s2omSJr9!_7Emh^+uuAGzeNRrOC+j;KJ z6^mjwUVn2eIC|QdE5>C$Z{AsU?aSHr%d75iZ1MdkuYaBGJ?*)2|6Ai(Hnz@lJ+~E? z@A|i#x%Tj$cNKT;x$L(*J?rrHzfx{qUyts6`Fomdxo~sQ%?EpgEvEOEU;13OKW_c` z=wIL0_jhOAvh3IX$+Y%d^@{IS@4YwuGwoAhdB5ho(uETT1%i`KJN9O8cy~ykdecU` z0Odnh_6wX|@O#h3V4-`iAAS60?+i44aluWnq?Fs-<8Yzuu@@;C2i^U*)XE$V^05>= zsdxL!7h{hnZRg$lWHsQ3D! zz~!J{zukgErsT}>|NJD`Ysc9y(!9Gi3ZM562~tTnKey$}Uw(7bknL`#FGd+^Zo9HX z=ttO=)|kIH-n4w?3*qKX){5A?wB_-Btvgp!wuYMAO}k_?~(F6h6Y{+21aHEMg|53B_L*mvZa7*CLo&yNdEz*J7%ajE0E6yWdns7 z1Q}VtdO3h>QK&dbj~G-OWR5tL9R$=M#mEX)&%(^WAPr^n0NENyW(GmoAUA;k2NZe$ J*&s0(4FE_pHE93< literal 0 HcmV?d00001 diff --git a/backend/tests/data/tif/ultra_odd.tif b/backend/tests/data/tif/ultra_odd.tif new file mode 100644 index 0000000000000000000000000000000000000000..907f606bb821bbdb820d2f6235562a706a136000 GIT binary patch literal 350 zcmebD)MAKWU|?vFeGp*Wcwily#!N4D<{dF?soatamQ^?$6D!wlbW01?5y@jTW;s=G zz-F4aFvFBHiV`UnI>M3%y&ed2PSNI(Zfr|7<`I(#)#go{U?F&jiHCuKk(q%JXfiJl zGa|8>pllYPI5U*Z3S_fE*~~z;AR`M{F9(n<24#cH5r?t^fNUv7R INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf); @@ -68,24 +69,24 @@ static void test_pixel_plot(int index, int debug) { /* 13*/ { 3, 3, "101010101", 0 }, /* 14*/ { 4, 3, "10", 1 }, /* 15*/ { 3, 4, "10", 1 }, - /* 16*/ { 52, 51, "10", 1 }, // Strip Count 1, Rows Per Strip 51 (52 * 51 * 3 == 7956) - /* 17*/ { 52, 52, "10", 1 }, // Strip Count 1, Rows Per Strip 52 (52 * 52 * 3 == 8112) - /* 18*/ { 53, 52, "10", 1 }, // Strip Count 2, Rows Per Strip 51 (53 * 51 * 3 == 8109) - /* 19*/ { 53, 53, "10", 1 }, // Strip Count 2, Rows Per Strip 51 - /* 20*/ { 2730, 1, "10", 1 }, // Strip Count 1, Rows Per Strip 1 (2730 * 1 * 3 == 8190) - /* 21*/ { 1, 2730, "10", 1 }, // Strip Count 1, Rows Per Strip 2730 - /* 22*/ { 2730, 2, "10", 1 }, // Strip Count 2, Rows Per Strip 1 - /* 23*/ { 2, 2730, "10", 1 }, // Strip Count 2, Rows Per Strip 1365 (2 * 1365 * 3 == 8190) - /* 24*/ { 2730, 3, "10", 1 }, // Strip Count 3, Rows Per Strip 1 - /* 25*/ { 3, 2730, "10", 1 }, // Strip Count 3, Rows Per Strip 910 (3 * 910 * 3 == 8190) - /* 26*/ { 2731, 4, "10", 1 }, // Strip Count 4, Rows Per Strip 1 (2731 * 1 * 3 == 8193) - large rows in 1 strip, even if > 8192 - /* 27*/ { 4, 2731, "10", 1 }, // Strip Count 5, Rows Per Strip 682 (4 * 682 * 3 == 8184) + /* 16*/ { 45, 44, "10", 1 }, // Strip Count 1, Rows Per Strip 44 (45 * 44 * 4 == 7920) + /* 17*/ { 45, 45, "10", 1 }, // Strip Count 1, Rows Per Strip 45 (45 * 45 * 4 == 8100) + /* 18*/ { 46, 45, "10", 1 }, // Strip Count 2, Rows Per Strip 44 (46 * 45 * 4 == 8280) + /* 19*/ { 46, 46, "10", 1 }, // Strip Count 2, Rows Per Strip 44 + /* 20*/ { 2048, 1, "10", 1 }, // Strip Count 1, Rows Per Strip 1 (2048 * 4 == 8192) + /* 21*/ { 1, 2048, "10", 1 }, // Strip Count 1, Rows Per Strip 2048 + /* 22*/ { 2048, 2, "10", 1 }, // Strip Count 2, Rows Per Strip 1 + /* 23*/ { 2, 2048, "10", 1 }, // Strip Count 2, Rows Per Strip 1024 (2 * 1024 * 4 == 8192) + /* 24*/ { 2048, 3, "10", 1 }, // Strip Count 3, Rows Per Strip 1 + /* 25*/ { 3, 2048, "10", 1 }, // Strip Count 4, Rows Per Strip 682 ((3 * 682 + 2) * 4 == 8192) + /* 26*/ { 2049, 4, "10", 1 }, // Strip Count 4, Rows Per Strip 1 (2049 * 1 * 4 == 8196) - large rows in 1 strip, even if > 8192 + /* 27*/ { 4, 2049, "10", 1 }, // Strip Count 5, Rows Per Strip 512 ((4 * 512 + 1) * 4 == 8196) }; int data_size = ARRAY_SIZE(data); char *tif = "out.tif"; - char data_buf[2731 * 4 + 1]; + char data_buf[65536]; for (int i = 0; i < data_size; i++) { @@ -98,10 +99,11 @@ static void test_pixel_plot(int index, int debug) { symbol->bitmap_width = data[i].width; symbol->bitmap_height = data[i].height; + strcpy(symbol->bgcolour, "FFFFFFEE"); // Use alpha background to force RGB symbol->debug |= debug; int size = data[i].width * data[i].height; - assert_nonzero(size < (int) sizeof(data_buf), "i:%d tif_pixel_plot size %d < sizeof(data_buf) %d\n", i, size, (int) sizeof(data_buf)); + assert_nonzero(size < (int) sizeof(data_buf), "i:%d tif_pixel_plot size %d >= sizeof(data_buf) %d\n", i, size, (int) sizeof(data_buf)); if (data[i].repeat) { testUtilStrCpyRepeat(data_buf, data[i].pattern, size); @@ -130,10 +132,138 @@ static void test_pixel_plot(int index, int debug) { testFinish(); } +static void test_print(int index, int generate, int debug) { + + testStart(""); + + int have_identify = testUtilHaveIdentify(); + + int ret; + struct item { + int symbology; + int input_mode; + int border_width; + int output_options; + int whitespace_width; + int show_hrt; + int option_1; + int option_2; + int height; + float scale; + char *fgcolour; + char *bgcolour; + char *data; + char *composite; + char *expected_file; + char *comment; + }; + struct item data[] = { + /* 0*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "112233", "EEDDCC", "A", "", "../data/tif/code128_fgbg.tif", "" }, + /* 1*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "C00000", "FEDCBACC", "A", "", "../data/tif/code128_bgalpha.tif", "" }, + /* 2*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "00000099", "FEDCBA", "A", "", "../data/tif/code128_fgalpha.tif", "" }, + /* 3*/ { BARCODE_CODE128, -1, -1, -1, 1, -1, -1, -1, 0, 0, "00000099", "FEDCBACC", "A", "", "../data/tif/code128_fgbgalpha.tif", "" }, + /* 4*/ { BARCODE_CODE128, -1, -1, CMYK_COLOUR, 1, -1, -1, -1, 0, 0, "C00000", "FEDCBA", "A", "", "../data/tif/code128_cmyk.tif", "" }, + /* 5*/ { BARCODE_CODE128, -1, -1, CMYK_COLOUR, 1, -1, -1, -1, 0, 0, "C0000099", "FEDCBACC", "A", "", "../data/tif/code128_cmyk_fgbgalpha.tif", "" }, + /* 6*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "C00000", "FEDCBACC", "1234", "", "../data/tif/ultra_bgalpha.tif", "" }, + /* 7*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "000000BB", "FEDCBA", "1234", "", "../data/tif/ultra_fgalpha.tif", "" }, + /* 8*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "000000BB", "FEDCBACC", "1234", "", "../data/tif/ultra_fgbgalpha.tif", "" }, + /* 9*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "000000BB", "", "1234", "", "../data/tif/ultra_fgalpha_nobg.tif", "" }, + /* 10*/ { BARCODE_ULTRA, -1, -1, -1, 1, -1, -1, -1, 0, 0, "", "FEDCBACC", "1234", "", "../data/tif/ultra_bgalpha_nofg.tif", "" }, + /* 11*/ { BARCODE_ULTRA, -1, -1, -1, -1, -1, -1, -1, 0, 0.5f, "", "", "1", "", "../data/tif/ultra_odd.tif", "" }, + /* 12*/ { BARCODE_HANXIN, UNICODE_MODE, -1, -1, -1, -1, 4, 84, 0, 2, "", "", "1", "", "../data/tif/hanxin_v84_l4_scale2.tif", "" }, + /* 13*/ { BARCODE_AZTEC, -1, -1, -1, -1, -1, -1, 32, 0, 0, "4BE055", "", "1", "", "../data/tif/aztec_v32_fg.tif", "" }, + /* 14*/ { BARCODE_DAFT, -1, -1, -1, -1, -1, -1, -1, 1, 0.5f, "", "", "F", "", "../data/tif/daft_scale0.5.tif", "" }, + }; + int data_size = ARRAY_SIZE(data); + + char *data_dir = "../data/tif"; + char *tif = "out.tif"; + char escaped[1024]; + int escaped_size = 1024; + char *text; + + if (generate) { + if (!testUtilExists(data_dir)) { + ret = mkdir(data_dir, 0755); + assert_zero(ret, "mkdir(%s) ret %d != 0\n", data_dir, ret); + } + } + + for (int i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + struct zint_symbol* symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + int length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, data[i].option_1, data[i].option_2, -1, data[i].output_options, data[i].data, -1, debug); + if (data[i].show_hrt != -1) { + symbol->show_hrt = data[i].show_hrt; + } + if (data[i].height) { + symbol->height = data[i].height; + } + if (data[i].scale) { + symbol->scale = data[i].scale; + } + if (data[i].border_width != -1) { + symbol->border_width = data[i].border_width; + } + if (data[i].whitespace_width != -1) { + symbol->whitespace_width = data[i].whitespace_width; + } + if (*data[i].fgcolour) { + strcpy(symbol->fgcolour, data[i].fgcolour); + } + if (*data[i].bgcolour) { + strcpy(symbol->bgcolour, data[i].bgcolour); + } + if (strlen(data[i].composite)) { + text = data[i].composite; + strcpy(symbol->primary, data[i].data); + } else { + text = data[i].data; + } + int text_length = strlen(text); + + ret = ZBarcode_Encode(symbol, (unsigned char *) text, text_length); + assert_zero(ret, "i:%d %s ZBarcode_Encode ret %d != 0 %s\n", i, testUtilBarcodeName(data[i].symbology), ret, symbol->errtxt); + + strcpy(symbol->outfile, tif); + ret = ZBarcode_Print(symbol, 0); + assert_zero(ret, "i:%d %s ZBarcode_Print %s ret %d != 0\n", i, testUtilBarcodeName(data[i].symbology), symbol->outfile, ret); + + if (generate) { + printf(" /*%3d*/ { %s, %s, %d, %s, %d, %d, %d, %d, %d, %.5g, \"%s\",\"%s\", \"%s\", \"%s\", \"%s\", \"%s\" },\n", + i, testUtilBarcodeName(data[i].symbology), testUtilInputModeName(data[i].input_mode), data[i].border_width, testUtilOutputOptionsName(data[i].output_options), + data[i].whitespace_width, data[i].show_hrt, data[i].option_1, data[i].option_2, data[i].height, data[i].scale, data[i].fgcolour, data[i].bgcolour, + testUtilEscape(data[i].data, length, escaped, escaped_size), data[i].composite, data[i].expected_file, data[i].comment); + ret = rename(symbol->outfile, data[i].expected_file); + assert_zero(ret, "i:%d rename(%s, %s) ret %d != 0\n", i, symbol->outfile, data[i].expected_file, ret); + if (have_identify) { + ret = testUtilVerifyIdentify(data[i].expected_file, debug); + assert_zero(ret, "i:%d %s identify %s ret %d != 0\n", i, testUtilBarcodeName(data[i].symbology), data[i].expected_file, ret); + } + } else { + assert_nonzero(testUtilExists(symbol->outfile), "i:%d testUtilExists(%s) == 0\n", i, symbol->outfile); + assert_nonzero(testUtilExists(data[i].expected_file), "i:%d testUtilExists(%s) == 0\n", i, data[i].expected_file); + + ret = testUtilCmpBins(symbol->outfile, data[i].expected_file); + assert_zero(ret, "i:%d %s testUtilCmpBins(%s, %s) %d != 0\n", i, testUtilBarcodeName(data[i].symbology), symbol->outfile, data[i].expected_file, ret); + assert_zero(remove(symbol->outfile), "i:%d remove(%s) != 0\n", i, symbol->outfile); + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + int main(int argc, char *argv[]) { testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ { "test_pixel_plot", test_pixel_plot, 1, 0, 1 }, + { "test_print", test_print, 1, 1, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tif.c b/backend/tif.c index b02056be..72cbe80b 100644 --- a/backend/tif.c +++ b/backend/tif.c @@ -3,7 +3,7 @@ /* libzint - the open source barcode library - Copyright (C) 2016 - 2020 Robin Stuart + Copyright (C) 2016 - 2021 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -35,43 +35,238 @@ #include #include #include +#include #include "common.h" #include "tif.h" +#include "tif_lzw.h" #ifdef _MSC_VER #include #include #include #endif +#if !defined(_WIN32) && !defined(__APPLE__) +#include +# if __BYTE_ORDER == __BIG_ENDIAN +#define TIF_BIG_ENDIAN +#endif +#endif + +/* PhotometricInterpretation */ +#define TIF_PMI_WHITEISZERO 0 +#define TIF_PMI_BLACKISZERO 1 +#define TIF_PMI_RGB 2 +#define TIF_PMI_PALETTE_COLOR 3 +#define TIF_PMI_SEPARATED 5 /* CMYK */ + +/* Compression */ +#define TIF_NO_COMPRESSION 1 +#define TIF_LZW 5 + +static void to_color_map(unsigned char rgb[4], tiff_color_t *color_map_entry) { + color_map_entry->red = (rgb[0] << 8) | rgb[0]; + color_map_entry->green = (rgb[1] << 8) | rgb[1]; + color_map_entry->blue = (rgb[2] << 8) | rgb[2]; +} + +static void to_cmyk(unsigned char rgb[3], unsigned char alpha, unsigned char *cmyk) { + unsigned char max = rgb[0]; + if (rgb[1] > max) { + max = rgb[1]; + } + if (rgb[2] > max) { + max = rgb[2]; + } + cmyk[0] = max - rgb[0]; + cmyk[1] = max - rgb[1]; + cmyk[2] = max - rgb[2]; + cmyk[3] = 0xff - max; + cmyk[4] = alpha; + +} + INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) { - int fgred, fggrn, fgblu, bgred, bggrn, bgblu; + unsigned char fg[4], bg[4]; int i; + int pmi; /* PhotometricInterpretation */ int rows_per_strip, strip_count; - unsigned int free_memory; + int rows_last_strip; + int bytes_per_strip; + uint16_t bits_per_sample; + int samples_per_pixel; + int pixels_per_sample; + unsigned char map[128]; + tiff_color_t color_map[256] = {0}; + unsigned char palette[32][5]; + int color_map_size = 0; + int extra_samples = 0; + uint32_t free_memory; int row, column, strip; + int strip_row; unsigned int bytes_put; + long total_bytes_put; FILE *tif_file; + unsigned char *pb; + int compression = TIF_NO_COMPRESSION; + tif_lzw_state lzw_state; + long file_pos; #ifdef _MSC_VER uint32_t* strip_offset; uint32_t* strip_bytes; + unsigned char *strip_buf; #endif tiff_header_t header; - tiff_ifd_t ifd; - uint16_t temp; + uint16_t entries = 0; + tiff_tag_t tags[20]; + uint32_t offset = 0; + int update_offsets[20]; + int offsets = 0; + int ifd_size; uint32_t temp32; - fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); - fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); - fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); - bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); - bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); - bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); + fg[0] = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); + fg[1] = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); + fg[2] = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); + bg[0] = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); + bg[1] = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); + bg[2] = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); + + if (strlen(symbol->fgcolour) > 6) { + fg[3] = (16 * ctoi(symbol->fgcolour[6])) + ctoi(symbol->fgcolour[7]); + } else { + fg[3] = 0xff; + } + + if (strlen(symbol->bgcolour) > 6) { + bg[3] = (16 * ctoi(symbol->bgcolour[6])) + ctoi(symbol->bgcolour[7]); + } else { + bg[3] = 0xff; + } + + if (symbol->symbology == BARCODE_ULTRA) { + static const int ultra_chars[8] = { 'W', 'C', 'B', 'M', 'R', 'Y', 'G', 'K' }; + static unsigned char ultra_rgbs[8][3] = { + { 0xff, 0xff, 0xff, }, /* White */ + { 0, 0xff, 0xff, }, /* Cyan */ + { 0, 0, 0xff, }, /* Blue */ + { 0xff, 0, 0xff, }, /* Magenta */ + { 0xff, 0, 0, }, /* Red */ + { 0xff, 0xff, 0, }, /* Yellow */ + { 0, 0xff, 0, }, /* Green */ + { 0, 0, 0, }, /* Black */ + }; + + if (symbol->output_options & CMYK_COLOUR) { + for (i = 0; i < 8; i++) { + map[ultra_chars[i]] = i; + to_cmyk(ultra_rgbs[i], fg[3], palette[i]); + } + map['0'] = 8; + to_cmyk(bg, bg[3], palette[8]); + map['1'] = 9; + to_cmyk(fg, fg[3], palette[9]); + + pmi = TIF_PMI_SEPARATED; + bits_per_sample = 8; + if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */ + samples_per_pixel = 4; + } else { + samples_per_pixel = 5; + extra_samples = 1; /* Associated alpha */ + } + pixels_per_sample = 1; + } else { + for (i = 0; i < 8; i++) { + map[ultra_chars[i]] = i; + memcpy(palette[i], ultra_rgbs[i], 3); + palette[i][3] = fg[3]; + } + map['0'] = 8; + memcpy(palette[8], bg, 4); + map['1'] = 9; + memcpy(palette[9], fg, 4); + + if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */ + pmi = TIF_PMI_PALETTE_COLOR; + for (i = 0; i < 10; i++) { + to_color_map(palette[i], &color_map[i]); + } + bits_per_sample = 4; + samples_per_pixel = 1; + pixels_per_sample = 2; + color_map_size = 16; /* 2**BitsPerSample */ + } else { + pmi = TIF_PMI_RGB; + bits_per_sample = 8; + samples_per_pixel = 4; + pixels_per_sample = 1; + extra_samples = 1; /* Associated alpha */ + } + } + } else { /* fg/bg only */ + if (symbol->output_options & CMYK_COLOUR) { + map['0'] = 0; + to_cmyk(bg, bg[3], palette[0]); + map['1'] = 1; + to_cmyk(fg, fg[3], palette[1]); + + pmi = TIF_PMI_SEPARATED; + bits_per_sample = 8; + if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */ + samples_per_pixel = 4; + } else { + samples_per_pixel = 5; + extra_samples = 1; /* Associated alpha */ + } + pixels_per_sample = 1; + } else if (bg[0] == 0xff && bg[1] == 0xff && bg[2] == 0xff && bg[3] == 0xff + && fg[0] == 0 && fg[1] == 0 && fg[2] == 0 && fg[3] == 0xff) { + map['0'] = 0; + map['1'] = 1; + + pmi = TIF_PMI_WHITEISZERO; + bits_per_sample = 1; + samples_per_pixel = 1; + pixels_per_sample = 8; + } else if (bg[0] == 0 && bg[1] == 0 && bg[2] == 0 && bg[3] == 0xff + && fg[0] == 0xff && fg[1] == 0xff && fg[2] == 0xff && fg[3] == 0xff) { + map['0'] = 1; + map['1'] = 0; + + pmi = TIF_PMI_BLACKISZERO; + bits_per_sample = 1; + samples_per_pixel = 1; + pixels_per_sample = 8; + } else { + map['0'] = 0; + memcpy(palette[0], bg, 4); + map['1'] = 1; + memcpy(palette[1], fg, 4); + + pmi = TIF_PMI_PALETTE_COLOR; + for (i = 0; i < 2; i++) { + to_color_map(palette[i], &color_map[i]); + } + if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */ + bits_per_sample = 4; + samples_per_pixel = 1; + pixels_per_sample = 2; + color_map_size = 16; /* 2**BitsPerSample */ + } else { + bits_per_sample = 8; + samples_per_pixel = 2; + pixels_per_sample = 1; + color_map_size = 256; /* 2**BitsPerSample */ + extra_samples = 1; /* Associated alpha */ + } + } + } /* TIFF Rev 6 Section 7 p.27 "Set RowsPerStrip such that the size of each strip is about 8K bytes... * Note that extremely wide high resolution images may have rows larger than 8K bytes; in this case, * RowsPerStrip should be 1, and the strip will be larger than 8K." */ - rows_per_strip = 8192 / (symbol->bitmap_width * 3); + rows_per_strip = (8192 * pixels_per_sample) / (symbol->bitmap_width * samples_per_pixel); if (rows_per_strip == 0) { rows_per_strip = 1; } @@ -79,43 +274,56 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) /* Suppresses clang-tidy clang-analyzer-core.VLASize warning */ assert(symbol->bitmap_height > 0); - strip_count = symbol->bitmap_height / rows_per_strip; - if ((symbol->bitmap_height % rows_per_strip) != 0) { - strip_count++; - } - - if (rows_per_strip > symbol->bitmap_height) { - rows_per_strip = symbol->bitmap_height; + if (rows_per_strip >= symbol->bitmap_height) { + strip_count = 1; + rows_per_strip = rows_last_strip = symbol->bitmap_height; + } else { + strip_count = symbol->bitmap_height / rows_per_strip; + rows_last_strip = symbol->bitmap_height % rows_per_strip; + if (rows_last_strip != 0) { + strip_count++; + } + if (rows_per_strip > symbol->bitmap_height) { + rows_per_strip = rows_last_strip = symbol->bitmap_height; + } } + assert(strip_count > 0); /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */ if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("TIFF (%dx%d) Strip Count %d, Rows Per Strip %d\n", symbol->bitmap_width, symbol->bitmap_height, strip_count, rows_per_strip); + printf("TIFF (%dx%d) Strip Count %d, Rows Per Strip %d\n", symbol->bitmap_width, symbol->bitmap_height, + strip_count, rows_per_strip); } + bytes_per_strip = rows_per_strip * ((symbol->bitmap_width + pixels_per_sample - 1) / pixels_per_sample) + * samples_per_pixel; + #ifndef _MSC_VER uint32_t strip_offset[strip_count]; uint32_t strip_bytes[strip_count]; + unsigned char strip_buf[bytes_per_strip + 1]; #else - strip_offset = (uint32_t*) _alloca(strip_count * sizeof(uint32_t)); - strip_bytes = (uint32_t*) _alloca(strip_count * sizeof(uint32_t)); + strip_offset = (uint32_t *) _alloca(strip_count * sizeof(uint32_t)); + strip_bytes = (uint32_t *) _alloca(strip_count * sizeof(uint32_t)); + strip_buf = (unsigned char *) _alloca(bytes_per_strip + 1); #endif - free_memory = 8; + free_memory = sizeof(tiff_header_t); - for(i = 0; i < strip_count; i++) { + for (i = 0; i < strip_count; i++) { strip_offset[i] = free_memory; if (i != (strip_count - 1)) { - strip_bytes[i] = rows_per_strip * symbol->bitmap_width * 3; + strip_bytes[i] = bytes_per_strip; } else { - if ((symbol->bitmap_height % rows_per_strip) != 0) { - strip_bytes[i] = (symbol->bitmap_height % rows_per_strip) * symbol->bitmap_width * 3; + if (rows_last_strip) { + strip_bytes[i] = rows_last_strip * ((symbol->bitmap_width + pixels_per_sample - 1) / pixels_per_sample) + * samples_per_pixel; } else { - strip_bytes[i] = rows_per_strip * symbol->bitmap_width * 3; + strip_bytes[i] = bytes_per_strip; } } free_memory += strip_bytes[i]; - if ((free_memory % 2) == 1) { - free_memory++; - } + } + if (free_memory & 1) { + free_memory++; // IFD must be on word boundary } if (free_memory > 0xffff0000) { @@ -133,184 +341,232 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) #endif tif_file = stdout; } else { - if (!(tif_file = fopen(symbol->outfile, "wb"))) { + if (!(tif_file = fopen(symbol->outfile, "wb+"))) { strcpy(symbol->errtxt, "672: Can't open output file"); return ZINT_ERROR_FILE_ACCESS; } + compression = TIF_LZW; + tif_lzw_init(&lzw_state); } /* Header */ - header.byte_order = 0x4949; +#ifdef TIF_BIG_ENDIAN + header.byte_order = 0x4D4D; // "MM" big-endian +#else + header.byte_order = 0x4949; // "II" little-endian +#endif header.identity = 42; header.offset = free_memory; fwrite(&header, sizeof(tiff_header_t), 1, tif_file); - free_memory += sizeof(tiff_ifd_t); + total_bytes_put = sizeof(tiff_header_t); /* Pixel data */ + pb = pixelbuf; strip = 0; + strip_row = 0; bytes_put = 0; for (row = 0; row < symbol->bitmap_height; row++) { - for (column = 0; column < symbol->bitmap_width; column++) { - switch(pixelbuf[(row * symbol->bitmap_width) + column]) { - case 'W': // White - putc(255, tif_file); - putc(255, tif_file); - putc(255, tif_file); - break; - case 'C': // Cyan - putc(0, tif_file); - putc(255, tif_file); - putc(255, tif_file); - break; - case 'B': // Blue - putc(0, tif_file); - putc(0, tif_file); - putc(255, tif_file); - break; - case 'M': // Magenta - putc(255, tif_file); - putc(0, tif_file); - putc(255, tif_file); - break; - case 'R': // Red - putc(255, tif_file); - putc(0, tif_file); - putc(0, tif_file); - break; - case 'Y': // Yellow - putc(255, tif_file); - putc(255, tif_file); - putc(0, tif_file); - break; - case 'G': // Green - putc(0, tif_file); - putc(255, tif_file); - putc(0, tif_file); - break; - case 'K': // Black - putc(0, tif_file); - putc(0, tif_file); - putc(0, tif_file); - break; - case '1': - putc(fgred, tif_file); - putc(fggrn, tif_file); - putc(fgblu, tif_file); - break; - default: - putc(bgred, tif_file); - putc(bggrn, tif_file); - putc(bgblu, tif_file); - break; + if (samples_per_pixel == 1) { + if (bits_per_sample == 1) { /* WHITEISZERO or BLACKISZERO */ + for (column = 0; column < symbol->bitmap_width; column += 8) { + unsigned char byte = 0; + for (i = 0; i < 8 && column + i < symbol->bitmap_width; i++, pb++) { + byte |= map[*pb] << (7 - i); + } + strip_buf[bytes_put++] = byte; + } + } else { /* bits_per_sample == 4, PALETTE_COLOR with no alpha */ + for (column = 0; column < symbol->bitmap_width; column += 2) { + unsigned char byte = map[*pb++] << 4; + if (column + 1 < symbol->bitmap_width) { + byte |= map[*pb++]; + } + strip_buf[bytes_put++] = byte; + } + } + } else if (samples_per_pixel == 2) { /* PALETTE_COLOR with alpha */ + for (column = 0; column < symbol->bitmap_width; column++) { + int idx = map[*pb++]; + strip_buf[bytes_put++] = idx; + strip_buf[bytes_put++] = palette[idx][3]; + } + } else { /* samples_per_pixel >= 4, RGB with alpha (4) or CMYK with (5) or without (4) alpha */ + for (column = 0; column < symbol->bitmap_width; column++) { + int idx = map[*pb++]; + memcpy(&strip_buf[bytes_put], &palette[idx], samples_per_pixel); + bytes_put += samples_per_pixel; } - bytes_put += 3; } - if (strip < strip_count && (bytes_put + 3) >= strip_bytes[strip]) { - // End of strip, pad if strip length is odd - if (strip_bytes[strip] % 2 == 1) { - putc(0, tif_file); + strip_row++; + + if (strip_row == rows_per_strip || (strip == strip_count - 1 && strip_row == rows_last_strip)) { + // End of strip + if (compression == TIF_LZW) { + file_pos = ftell(tif_file); + if (!tif_lzw_encode(&lzw_state, tif_file, strip_buf, bytes_put)) { /* Only fails if can't malloc */ + tif_lzw_cleanup(&lzw_state); + fclose(tif_file); /* Only use LZW if not STDOUT, so ok to close */ + strcpy(symbol->errtxt, "673: Failed to malloc LZW hash table"); + return ZINT_ERROR_MEMORY; + } + bytes_put = ftell(tif_file) - file_pos; + if (bytes_put != strip_bytes[strip]) { + int diff = bytes_put - strip_bytes[strip]; + strip_bytes[strip] = bytes_put; + for (i = strip + 1; i < strip_count; i++) { + strip_offset[i] += diff; + } + } + } else { + fwrite(strip_buf, 1, bytes_put, tif_file); } strip++; + total_bytes_put += bytes_put; bytes_put = 0; + strip_row = 0; + /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */ + assert(strip < strip_count || row + 1 == symbol->bitmap_height); } } + if (total_bytes_put & 1) { + putc(0, tif_file); // IFD must be on word boundary + total_bytes_put++; + } + + if (compression == TIF_LZW) { + tif_lzw_cleanup(&lzw_state); + + file_pos = ftell(tif_file); + fseek(tif_file, 4, SEEK_SET); + free_memory = file_pos; + fwrite(&free_memory, 4, 1, tif_file); + fseek(tif_file, file_pos, SEEK_SET); + } + /* Image File Directory */ - ifd.entries = 14; - ifd.offset = 0; + tags[entries].tag = 0x0100; // ImageWidth + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = symbol->bitmap_width; - ifd.new_subset.tag = 0xfe; - ifd.new_subset.type = 4; - ifd.new_subset.count = 1; - ifd.new_subset.offset = 0; + tags[entries].tag = 0x0101; // ImageLength - number of rows + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = symbol->bitmap_height; - ifd.image_width.tag = 0x0100; - ifd.image_width.type = 3; // SHORT - ifd.image_width.count = 1; - ifd.image_width.offset = symbol->bitmap_width; + if (samples_per_pixel != 1 || bits_per_sample != 1) { + tags[entries].tag = 0x0102; // BitsPerSample + tags[entries].type = 3; // SHORT + tags[entries].count = samples_per_pixel; + if (samples_per_pixel == 1) { + tags[entries++].offset = bits_per_sample; + } else if (samples_per_pixel == 2) { /* 2 SHORTS fit into LONG offset so packed into offset */ + tags[entries++].offset = (bits_per_sample << 16) | bits_per_sample; + } else { + update_offsets[offsets++] = entries; + tags[entries++].offset = free_memory; + free_memory += samples_per_pixel * 2; + } + } - ifd.image_length.tag = 0x0101; - ifd.image_length.type = 3; // SHORT - ifd.image_length.count = 1; - ifd.image_length.offset = symbol->bitmap_height; + tags[entries].tag = 0x0103; // Compression + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = compression; - ifd.bits_per_sample.tag = 0x0102; - ifd.bits_per_sample.type = 3; // SHORT - ifd.bits_per_sample.count = 3; - ifd.bits_per_sample.offset = free_memory; - free_memory += 6; + tags[entries].tag = 0x0106; // PhotometricInterpretation + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = pmi; - ifd.compression.tag = 0x0103; - ifd.compression.type = 3; - ifd.compression.count = 1; - ifd.compression.offset = 1; // Uncompressed - - ifd.photometric.tag = 0x0106; - ifd.photometric.type = 3; // SHORT - ifd.photometric.count = 1; - ifd.photometric.offset = 2; // RGB Model - - ifd.strip_offsets.tag = 0x0111; - ifd.strip_offsets.type = 4; // LONG - ifd.strip_offsets.count = strip_count; + tags[entries].tag = 0x0111; // StripOffsets + tags[entries].type = 4; // LONG + tags[entries].count = strip_count; if (strip_count == 1) { - ifd.strip_offsets.offset = strip_offset[0]; + tags[entries++].offset = strip_offset[0]; } else { - ifd.strip_offsets.offset = free_memory; + update_offsets[offsets++] = entries; + tags[entries++].offset = free_memory; free_memory += strip_count * 4; } - ifd.samples_per_pixel.tag = 0x0115; - ifd.samples_per_pixel.type = 3; - ifd.samples_per_pixel.count = 1; - ifd.samples_per_pixel.offset = 3; + if (samples_per_pixel > 1) { + tags[entries].tag = 0x0115; // SamplesPerPixel + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = samples_per_pixel; + } - ifd.rows_per_strip.tag = 0x0116; - ifd.rows_per_strip.type = 4; - ifd.rows_per_strip.count = 1; - ifd.rows_per_strip.offset = rows_per_strip; + tags[entries].tag = 0x0116; // RowsPerStrip + tags[entries].type = 4; // LONG + tags[entries].count = 1; + tags[entries++].offset = rows_per_strip; - ifd.strip_byte_counts.tag = 0x0117; - ifd.strip_byte_counts.type = 4; - ifd.strip_byte_counts.count = strip_count; + tags[entries].tag = 0x0117; // StripByteCounts + tags[entries].type = 4; // LONG + tags[entries].count = strip_count; if (strip_count == 1) { - ifd.strip_byte_counts.offset = strip_bytes[0]; + tags[entries++].offset = strip_bytes[0]; } else { - ifd.strip_byte_counts.offset = free_memory; + update_offsets[offsets++] = entries; + tags[entries++].offset = free_memory; free_memory += strip_count * 4; } - ifd.x_resolution.tag = 0x011a; - ifd.x_resolution.type = 5; - ifd.x_resolution.count = 1; - ifd.x_resolution.offset = free_memory; + tags[entries].tag = 0x011a; // XResolution + tags[entries].type = 5; // RATIONAL + tags[entries].count = 1; + update_offsets[offsets++] = entries; + tags[entries++].offset = free_memory; free_memory += 8; - ifd.y_resolution.tag = 0x011b; - ifd.y_resolution.type = 5; - ifd.y_resolution.count = 1; - ifd.y_resolution.offset = free_memory; -// free_memory += 8; + tags[entries].tag = 0x011b; // YResolution + tags[entries].type = 5; // RATIONAL + tags[entries].count = 1; + update_offsets[offsets++] = entries; + tags[entries++].offset = free_memory; + free_memory += 8; - ifd.planar_config.tag = 0x11c; - ifd.planar_config.type = 3; - ifd.planar_config.count = 1; - ifd.planar_config.offset = 1; + tags[entries].tag = 0x0128; // ResolutionUnit + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = 2; // Inches - ifd.resolution_unit.tag = 0x0128; - ifd.resolution_unit.type = 3; - ifd.resolution_unit.count = 1; - ifd.resolution_unit.offset = 2; // Inches + if (color_map_size) { + tags[entries].tag = 0x0140; // ColorMap + tags[entries].type = 3; // SHORT + tags[entries].count = color_map_size * 3; + update_offsets[offsets++] = entries; + tags[entries++].offset = free_memory; + //free_memory += color_map_size * 3 * 2; /* Unnecessary as long as last use */ + } - fwrite(&ifd, sizeof(tiff_ifd_t), 1, tif_file); + if (extra_samples) { + tags[entries].tag = 0x0152; // ExtraSamples + tags[entries].type = 3; // SHORT + tags[entries].count = 1; + tags[entries++].offset = extra_samples; + } - /* Bits per sample */ - temp = 8; - fwrite(&temp, 2, 1, tif_file); // Red Bytes - fwrite(&temp, 2, 1, tif_file); // Green Bytes - fwrite(&temp, 2, 1, tif_file); // Blue Bytes + ifd_size = sizeof(entries) + sizeof(tiff_tag_t) * entries + sizeof(offset); + for (i = 0; i < offsets; i++) { + tags[update_offsets[i]].offset += ifd_size; + } + + fwrite(&entries, sizeof(entries), 1, tif_file); + fwrite(&tags, sizeof(tiff_tag_t), entries, tif_file); + fwrite(&offset, sizeof(offset), 1, tif_file); + total_bytes_put += ifd_size; + + if (samples_per_pixel > 2) { + for (i = 0; i < samples_per_pixel; i++) { + fwrite(&bits_per_sample, sizeof(bits_per_sample), 1, tif_file); + } + total_bytes_put += sizeof(bits_per_sample) * samples_per_pixel; + } if (strip_count != 1) { /* Strip offsets */ @@ -322,6 +578,7 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) for (i = 0; i < strip_count; i++) { fwrite(&strip_bytes[i], 4, 1, tif_file); } + total_bytes_put += strip_count * 8; } /* X Resolution */ @@ -329,16 +586,36 @@ INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) fwrite(&temp32, 4, 1, tif_file); temp32 = 1; fwrite(&temp32, 4, 1, tif_file); + total_bytes_put += 8; /* Y Resolution */ temp32 = 72; fwrite(&temp32, 4, 1, tif_file); temp32 = 1; fwrite(&temp32, 4, 1, tif_file); + total_bytes_put += 8; + + if (color_map_size) { + for (i = 0; i < color_map_size; i++) { + fwrite(&color_map[i].red, 2, 1, tif_file); + } + for (i = 0; i < color_map_size; i++) { + fwrite(&color_map[i].green, 2, 1, tif_file); + } + for (i = 0; i < color_map_size; i++) { + fwrite(&color_map[i].blue, 2, 1, tif_file); + } + total_bytes_put += 6 * color_map_size; + } if (symbol->output_options & BARCODE_STDOUT) { fflush(tif_file); } else { + if (ftell(tif_file) != total_bytes_put) { + fclose(tif_file); + strcpy(symbol->errtxt, "674: Failed to write all output"); + return ZINT_ERROR_FILE_WRITE; + } fclose(tif_file); } diff --git a/backend/tif.h b/backend/tif.h index 3e3c4596..80b31ec3 100644 --- a/backend/tif.h +++ b/backend/tif.h @@ -2,7 +2,7 @@ /* libzint - the open source barcode library - Copyright (C) 2016-2017 Robin Stuart + Copyright (C) 2016-2021 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,10 +29,12 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TIF_H -#define TIF_H +/* vim: set ts=4 sw=4 et : */ -#ifdef __cplusplus +#ifndef TIF_H +#define TIF_H + +#ifdef __cplusplus extern "C" { #endif @@ -58,31 +60,16 @@ extern "C" { uint32_t offset; } tiff_tag_t; - typedef struct tiff_ifd { - uint16_t entries; - tiff_tag_t new_subset; - tiff_tag_t image_width; - tiff_tag_t image_length; - tiff_tag_t bits_per_sample; - tiff_tag_t compression; - tiff_tag_t photometric; - tiff_tag_t strip_offsets; - tiff_tag_t samples_per_pixel; - tiff_tag_t rows_per_strip; - tiff_tag_t strip_byte_counts; - tiff_tag_t x_resolution; - tiff_tag_t y_resolution; - tiff_tag_t planar_config; - tiff_tag_t resolution_unit; - uint32_t offset; - } tiff_ifd_t; + typedef struct tiff_color { + uint16_t red; + uint16_t green; + uint16_t blue; + } tiff_color_t; #pragma pack() -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* TIF_H */ - - +#endif /* TIF_H */ diff --git a/backend/tif_lzw.h b/backend/tif_lzw.h new file mode 100644 index 00000000..d18b9b2e --- /dev/null +++ b/backend/tif_lzw.h @@ -0,0 +1,373 @@ +/* tif_lzw.h - LZW compression for TIFF + + libzint - the open source barcode library + Copyright (C) 2021 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* vim: set ts=4 sw=4 et : */ + +#ifndef TIF_LZW_H +#define TIF_LZW_H + +/* + * Adapted from TIFF Library 4.2.0 libtiff/tif_lzw.c */ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +/* + * TIFF Library. + * Rev 5.0 Lempel-Ziv & Welch Compression Support + * + * This code is derived from the compress program whose code is + * derived from software contributed to Berkeley by James A. Woods, + * derived from original work by Spencer Thomas and Joseph Orost. + * + * The original Berkeley copyright notice appears below in its entirety. + */ +/* + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#define MAXCODE(n) ((1L << (n)) - 1) + +/* + * The TIFF spec specifies that encoded bit + * strings range from 9 to 12 bits. + */ +#define BITS_MIN 9 /* start with 9 bits */ +#define BITS_MAX 12 /* max of 12 bit strings */ +/* predefined codes */ +#define CODE_CLEAR 256 /* code to clear string table */ +#define CODE_EOI 257 /* end-of-information code */ +#define CODE_FIRST 258 /* first free code entry */ +#define CODE_MAX MAXCODE(BITS_MAX) +#define HSIZE 9001L /* 91% occupancy */ +#define HSHIFT (13 - 8) + +/* + * Encoding-specific state. + */ +typedef uint16_t tif_lzw_hcode; /* codes fit in 16 bits */ +typedef struct { + long hash; + tif_lzw_hcode code; +} tif_lzw_hash; + +#define CHECK_GAP 10000 /* ratio check interval */ + +/* + * State block. + */ +typedef struct { + tif_lzw_hash *enc_hashtab; /* kept separate for small machines */ +} tif_lzw_state; + +/* + * LZW Encoding. + */ + +/* + * Reset encoding hash table. + */ +static void tif_lzw_cl_hash(tif_lzw_state *sp) { + register tif_lzw_hash *hp = &sp->enc_hashtab[HSIZE - 1]; + register long i = HSIZE - 8; + + do { + i -= 8; + hp[-7].hash = -1; + hp[-6].hash = -1; + hp[-5].hash = -1; + hp[-4].hash = -1; + hp[-3].hash = -1; + hp[-2].hash = -1; + hp[-1].hash = -1; + hp[ 0].hash = -1; + hp -= 8; + } while (i >= 0); + + for (i += 8; i > 0; i--, hp--) { + hp->hash = -1; + } +} + +#define CALCRATIO(sp, rat) { \ + if (incount > 0x007fffff) { /* NB: shift will overflow */ \ + rat = outcount >> 8; \ + rat = (rat == 0 ? 0x7fffffff : incount / rat); \ + } else \ + rat = (incount << 8) / outcount; \ +} + +/* Explicit 0xff masking to make icc -check=conversions happy */ +#define PutNextCode(op_file, c) { \ + nextdata = (nextdata << nbits) | c; \ + nextbits += nbits; \ + putc((nextdata >> (nextbits - 8)) & 0xff, op_file); \ + nextbits -= 8; \ + if (nextbits >= 8) { \ + putc((nextdata >> (nextbits - 8)) & 0xff, op_file); \ + nextbits -= 8; \ + } \ + outcount += nbits; \ +} + +/* + * Encode a chunk of pixels. + * + * Uses an open addressing double hashing (no chaining) on the + * prefix code/next character combination. We do a variant of + * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's + * relatively-prime secondary probe. Here, the modular division + * first probe is gives way to a faster exclusive-or manipulation. + * Also do block compression with an adaptive reset, whereby the + * code table is cleared when the compression ratio decreases, + * but after the table fills. The variable-length output codes + * are re-sized at this point, and a CODE_CLEAR is generated + * for the decoder. + */ +static int tif_lzw_encode(tif_lzw_state *sp, FILE *op_file, const unsigned char *bp, int cc) { + register long fcode; + register tif_lzw_hash *hp; + register int h, c; + tif_lzw_hcode ent; + long disp; + + int nbits; /* # of bits/code */ + int maxcode; /* maximum code for nbits */ + int free_ent; /* next free entry in hash table */ + unsigned long nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in nextdata */ + long checkpoint; /* point at which to clear table */ + long ratio; /* current compression ratio */ + long incount; /* (input) data bytes encoded */ + long outcount; /* encoded (output) bytes */ + + /* + * Reset encoding state at the start of a strip. + */ + if (sp->enc_hashtab == NULL) { + sp->enc_hashtab = (tif_lzw_hash *) malloc(HSIZE * sizeof(tif_lzw_hash)); + if (sp->enc_hashtab == NULL) { + return 0; + } + } + + tif_lzw_cl_hash(sp); /* clear hash table */ + + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + free_ent = CODE_FIRST; + nextdata = 0; + nextbits = 0; + checkpoint = CHECK_GAP; + ratio = 0; + incount = 0; + outcount = 0; + + ent = (tif_lzw_hcode) -1; + + if (cc > 0) { + PutNextCode(op_file, CODE_CLEAR); + ent = *bp++; cc--; incount++; + } + while (cc > 0) { + c = *bp++; cc--; incount++; + fcode = ((long)c << BITS_MAX) + ent; + h = (c << HSHIFT) ^ ent; /* xor hashing */ +#ifdef _WINDOWS + /* + * Check hash index for an overflow. + */ + if (h >= HSIZE) { + h -= HSIZE; + } +#endif + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + continue; + } + if (hp->hash >= 0) { + /* + * Primary hash failed, check secondary hash. + */ + disp = HSIZE - h; + if (h == 0) { + disp = 1; + } + do { + /* + * Avoid pointer arithmetic because of + * wraparound problems with segments. + */ + if ((h -= disp) < 0) { + h += HSIZE; + } + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + goto hit; + } + } while (hp->hash >= 0); + } + /* + * New entry, emit code and add to table. + */ + PutNextCode(op_file, ent); + ent = (tif_lzw_hcode) c; + hp->code = (tif_lzw_hcode) (free_ent++); + hp->hash = fcode; + if (free_ent == CODE_MAX - 1) { + /* table is full, emit clear code and reset */ + tif_lzw_cl_hash(sp); + ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op_file, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + maxcode = (int) MAXCODE(nbits); + } else if (incount >= checkpoint) { + long rat; + /* + * Check compression ratio and, if things seem + * to be slipping, clear the hash table and + * reset state. The compression ratio is a + * 24+8-bit fractional number. + */ + checkpoint = incount + CHECK_GAP; + CALCRATIO(sp, rat); + if (rat <= ratio) { + tif_lzw_cl_hash(sp); + ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op_file, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else { + ratio = rat; + } + } + } + hit: + ; + } + + /* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ + if (ent != (tif_lzw_hcode) -1) { + + PutNextCode(op_file, ent); + free_ent++; + + if (free_ent == CODE_MAX - 1) { + /* table is full, emit clear code and reset */ + outcount = 0; + PutNextCode(op_file, CODE_CLEAR); + nbits = BITS_MIN; + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + } + } + } + PutNextCode(op_file, CODE_EOI); + /* Explicit 0xff masking to make icc -check=conversions happy */ + if (nextbits > 0) { + putc((nextdata << (8 - nextbits)) & 0xff, op_file); + } + + return 1; +} + +static void tif_lzw_cleanup(tif_lzw_state *sp) { + if (sp->enc_hashtab) { + free(sp->enc_hashtab); + } +} + +static void tif_lzw_init(tif_lzw_state *sp) { + sp->enc_hashtab = NULL; +} + +#endif /* TIF_LZW_H */ diff --git a/backend/zint.h b/backend/zint.h index 90d58b8c..e781159f 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -275,6 +275,7 @@ extern "C" { #define ZINT_ERROR_ENCODING_PROBLEM 9 #define ZINT_ERROR_FILE_ACCESS 10 #define ZINT_ERROR_MEMORY 11 +#define ZINT_ERROR_FILE_WRITE 12 // File types #define OUT_BUFFER 0 diff --git a/docs/manual.txt b/docs/manual.txt index f2d3f436..c0a98b8a 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -1037,6 +1037,9 @@ ZINT_ERROR_FILE_ACCESS | Zint was unable to open the requested output | problem. ZINT_ERROR_MEMORY | Zint ran out of memory. This should only be a | problem with legacy systems. +ZINT_ERROR_FILE_WRITE | Zint failed to write all contents to the + | requested output file. This should only occur + | if the output disk becomes full. -------------------------------------------------------------------------------- To catch errors use an integer variable as shown in the code below: diff --git a/frontend_qt/frontend_qt.pro b/frontend_qt/frontend_qt.pro index e3f0a639..bd25f8c7 100644 --- a/frontend_qt/frontend_qt.pro +++ b/frontend_qt/frontend_qt.pro @@ -53,6 +53,7 @@ HEADERS += barcodeitem.h \ ..\backend\sjis.h \ ..\backend\stdint_msvc.h \ ..\backend\tif.h \ + ..\backend\tif_lzw.h \ ..\backend\zint.h \ ..\backend\zintconfig.h \ diff --git a/frontend_qt/mainWindow.ui b/frontend_qt/mainWindow.ui index 1a50e829..7bd674fc 100644 --- a/frontend_qt/mainWindow.ui +++ b/frontend_qt/mainWindow.ui @@ -936,10 +936,10 @@ p, li { white-space: pre-wrap; } - Use CMYK colour space in EPS output + Use CMYK colour space in EPS/TIF output - CMY&K (EPS) + CMY&K (EPS/TIF) false diff --git a/win32/libzint.vcxproj b/win32/libzint.vcxproj index 651519bf..581fc1e0 100644 --- a/win32/libzint.vcxproj +++ b/win32/libzint.vcxproj @@ -210,6 +210,7 @@ + diff --git a/win32/vs2008/libzint.vcproj b/win32/vs2008/libzint.vcproj index 4af9e7cb..015edc9b 100644 --- a/win32/vs2008/libzint.vcproj +++ b/win32/vs2008/libzint.vcproj @@ -617,6 +617,10 @@ RelativePath="..\backend\tif.h" > + + diff --git a/win32/vs2015/libzint.vcxproj b/win32/vs2015/libzint.vcxproj index f08100cd..66b8bacb 100644 --- a/win32/vs2015/libzint.vcxproj +++ b/win32/vs2015/libzint.vcxproj @@ -389,6 +389,7 @@ + diff --git a/win32/vs2015/vsx/libzintMD.vcxproj b/win32/vs2015/vsx/libzintMD.vcxproj index aa6a7ab2..9c7f4b52 100644 --- a/win32/vs2015/vsx/libzintMD.vcxproj +++ b/win32/vs2015/vsx/libzintMD.vcxproj @@ -157,6 +157,7 @@ + diff --git a/win32/vs2019/libzint.vcxproj b/win32/vs2019/libzint.vcxproj index 8baece13..473ea5c0 100644 --- a/win32/vs2019/libzint.vcxproj +++ b/win32/vs2019/libzint.vcxproj @@ -210,6 +210,7 @@ +