From aabd104114f8b285dc93788e0f6888b10db72099 Mon Sep 17 00:00:00 2001 From: josch Date: Mon, 16 Feb 2015 19:23:21 +0100 Subject: [PATCH] update tests handling --- src/tests/__init__.py | 100 +++++++++++++++++++++++++++++++- src/tests/output/CMYK.jpg.pdf | Bin 0 -> 5741 bytes src/tests/output/CMYK.tif.pdf | Bin 0 -> 1861 bytes src/tests/output/normal.jpg.pdf | Bin 0 -> 3228 bytes src/tests/output/normal.png.pdf | Bin 0 -> 1710 bytes 5 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/tests/output/CMYK.jpg.pdf create mode 100644 src/tests/output/CMYK.tif.pdf create mode 100644 src/tests/output/normal.jpg.pdf create mode 100644 src/tests/output/normal.png.pdf diff --git a/src/tests/__init__.py b/src/tests/__init__.py index 8fd6866..e3eb235 100644 --- a/src/tests/__init__.py +++ b/src/tests/__init__.py @@ -1,7 +1,103 @@ import unittest -import test_img2pdf + +import datetime +import os +import unittest +import img2pdf +import zlib +from PIL import Image + +HERE = os.path.dirname(__file__) + +#convert +set date:create +set date:modify -define png:exclude-chunk=time def test_suite(): + class TestImg2Pdf(unittest.TestCase): + pass + + for test_name in os.listdir(os.path.join(HERE, "input")): + inputf = os.path.join(HERE, "input", test_name) + if not os.path.isfile(inputf): + continue + outputf = os.path.join(HERE, "output", test_name+".pdf") + assert os.path.isfile(outputf) + def handle(self, f=inputf, out=outputf): + with open(f, "rb") as inf: + orig_imgdata = inf.read() + pdf = img2pdf.convert([f], nodate=True) + imgdata = b"" + instream = False + imgobj = False + colorspace = None + imgfilter = None + width = None + height = None + length = None + # ugly workaround to parse the created pdf + for line in pdf.split(b'\n'): + if instream: + if line == b"endstream": + break + else: + imgdata += line + b'\n' + else: + if imgobj and line == b"stream": + instream = True + elif b"/Subtype /Image" in line: + imgobj = True + elif b"/Width" in line: + width = int(line.split()[-1]) + elif b"/Height" in line: + height = int(line.split()[-1]) + elif b"/Length" in line: + length = int(line.split()[-1]) + elif b"/Filter" in line: + imgfilter = line.split()[-2] + elif b"/ColorSpace" in line: + colorspace = line.split()[-1] + # remove trailing \n + imgdata = imgdata[:-1] + # test if the length field is correct + self.assertEqual(len(imgdata), length) + # test if the filter is valid: + self.assertIn(imgfilter, [b"/DCTDecode", b"/JPXDecode", b"/FlateDecode"]) + # test if the colorspace is valid + self.assertIn(colorspace, [b"/DeviceGray", b"/DeviceRGB", b"/DeviceCMYK"]) + # test if the image has correct size + orig_img = Image.open(f) + self.assertEqual(width, orig_img.size[0]) + self.assertEqual(height, orig_img.size[1]) + # if the input file is a jpeg then it should've been copied + # verbatim into the PDF + if imgfilter in [b"/DCTDecode", b"/JPXDecode"]: + self.assertEqual(imgdata, orig_imgdata) + elif imgfilter == b"/FlateDecode": + # otherwise, the data is flate encoded and has to be equal to + # the pixel data of the input image + imgdata = zlib.decompress(imgdata) + if colorspace == b"/DeviceGray": + colorspace = 'L' + elif colorspace == b"/DeviceRGB": + colorspace = 'RGB' + elif colorspace == b"/DeviceCMYK": + colorspace = 'CMYK' + else: + raise Exception("invalid colorspace") + im = Image.frombytes(colorspace, (width, height), imgdata) + if orig_img.mode == '1': + orig_img = orig_img.convert("L") + elif orig_img.mode not in ("RGB", "L", "CMYK", "CMYK;I"): + orig_img = orig_img.convert("RGB") + self.assertEqual(im.tobytes(), orig_img.tobytes()) + im.close() + # lastly, make sure that the generated pdf matches bit by bit the + # expected pdf + with open(out, "rb") as outf: + out = outf.read() + self.assertEqual(pdf, out) + orig_img.close() + setattr(TestImg2Pdf, "test_%s"%test_name, handle) + return unittest.TestSuite(( - unittest.makeSuite(test_img2pdf.TestImg2Pdf), + unittest.makeSuite(TestImg2Pdf), )) diff --git a/src/tests/output/CMYK.jpg.pdf b/src/tests/output/CMYK.jpg.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e2f9380ca45b6f9e80f8b3e190237648ac10e65f GIT binary patch literal 5741 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
YAds*3(9ebI7w*qCiTs63-ghtZXFl(T zR;9;sMJ>s-tI17T@xw+|RQCIK91;tF-s^6u*f5q*!R2X}k8idee+ZiUzt`-K&2pK# z&Q6hsDx46(B9ET$?C_ks>4kY=I%rjKeoXe!NkQM*O3Rw^{OC%)@ON5tdV2h?RED`! zh13@j61&3QH;8OJTF($@sGX^LCXCPZNC^+SN}s>*t-^7wkND`8gPj7;jkgM%wtN;I zz$gAT*>=^@x}B%H)aD&iE&IbW5+(ZYK@E>anLRL_mxRu{m3mlAiX+G1kP+Mv7E{~C*xEg3IgVOHI zBt{*0USMvwd!W_SeiXwKrQCo$TT=W)OIAMd)J=DE>-0(QJ2t26WYZZVlceQ>FtTOM z&uP2-dQxJDwiZZlvUP_Zh7|h2&+SUl1$Lji?lE@F)!3zpBfo1! zw@>RSpWPZUb;b`5zbvXhnxFQ1zhPXTs`1|5LL(^ZDJ{>6#9HKE*>Gf7qJ zfJ3f&$y&$bN6GulQ_6B7&p#`NyQ-g7CZL_VRSmR0sk>>}`gEZ}m=_jYOEVP}Lw35y z-4N_A7f*3(2KP0nJvu2-q;zhu)mA2nOQE>irdkooy=d#h*q^ZW!0_138@zX^sEvB9e*`>t0~YN4=tHa{AO%`0a={0wwTiu_P{bAs{EzL6m_v&iey zF$W1fzEDXI;yFkLWZDHxvi~A_v|Q*E%Au~w&Ry{2XL*CXgMJXS2LFWsk&EsN%DZwc zE37UbNH zPH4s?kz^_cPZufLVqntTHg~0Mq{h;UeX!qcSZi}NIrSwqWRDC@rqZh*Lold|PprHr zITn6~%SQYQ00#8nVzKbDH01xjRwfV|Wx`zFsXZo>{jb)^bwAH>)fsHPS{v@7n8hLM zoD>(4)kKW?#BmWLP?UJ%7?X@K)N4mUPe%M?mBe6`rTWL3$1c8_P7}6f3^@2OvV^5- z(T4|eWp4=H&^d`5s!1n48j#ZuWhII-1!=yRAoB(fjuC*b`%chXVYK9Ei2^{+ZrL__c}~dX_VT?f|eO?*SK) zQ^aZe`72q1XF2C;b)u#Pzxv@6JA`qkyuWg4-AdcfNgX% zHwA^mV%4xHAJjj({ixqdsGxszIJUnH*`mX!Y5bc`O^w}e{4aLus{dw(Ro~C<1pjRp zO7o-ykZG{Lo5E&6K2+2O{y#loJ1Ujk>iuVKPl+P4Q~2HR^rVIU&IyafsKNH^F|sy> F{Ra)2SjqqZ literal 0 HcmV?d00001 diff --git a/src/tests/output/CMYK.tif.pdf b/src/tests/output/CMYK.tif.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2441e99c1d4fcdd1563796ed766f67ecb5fddf03 GIT binary patch literal 1861 zcmZWq2~bm46mCZw*>wACZ%{}kl`_8%V&wVH_g3CVa zejI=WF(8*34%*lNATrQi6b8fxO%Rl<1bkv6ArS3EfhiGO24H6gLL3?r0LWd`1D&{0 z92mqZgGekI9}EI<@-$$GdLl)BwKQ^<|EA%<5C`UirYjUYAR3F}$c;fVVvvc&n(fCR z12nZ%uBrpPC_E%mojV!gbE9}+h#-|bg+zZ(YB&@It78hB$i{$X|DGy`?CccORSQ~K z3b_I`0dk(|0uDeN2FwIaaflDVhj|c%4g3f!b4FOpr;54C3S$Fk`QZdE;0++FMQeqQ7qM<{-d+f>F{Dor%{8oL(&8r<& zK3dq&>v891Al2u>d}2rOVx7h_*+9+Q7HMyv=EtZM{o~g3u~AvOMedb7#xu{ab#6^? z9F%3UhZ^@x^=@&J)mAZQW?v9qO!kvjwaSuh8*}XPi%kU-d z?9oft4(se7(v!|*^oeiQE_L`u8`s$=g4 zG0HuV#M77FhS7cV^CZFNt}(X z4fE@s@_-K7#cSZyV`^#lw{s}v~TE10~&|l<6>^5nevMRH73%`~%S0DeAXo03Z z-aYpqJ5!oAF&zFUIsJ@ic1W;3xps(16!z7wF0j}TO{f;>>W&FMG-PJd@p0>ejV+7c zbXid*&JS#JbJ<~$lV;?nk_nv=~@4kD!IpzANt}JTItmL|r!NB`C%z)Xn zV}ZES|L_-Q1aY~Vu^9ySP(#hrAoBep{GcKDE+zQ${$#$=pVZo73=g6M7|;TccWUJT z&CSekW*{A0!SJAB3*@X|=14yIP{Xh|i_b6|4(X%+^D{O1%nxghMP9gNKbS{hML;}Y t`LQE%=v+|FU-j0Jxm@H4Td@zZ;vhtVqLEX0utF2o9ESr?C}&R>;2+CI;0*u( literal 0 HcmV?d00001 diff --git a/src/tests/output/normal.jpg.pdf b/src/tests/output/normal.jpg.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f5402f9828984f8195cf54b8d8d11faf2f8c7bf7 GIT binary patch literal 3228 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 CN@czP literal 0 HcmV?d00001 diff --git a/src/tests/output/normal.png.pdf b/src/tests/output/normal.png.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e1c13c460d9b40b7af382b44d6306479d4337e57 GIT binary patch literal 1710 zcmY!laB~UWtMsM3Z-BO0hz;f-%S#g;->Rz~&PWcr;6AggS(9l%R001yi`KAR#+Du+yQGJ|rkWK0xvS$eqX@@JY=}FUe3aF$SvPDlREX zP0Zyg{ z!xoV6b`6;Qec=1Th zOwT9*Itii{>V69&O9(%>G^qrf1Uz#=9tVdMBp{&S2oVa;Oab~D=uISVSIl`k%ig0X zP~up3&}V)8OAiz>oTH_7ih2eH z&*(@pWxYNF94t_neYR?E-0ZW< z!dADpxBsm9ci_N*6DLkQdGh4arAfyh@7%LzO^B9k$&JGrKAPqRfByX0vul@@0EdQa ziqXwy&(dt<($n|G%I4^ZIp5wCyzWG8S@;HVaq*y)BG)}sCT-oiwZLMIkJ|nF_q&fK zX-(~NQSw_}oRzgob{$8p(4|d$!ECFhoKEd^Yi9jgRckdjFQC4zZr`3gcdlQ*9(nt% z#E~_J4VO`Qyie^)b%nthYtJvZSY{XKNiz+ITbPTZPSwLsL&b%~-$nnwfG_4}X%) zjU2Pze?NWIf6=iaLMLv$`9zNm`{S;$8OrG>%|E|>{rd0Uznh1>c>8wl%$c0+hjZ3V z-|G0bxT3uLd4a{TW5+b^PrR7n^83&98);bqyJf?)rmkMS`t94?*=O7OIOO`jCvSUk z>f4VWKdN&s%O9C_80d^rj~>|Ni~Er8kCq+bUyQ z+r8VjfB*LF+KwOJzJ;y6`sk(BRIa((eR&^6Z3uNy68x31`|i68ldAgq|G$1k=}nK1 zi@U%p{`O33YwN4~oCSqCVy~yXE#rB$kTE#R+1Yvd^5t*VY>$kRyHd5ro_E*IorODN ztmgIwIBHGJ%gNdD;jQ`grlU5twyaEyyYJfB+xPRGKX}mbU;KsUpp_<4z0uLp2NO0t zjn9qX76YZ|hW|6{PXs)$!7K>O5Cs8J`BPDpn#N_IV9o_95+Ojr%+%D_R3S|PA!exn zmQu(=h?xP+0|6v4Lt}FcF=Jz3frX~d#0W#3p@|uix{{*A%$(FBE?BMNnU|KY0CGRH mQVGh>2i6q`esE@0D$ony5;L)=1neh66AL3QRaIAiH!c7;X>-E> literal 0 HcmV?d00001