From 41d126c4e6993a93c16e616715f1c9df34a4ce2a Mon Sep 17 00:00:00 2001 From: David Manthey Date: Fri, 27 Sep 2019 09:27:24 -0400 Subject: [PATCH 1/3] Handle different tiff orientations. For a Tiled TIFF that is not in the standard top-left orientation, this uses a less-efficient code path that may composite up to four tiles to get a conceptual tile at the location desired. This still needs tests. --- .../tiff/large_image_source_tiff/__init__.py | 8 +- .../large_image_source_tiff/tiff_reader.py | 136 +++++++++++++++--- 2 files changed, 124 insertions(+), 20 deletions(-) diff --git a/sources/tiff/large_image_source_tiff/__init__.py b/sources/tiff/large_image_source_tiff/__init__.py index 171f1d13b..4d2350e1a 100644 --- a/sources/tiff/large_image_source_tiff/__init__.py +++ b/sources/tiff/large_image_source_tiff/__init__.py @@ -185,9 +185,9 @@ def _addAssociatedImage(self, largeImagePath, directoryNum, mustBeTiled=False, t associated._pixelInfo['width'] <= 8192 and associated._pixelInfo['height'] <= 8192): image = associated._tiffFile.read_image() - # Optrascan scanners are store xml image descriptions in a - # "tiled image". Check if this is the case, and, if so, parse - # such data + # Optrascan scanners store xml image descriptions in a "tiled + # image". Check if this is the case, and, if so, parse such + # data if image.tobytes()[:6] == b'', 1)[0] + b'>', topImage) return @@ -262,7 +262,7 @@ def getTile(self, x, y, z, pilImageAllowed=False, sparseFallback=False, else: tile = self._tiffDirectories[z].getTile(x, y) format = 'JPEG' - if PIL and isinstance(tile, PIL.Image.Image): + if isinstance(tile, PIL.Image.Image): format = TILE_FORMAT_PIL return self._outputTile(tile, format, x, y, z, pilImageAllowed, **kwargs) diff --git a/sources/tiff/large_image_source_tiff/tiff_reader.py b/sources/tiff/large_image_source_tiff/tiff_reader.py index f87821f20..e3608f286 100644 --- a/sources/tiff/large_image_source_tiff/tiff_reader.py +++ b/sources/tiff/large_image_source_tiff/tiff_reader.py @@ -18,8 +18,10 @@ import ctypes import PIL.Image +import numpy import os import six +import threading from functools import partial from xml.etree import cElementTree @@ -122,6 +124,7 @@ def __init__(self, filePath, directoryNum, mustBeTiled=True): self._mustBeTiled = mustBeTiled self._tiffFile = None + self._tileLock = threading.RLock() self._open(filePath, directoryNum) self._loadMetadata() @@ -224,9 +227,18 @@ def _validate(self): # noqa 'Only greyscale (black is 0), RGB, and YCbCr photometric ' 'interpretation TIFF files are supported') - if self._tiffInfo.get('orientation') not in {None, libtiff_ctypes.ORIENTATION_TOPLEFT}: + if self._tiffInfo.get('orientation') not in { + libtiff_ctypes.ORIENTATION_TOPLEFT, + libtiff_ctypes.ORIENTATION_TOPRIGHT, + libtiff_ctypes.ORIENTATION_BOTRIGHT, + libtiff_ctypes.ORIENTATION_BOTLEFT, + libtiff_ctypes.ORIENTATION_LEFTTOP, + libtiff_ctypes.ORIENTATION_RIGHTTOP, + libtiff_ctypes.ORIENTATION_RIGHTBOT, + libtiff_ctypes.ORIENTATION_LEFTBOT, + None}: raise ValidationTiffException( - 'Only top-left orientation TIFF files are supported') + 'Unsupported TIFF orientation') if self._tiffInfo.get('compression') not in { libtiff_ctypes.COMPRESSION_NONE, @@ -277,6 +289,13 @@ def _loadMetadata(self): self._tileHeight = info.get('tilelength') self._imageWidth = info.get('imagewidth') self._imageHeight = info.get('imagelength') + if info.get('orientation') in { + libtiff_ctypes.ORIENTATION_LEFTTOP, + libtiff_ctypes.ORIENTATION_RIGHTTOP, + libtiff_ctypes.ORIENTATION_RIGHTBOT, + libtiff_ctypes.ORIENTATION_LEFTBOT}: + self._imageWidth, self._imageHeight = self._imageHeight, self._imageWidth + self._tileWidth, self._tileHeight = self._tileHeight, self._tileWidth self.parse_image_description(info.get('imagedescription', '')) # From TIFF specification, tag 0x128, 2 is inches, 3 is centimeters. units = {2: 25.4, 3: 10} @@ -291,10 +310,10 @@ def _loadMetadata(self): units.get(info.get('resolutionunit')) and info.get('yresolution') >= 100): self._pixelInfo['mm_y'] = units[info['resolutionunit']] / info['yresolution'] - if not self._pixelInfo.get('width') and info.get('imagewidth'): - self._pixelInfo['width'] = info['imagewidth'] - if not self._pixelInfo.get('height') and info.get('imagelength'): - self._pixelInfo['height'] = info['imagelength'] + if not self._pixelInfo.get('width') and self._imageWidth: + self._pixelInfo['width'] = self._imageWidth + if not self._pixelInfo.get('height') and self._imageHeight: + self._pixelInfo['height'] = self._imageHeight @methodcache(key=partial(strhash, '_getJpegTables')) def _getJpegTables(self): @@ -347,7 +366,7 @@ def _getJpegTables(self): tableData = tableBuffer[2:tableSize - 2] return tableData - def _toTileNum(self, x, y): + def _toTileNum(self, x, y, transpose=False): """ Get the internal tile number of a tile, from its row and column index. @@ -355,17 +374,25 @@ def _toTileNum(self, x, y): :type x: int :param y: The row index of the desired tile. :type y: int + :param transpose: If true, transpose width and height + :type tranpose: boolean :return: The internal tile number of the desired tile. :rtype int :raises: InvalidOperationTiffException """ # TIFFCheckTile and TIFFComputeTile require pixel coordinates - pixelX = int(x * self._tileWidth) - pixelY = int(y * self._tileHeight) - - if pixelX >= self._imageWidth or pixelY >= self._imageHeight: - raise InvalidOperationTiffException( - 'Tile x=%d, y=%d does not exist' % (x, y)) + if not transpose: + pixelX = int(x * self._tileWidth) + pixelY = int(y * self._tileHeight) + if pixelX >= self._imageWidth or pixelY >= self._imageHeight: + raise InvalidOperationTiffException( + 'Tile x=%d, y=%d does not exist' % (x, y)) + else: + pixelX = int(x * self._tileHeight) + pixelY = int(y * self._tileWidth) + if pixelX >= self._imageHeight or pixelY >= self._imageWidth: + raise InvalidOperationTiffException( + 'Tile x=%d, y=%d does not exist' % (x, y)) if libtiff_ctypes.libtiff.TIFFCheckTile( self._tiffFile, pixelX, pixelY, 0, 0) == 0: raise InvalidOperationTiffException( @@ -506,11 +533,13 @@ def _getUncompressedTile(self, tileNum): :rtype: PIL.Image :raises: IOTiffException """ - tileSize = libtiff_ctypes.libtiff.TIFFTileSize(self._tiffFile).value + with self._tileLock: + tileSize = libtiff_ctypes.libtiff.TIFFTileSize(self._tiffFile).value imageBuffer = ctypes.create_string_buffer(tileSize) - readSize = libtiff_ctypes.libtiff.TIFFReadEncodedTile( - self._tiffFile, tileNum, imageBuffer, tileSize) + with self._tileLock: + readSize = libtiff_ctypes.libtiff.TIFFReadEncodedTile( + self._tiffFile, tileNum, imageBuffer, tileSize) if readSize < tileSize: raise IOTiffException('Read an unexpected number of bytes from an encoded tile') if self._tiffInfo.get('samplesperpixel') == 1: @@ -524,6 +553,77 @@ def _getUncompressedTile(self, tileNum): image = PIL.Image.frombytes(mode, (self._tileWidth, self._tileHeight), imageBuffer) return image + def _getTileRotated(self, x, y): + """ + Get a tile from a rotated TIF. This composites uncompressed tiles as + necessary and then rotates the result. + + :param x: The column index of the desired tile. + :param y: The row index of the desired tile. + :return: either a buffer with a JPEG or a PIL image. + """ + x0 = x * self._tileWidth + x1 = x0 + self._tileWidth + y0 = y * self._tileHeight + y1 = y0 + self._tileHeight + iw, ih = self._imageWidth, self._imageHeight + tw, th = self._tileWidth, self._tileHeight + transpose = False + if self._tiffInfo.get('orientation') in { + libtiff_ctypes.ORIENTATION_LEFTTOP, + libtiff_ctypes.ORIENTATION_RIGHTTOP, + libtiff_ctypes.ORIENTATION_RIGHTBOT, + libtiff_ctypes.ORIENTATION_LEFTBOT}: + x0, x1, y0, y1 = y0, y1, x0, x1 + iw, ih = ih, iw + tw, th = th, tw + transpose = True + if self._tiffInfo.get('orientation') in { + libtiff_ctypes.ORIENTATION_TOPRIGHT, + libtiff_ctypes.ORIENTATION_BOTRIGHT, + libtiff_ctypes.ORIENTATION_RIGHTTOP, + libtiff_ctypes.ORIENTATION_RIGHTBOT}: + x0, x1 = iw - x1, iw - x0 + if self._tiffInfo.get('orientation') in { + libtiff_ctypes.ORIENTATION_BOTRIGHT, + libtiff_ctypes.ORIENTATION_BOTLEFT, + libtiff_ctypes.ORIENTATION_RIGHTBOT, + libtiff_ctypes.ORIENTATION_LEFTBOT}: + y0, y1 = ih - y1, ih - y0 + tx0 = x0 // tw + tx1 = (x1 - 1) // tw + ty0 = y0 // th + ty1 = (y1 - 1) // th + tile = None + for ty in range(max(0, ty0), max(0, ty1 + 1)): + for tx in range(max(0, tx0), max(0, tx1 + 1)): + subtile = self._getUncompressedTile(self._toTileNum(tx, ty, transpose)) + if not tile: + tile = PIL.Image.new(subtile.mode, (tw, th)) + tile.paste(subtile, (tx * tw - x0, ty * th - y0)) + if tile is None: + raise InvalidOperationTiffException( + 'Tile x=%d, y=%d does not exist' % (x, y)) + if self._tiffInfo.get('orientation') in { + libtiff_ctypes.ORIENTATION_BOTRIGHT, + libtiff_ctypes.ORIENTATION_BOTLEFT, + libtiff_ctypes.ORIENTATION_RIGHTBOT, + libtiff_ctypes.ORIENTATION_LEFTBOT}: + tile = tile.transpose(PIL.Image.FLIP_TOP_BOTTOM) + if self._tiffInfo.get('orientation') in { + libtiff_ctypes.ORIENTATION_TOPRIGHT, + libtiff_ctypes.ORIENTATION_BOTRIGHT, + libtiff_ctypes.ORIENTATION_RIGHTTOP, + libtiff_ctypes.ORIENTATION_RIGHTBOT}: + tile = tile.transpose(PIL.Image.FLIP_LEFT_RIGHT) + if self._tiffInfo.get('orientation') in { + libtiff_ctypes.ORIENTATION_LEFTTOP, + libtiff_ctypes.ORIENTATION_RIGHTTOP, + libtiff_ctypes.ORIENTATION_RIGHTBOT, + libtiff_ctypes.ORIENTATION_LEFTBOT}: + tile = tile.transpose(PIL.Image.TRANSPOSE) + return tile + @property def tileWidth(self): """ @@ -568,6 +668,10 @@ def getTile(self, x, y): :rtype: bytes :raises: InvalidOperationTiffException or IOTiffException """ + if self._tiffInfo.get('orientation') not in { + libtiff_ctypes.ORIENTATION_TOPLEFT, + None}: + return self._getTileRotated(x, y) # This raises an InvalidOperationTiffException if the tile doesn't exist tileNum = self._toTileNum(x, y) From 1cc9343ef3d1da9fff671fb5c4cde7ec8fec07be Mon Sep 17 00:00:00 2001 From: David Manthey Date: Fri, 11 Oct 2019 15:22:41 -0400 Subject: [PATCH 2/3] Add orientation tests. --- .../large_image_source_tiff/tiff_reader.py | 1 - test/test_files/test_orient0.tif | Bin 0 -> 7761 bytes test/test_files/test_orient1.tif | Bin 0 -> 7761 bytes test/test_files/test_orient2.tif | Bin 0 -> 7761 bytes test/test_files/test_orient3.tif | Bin 0 -> 7761 bytes test/test_files/test_orient4.tif | Bin 0 -> 7761 bytes test/test_files/test_orient5.tif | Bin 0 -> 7761 bytes test/test_files/test_orient6.tif | Bin 0 -> 7761 bytes test/test_files/test_orient7.tif | Bin 0 -> 7761 bytes test/test_files/test_orient8.tif | Bin 0 -> 7761 bytes test/test_source_tiff.py | 27 ++++++++++++++++++ 11 files changed, 27 insertions(+), 1 deletion(-) create mode 100755 test/test_files/test_orient0.tif create mode 100755 test/test_files/test_orient1.tif create mode 100755 test/test_files/test_orient2.tif create mode 100755 test/test_files/test_orient3.tif create mode 100755 test/test_files/test_orient4.tif create mode 100755 test/test_files/test_orient5.tif create mode 100755 test/test_files/test_orient6.tif create mode 100755 test/test_files/test_orient7.tif create mode 100755 test/test_files/test_orient8.tif diff --git a/sources/tiff/large_image_source_tiff/tiff_reader.py b/sources/tiff/large_image_source_tiff/tiff_reader.py index e3608f286..9bef36043 100644 --- a/sources/tiff/large_image_source_tiff/tiff_reader.py +++ b/sources/tiff/large_image_source_tiff/tiff_reader.py @@ -18,7 +18,6 @@ import ctypes import PIL.Image -import numpy import os import six import threading diff --git a/test/test_files/test_orient0.tif b/test/test_files/test_orient0.tif new file mode 100755 index 0000000000000000000000000000000000000000..ef20ecbcede731730edc5f3af62dd89d800e9ebd GIT binary patch literal 7761 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 literal 0 HcmV?d00001 diff --git a/test/test_files/test_orient2.tif b/test/test_files/test_orient2.tif new file mode 100755 index 0000000000000000000000000000000000000000..a114c60163aa376f679500f3b59e6d5a856bf1c2 GIT binary patch literal 7761 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 literal 0 HcmV?d00001 diff --git a/test/test_files/test_orient4.tif b/test/test_files/test_orient4.tif new file mode 100755 index 0000000000000000000000000000000000000000..b04b0b7171b91a7c887edeef1b84f13a73f2a67c GIT binary patch literal 7761 zcmeHLX;>83wmnROprR-cjo8j04kS?|B2p>>*YFH6MscpFQAAXpK?D^zDx)ZNaEMd1 zuVR8qw4+Q$3?-AOi6SO4sy!HkxlKzoLsL-Ir`~SVo4hZ7;r$VI-9;D^#E;DH&BR;kM4b>n_RW0!kOQ zW^^oxCxLYW=aqTr#1X1FPDIJ+jPkOGTA~&0pDQlZi^xYS(e;ZI9BCpwDkArzdM^<@ ziAg6z_lRhRMno0O_=l|6GMT|P8<)&huuE`TXoW zO*azaA)*7N5}ldEu+mXP6JYF{YKFPl)qF9Qu`49PV@J{eO=FEsT~0CxE1xvBPxIHp zPHckjxg_4Zs@=4LR@4ixl!<7PuZZ$Tib!!u-q@7lBEKr(JSUTPX7l0rK^E35Bjq_{ zYIaatyNJ5IE~4AB@zWbj+tbm!01m-gl3s8i`}@V-SG28FbX4OkE&gb%y@BAu-MD!_ z&0h>N@F_$@FcY!nUwIgFbr9^T+NF^j#~36YB-Eo}vxx5S{(`TQh%Bl^l>UQ=Zmlv% zsSe5Nf6Hrfh*ZW-qidy)^0et9GCywEFQO1!OP5jX#e#{#TX0n1hTY|c zRWHLS@_Lk6u}t?i{H>jrmJxHbXsP|3byUTe!OaDQ_2oa@|9ZmRSSE-ws{r?*HLb8| zm*Ci}sbw<$OPOIURcp=QOu~7N{X-62|*)!@(jNh>K_7qVpn(uOf~a39&=Dqr4ljcNWIboS%qP4)BYaTAt`# z3I|$rtE%9Ep2^!R`yi{y`_|)IdMUUSm%4~pL(t5y)kC-!FW`M~%iP%j7@4?m4t}zo zKvaZMtK}r+ETwi2<6OfGy{T$55%mn#+5;HPrGIRrw^8iINa644dhpTwRU)b^HpoJS z?W+MhGyELDnfGD3F}Qd_6tBlDC5&eT*G6s@R&9yORJ$d@%2n%N z34kf_VWdwOH`UudN~SIF7eh3)G)302Z~?=2LE!!$}>z0O}%d`c;f6J z5lufQ(OCov_8w$ceFMN=QlLHs@NjNA8GHtC^)pyXv;o%fBdMSb);UBL!NDRe{V{m( z`Y=8>3_Q3-&s=vfhBT$TMz!B`Gt_txLn+4lXZv=Il}tJJx|DnfKD!Bgmf1in9z%R| zwPW(eX3}GYh(0+fq6hnM<9&c1-+n<#Tfqr%z{SPzCG)g~Y5hV(!GPd{7XlaoghK$- zyD)7ZDEKx2AOP=|I%OxN8U0zV__t5rU+_Bz_yj9EX~`q3`rL4m>2S^DVX|>su=2D- zf|WpPxTLXmynZ*ER0xf^x%UMggrtMb`7iiO-V&7AAxXHe-Bu-TAXdupcQf@~^XC(MGcSb^nF%n#XI(xqd zgFq-0#6l=+6cNNi!a`Dpl@Ddy2oaSjxZ&juv~IFK+>q`?v-sNaiMk9e^(ZiP%hEIK z99ox=EQ}6Q(S3wb+-T(@C+eL7T~#pz(1TL7`8_f)bZfkV&AFHUY2D3cAIqn$ z_5`(pn*j}jt0-;hMxBw8yMFr8<`4*c8^bR;pjj_2pL!-F4*+6?_2qDsc!Z zblXX@y8$^um2z(8l@-cHt(^0@vO?7;;lhb4g`$$)y4TW}6_rFIgfJ+w+H0p! z7qTib@VYIRP)4i(4E@H7=;(NU8OXG0@NaJ*wnA&_$u-=(3a_O|vMVnlBMa?V99x9h zS=dNIrIgt-8hQel!K z<>0$lL^QPS22WB(8(}E9p3*qd?fDe>TMI4;m$mMa3lD&}hHs(Nlgc|vtH}Ct5$&BK z(G9FOEZ2z01IXdVASt&eoLm6ecQi{x-%I@k|4Aa64`TCHjfk53)5)+;MD+O*{6m9? z+J}Lw_qmNL$1%;Du#l$V%$_OVm-^N}q2#yof1Ao@W z<+*JJ?@oViPX*iOXZ8#ebJPu0ND#%U&UB; ze{o-KiqL)d{Q%q>;l3E|x1dksy4Ha02a~UZL2kl>k}8fiH}rdBd)f)BVbd=Z+P_=D4j;e#!yVnN9UNcjKVZa2XO~f~6Wk|yygA9! zXNIqz|KDc5HRrv#^Md9tSh(VYm8*hRhpY+T7_libYV(%3_=Loyk>QZ~d5n>Yk-+=!S8C={vHt?z>PDFOZJ*q5#J$C+BjQUtW z5o0a%KNqDbnK-Eb#Y*=@HUZ_mZ=G5llvd*#5wmjLh;PzPwQbTl9Hu^|jI7*!Wv3<+ zpNTS0K%N(>YzzacOaaO*lnSO_$g&X!L6+4STlWlZ005|%`;3{*A0`u;GxUHVr^XqZ`1K3}9#xtt{sT%LV%+ zeFfK78CFZ{R~z=1mB@F{c8tmyP;&G&h6Qw7rLe^7aFNp^NpH@q1VdgTqDKw~GJjO8 z(uE~NXaZaEt-Kn)*vxLuy<0rtxN&DXVcVDlcj7iA!O5u>0K-ne?<=?w^$o?m z3%TR%!Z8`qOSrj^{$~)oI?5(`+ygI!x>V)U|;SMuN6 z9PaheCx>oOnIh6TN`*doB#D-SgD;OzkOf9sg0n4r6+emKjK`ShyaaN;W0GGst!lC1 zUyrR|dQzeCZIlfa5*T-IVQFKr?e3+Hc{;q~sW9!-*C#^9KdJKYn3y*6^poc6<;ynI zFPwF#W+yT`9?ETnL$0Ul9qG2M6#t~v09#u)pLy&+v+tJkui4fO6VZYywL4CBkNqgx z9Qb}ZGzehUxWzxT=QKPOTShq&S7E5GT;C`RT{?x$J$kDA?-~WWn>#q4jr~gBeSJjK zG4iz<+iK>$`!sdK#AAc|qrMQYtP*o$4jP8lf$tIP32ua*EuvnQFvJafcS->To|g`T zJ#Ll!vSm=m37AHI(p&g14&E^T(vafaD|!XH{sPOZadG304mwE)Q8K;#`*~I+MI4HV zS-yFr*3V@`nw@IdafcyG5{D10Y63}Oc^lsz$2`^JwhB#$0mi<7Z;oMsQDQqvwuU=pf9U0K&@LeX>Q4K9HH*nHJTRWRh?dJ!F#EQG8(H3<;+>*H ztB8b4SBF8S#VrEI+84^$M9_USvE~IJJh$sKYH6v{tGvw|U2ww2S<~xp0)(e#pI%>3 z@o8DN};=IGj2EfcnP>=;uNL&Ak(j@g8>tLZu+d3Jsmhzi$ z;aij{2p6vrz>O0CGOTIRH;kJn)2%J&B>;QIhY|-5VJO8O#y3WCF(>fam@Lve&{{;- zeYA8ixd{~5_4I-LF%Ca@UBru8f`nUUuegnV81=^m)bGj0-<u6dnA_xCR(xl5cb=+r_8^at+)8~JcdQW@b z@8y^i+uz88m5z4^oJa{+NtM8*g+b0jlu#vl?K^d9X za`|e?n#(FG820VC9I0*8(PHnx6~b8e&%RRehM`S&|8Y}a8M5yDx%27AyAN`nH^ox$ z_949#P+PX_WY&~I4lw1Lb+Nn1eZZ{sVYPEePd~#&Z|J?yhxCt1S2=5kMe2sB{8G3*w4A{k3QKNj|E8Hr6s_BOjW-HAFl7So-DFI~FI5**(3gJ*UFg-T(kp z*hn>PRD989_{cU{)^TB-hL48Ty$yw8Aeti>h~@$VL{of(CtcR>yXdKeS{2BR%M%7p zVt47+8D!plg?@%atQyC;v&BkWgp*|5y`U1ob9eq7+#E#TkqVBFuElzC zsZi;@9UaUi=zRPEXd>0Ydq{UuwDb*br%FT(pebzevM5cdBs;KyImhMuldJbW*m};k z;j%%0!m|45l8oFYubqca`8f-p0O}A0R<_C7J;SQElIxZwfrk0Ht%d?z=!}gzWEKTF zq#BNFL6z!O3@~w5g~UIzqsLfzQo$~4{dJR_4f@Ee9)e>1<(#Ua1&*AT8N7eYJhZSQgx^4bFRNY`M$=^oltb z&U+huOIt8V=*`heNxZjt?!5vhQto*^Gfb&SEa-PPy1y#QeahQ(?Xg9(zw0}rV(q+; z8lPE1v*S%mf==U-H3~Mstz$6G1K~8Fyrv5BowE!iGFcLKqh&)+kn(mg;#zW7a-ph_ zj;C{gAjnAJeYkhYoD_X%P(U&h@A83wmnROprR-cjo8j04kS?|B2p>>*YFH6MscpFQAAXpK?D^zDx)ZNaEMd1 zuVR8qw4+Q$3?-AOi6SO4sy!HkxlKzoLsL-Ir`~SVo4hZ7;r$VI-9;D^#E;DH&BR;kM4b>n_RW0!kOQ zW^^oxCxLYW=aqTr#1X1FPDIJ+jPkOGTA~&0pDQlZi^xYS(e;ZI9BCpwDkArzdM^<@ ziAg6z_lRhRMno0O_=l|6GMT|P8<)&huuE`TXoW zO*azaA)*7N5}ldEu+mXP6JYF{YKFPl)qF9Qu`49PV@J{eO=FEsT~0CxE1xvBPxIHp zPHckjxg_4Zs@=4LR@4ixl!<7PuZZ$Tib!!u-q@7lBEKr(JSUTPX7l0rK^E35Bjq_{ zYIaatyNJ5IE~4AB@zWbj+tbm!01m-gl3s8i`}@V-SG28FbX4OkE&gb%y@BAu-MD!_ z&0h>N@F_$@FcY!nUwIgFbr9^T+NF^j#~36YB-Eo}vxx5S{(`TQh%Bl^l>UQ=Zmlv% zsSe5Nf6Hrfh*ZW-qidy)^0et9GCywEFQO1!OP5jX#e#{#TX0n1hTY|c zRWHLS@_Lk6u}t?i{H>jrmJxHbXsP|3byUTe!OaDQ_2oa@|9ZmRSSE-ws{r?*HLb8| zm*Ci}sbw<$OPOIURcp=QOu~7N{X-62|*)!@(jNh>K_7qVpn(uOf~a39&=Dqr4ljcNWIboS%qP4)BYaTAt`# z3I|$rtE%9Ep2^!R`yi{y`_|)IdMUUSm%4~pL(t5y)kC-!FW`M~%iP%j7@4?m4t}zo zKvaZMtK}r+ETwi2<6OfGy{T$55%mn#+5;HPrGIRrw^8iINa644dhpTwRU)b^HpoJS z?W+MhGyELDnfGD3F}Qd_6tBlDC5&eT*G6s@R&9yORJ$d@%2n%N z34kf_VWdwOH`UudN~SIF7eh3)G)302Z~?=2LE!!$}>z0O}%d`c;f6J z5lufQ(OCov_8w$ceFMN=QlLHs@NjNA8GHtC^)pyXv;o%fBdMSb);UBL!NDRe{V{m( z`Y=8>3_Q3-&s=vfhBT$TMz!B`Gt_txLn+4lXZv=Il}tJJx|DnfKD!Bgmf1in9z%R| zwPW(eX3}GYh(0+fq6hnM<9&c1-+n<#Tfqr%z{SPzCG)g~Y5hV(!GPd{7XlaoghK$- zyD)7ZDEKx2AOP=|I%OxN8U0zV__t5rU+_Bz_yj9EX~`q3`rL4m>2S^DVX|>su=2D- zf|WpPxTLXmynZ*ER0xf^x%UMggrtMb`7iiO-V&7AAxXHe-Bu-TAXdupcQf@~^XC(MGcSb^nF%n#XI(xqd zgFq-0#6l=+6cNNi!a`Dpl@Ddy2oaSjxZ&juv~IFK+>q`?v-sNaiMk9e^(ZiP%hEIK z99ox=EQ}6Q(S3wb+-T(@C+eL7T~#pz(1TL7`8_f)bZfkV&AFHUY2D3cAIqn$ z_5`(pn*j}jt0-;hMxBw8yMFr8<`4*c8^bR;pjj_2pL!-F4*+6?_2qDsc!Z zblXX@y8$^um2z(8l@-cHt(^0@vO?7;;lhb4g`$$)y4TW}6_rFIgfJ+w+H0p! z7qTib@VYIRP)4i(4E@H7=;(NU8OXG0@NaJ*wnA&_$u-=(3a_O|vMVnlBMa?V99x9h zS=dNIrIgt-8hQel!K z<>0$lL^QPS22WB(8(}E9p3*qd?fDe>TMI4;m$mMa3lD&}hHs(Nlgc|vtH}Ct5$&BK z(G9FOEZ2z01IXdVASt&eoLm6ecQi{x-%I@k|4Aa64`TCHjfk53)5)+;MD+O*{6m9? z+J}Lw_qmNL$1%;Du#l$V%$_OVm-^N}q2#yof1Ao@W z<+*JJ?@oViPX*iOXZ8#ebJPu0ND#%U&UB; ze{o-KiqL)d{Q%q>;l3E|x1dksy4Ha0XO2)E40015jC_{;)FB_(ihq5Xnwprv$Her- z^^;{PmLLgisKv8hV64u|#MI2(qMM~vcWWDHkki|^%VwtLW)>FaFb$I!_#K(|v9KHR z`m}C+XD_oHx}o12+tW^14V!+U(Ei;DcKG<^AMWUG?cn%I{{bULI=hT=o!~yvx+w&oQ=**`*3n4nGlV1s}7&QE2778>F568@GvY%=&Rl;&6ySAbOf*3{O;o6&5O$1 zWI!jsZGWmXr00gtth1PE3#U4&akhP|h(H?{bBDjOlRM$W3e=b702p=xeqX_jsBb9d zUC1487mmq@Uc$|V^gn~x)loLlBkx@aIN<}7SFY`;3s(EZ>7CZs8tmF46Qh@%ypsRk z=5Vi%J~?!Q$`p~#Q7ZJwBT2Lr9DI3%f-Er75}a+}tN2L-XFSG4=OvK)9h3aBX;q62 z|9Wf%(~}C7Z=-CekifWu3rib|ZFetq%+ui=PlaixzCIB;{z;XG$HcUmr=K)mFJHEy ze&MV`H9L{n@lb9n9CAHX??|_8rT8bU2H4ud`OISnntivNf6caTn1~issoin1d+bNi z=D_#Up+Nw%#x4G#J*VNR*fPqIxC%pc<@!cp=+Y@{?$J}_f7dA3-Q2 zj*+j`*j6*|-KVJ=CLSByAN7TJWtEs4bI>rX4t$STPjDmjY!UUcgduL=yHg4%@Vs;w z>~X8)mo0-jPQWz!litFAaqx!umxdJYUePPq^%q!Pjf)$1bkIpch?42;-_NruDdJE> z%<|0}wSF!m((F{rjynulk~n-|RTD@O%iH+&IOeGyw^e953^4Wud~*z={8XlYUy|!j zvg9ReAd28i%Q^QlW2K}AWGUZ3D!+`}nadj>QDI>M{|DW?41){0M3cWdTB@jZiXF#Y z4WClWMO53U-^h+Tp)xpMQ%LYCTPb7V<#aYGS2Ozpd;X|emLju`UZA9H*9;n2P|=df z=To-DnVQ_aOTP|Xu{GQ&`$I2>gLVlCPQAe=?@6&8R*d98|Z5y+)XQZkiP1Tr!t)pqRh#dSMNs}())N!9xZVYoQO`rc&>OJj! zznk~xXLU=R)Kl@6>8-_OB{l`sxWyreo=gy}e?>@+R-V{s0 z+lTa0KyBHwlUY*=Ilz=}*2V53_W`rkhtE+8hFNiDh^w*x@C;6xX+E~k!jeKbS))4LRW9gSy?^v8LX7}`}_M8e|djkMa zVI$SFQSn8a;Un8*S;vKS8a^6U_cj!YfoP6kAesvd5KZwBo^)Bi@1my?YE>XNE>9RZ ziQT1NXOMaK75W(xv1%OW&K4_i5l)hI_kv1b4}ab-DvQ|R#HH4(!*&&85|u>kj@gz} z)I=TB7TA9~AycNcdGl^%vz7|U^G%sycAruYk#mzWNtzBS&)xZVaB~oSM=Cfzx)$rn zr9!3qc62b8p!4wupovrm?;+hu(b6}#ohlJEfTpm;%c3-;lI*|+<{X#rPp;nkVCy;C zhRX*13CrrIOEPksymlTw<>xGX0;oe2SlK3P_YAAvO0HX$1RCb&wi*g>p))q>kXaPy zkZL%x1y!nBF~G!K6%zlNd>#Gk@N5&)@hFdlf0)GKBrdEoU6B7ElD`;crSX0 zYLZuCGpDoG_bG4FwZ|6C{;uzgina4X zYJ6r5&5k!M2|A5S)+pEjw~oO$4}{Zz@|r5hcg`}9$Ye>_jg}2PLCV{~h-=AR$%U#y zI-bq}f*>P>_u&Sr%Ifx)x`3;cMN6RRe5evJTq~Qe{y58!e})UxZ>wyz3G*m^XmxK{ z4)1+1qM%9ra8mT4K>^83yyyQWh_2aT(9hUm?C)d;Bg_0+m0_^cPwe0V_8(yfW8Xfn hJYxr=Z4K%83wC%7`ZQiIDhmI+SBw8)gO{83wmnROprR-cjo8j04kS?|B2p>>*YFH6MscpFQAAXpK?D^zDx)ZNaEMd1 zuVR8qw4+Q$3?-AOi6SO4sy!HkxlKzoLsL-Ir`~SVo4hZ7;r$VI-9;D^#E;DH&BR;kM4b>n_RW0!kOQ zW^^oxCxLYW=aqTr#1X1FPDIJ+jPkOGTA~&0pDQlZi^xYS(e;ZI9BCpwDkArzdM^<@ ziAg6z_lRhRMno0O_=l|6GMT|P8<)&huuE`TXoW zO*azaA)*7N5}ldEu+mXP6JYF{YKFPl)qF9Qu`49PV@J{eO=FEsT~0CxE1xvBPxIHp zPHckjxg_4Zs@=4LR@4ixl!<7PuZZ$Tib!!u-q@7lBEKr(JSUTPX7l0rK^E35Bjq_{ zYIaatyNJ5IE~4AB@zWbj+tbm!01m-gl3s8i`}@V-SG28FbX4OkE&gb%y@BAu-MD!_ z&0h>N@F_$@FcY!nUwIgFbr9^T+NF^j#~36YB-Eo}vxx5S{(`TQh%Bl^l>UQ=Zmlv% zsSe5Nf6Hrfh*ZW-qidy)^0et9GCywEFQO1!OP5jX#e#{#TX0n1hTY|c zRWHLS@_Lk6u}t?i{H>jrmJxHbXsP|3byUTe!OaDQ_2oa@|9ZmRSSE-ws{r?*HLb8| zm*Ci}sbw<$OPOIURcp=QOu~7N{X-62|*)!@(jNh>K_7qVpn(uOf~a39&=Dqr4ljcNWIboS%qP4)BYaTAt`# z3I|$rtE%9Ep2^!R`yi{y`_|)IdMUUSm%4~pL(t5y)kC-!FW`M~%iP%j7@4?m4t}zo zKvaZMtK}r+ETwi2<6OfGy{T$55%mn#+5;HPrGIRrw^8iINa644dhpTwRU)b^HpoJS z?W+MhGyELDnfGD3F}Qd_6tBlDC5&eT*G6s@R&9yORJ$d@%2n%N z34kf_VWdwOH`UudN~SIF7eh3)G)302Z~?=2LE!!$}>z0O}%d`c;f6J z5lufQ(OCov_8w$ceFMN=QlLHs@NjNA8GHtC^)pyXv;o%fBdMSb);UBL!NDRe{V{m( z`Y=8>3_Q3-&s=vfhBT$TMz!B`Gt_txLn+4lXZv=Il}tJJx|DnfKD!Bgmf1in9z%R| zwPW(eX3}GYh(0+fq6hnM<9&c1-+n<#Tfqr%z{SPzCG)g~Y5hV(!GPd{7XlaoghK$- zyD)7ZDEKx2AOP=|I%OxN8U0zV__t5rU+_Bz_yj9EX~`q3`rL4m>2S^DVX|>su=2D- zf|WpPxTLXmynZ*ER0xf^x%UMggrtMb`7iiO-V&7AAxXHe-Bu-TAXdupcQf@~^XC(MGcSb^nF%n#XI(xqd zgFq-0#6l=+6cNNi!a`Dpl@Ddy2oaSjxZ&juv~IFK+>q`?v-sNaiMk9e^(ZiP%hEIK z99ox=EQ}6Q(S3wb+-T(@C+eL7T~#pz(1TL7`8_f)bZfkV&AFHUY2D3cAIqn$ z_5`(pn*j}jt0-;hMxBw8yMFr8<`4*c8^bR;pjj_2pL!-F4*+6?_2qDsc!Z zblXX@y8$^um2z(8l@-cHt(^0@vO?7;;lhb4g`$$)y4TW}6_rFIgfJ+w+H0p! z7qTib@VYIRP)4i(4E@H7=;(NU8OXG0@NaJ*wnA&_$u-=(3a_O|vMVnlBMa?V99x9h zS=dNIrIgt-8hQel!K z<>0$lL^QPS22WB(8(}E9p3*qd?fDe>TMI4;m$mMa3lD&}hHs(Nlgc|vtH}Ct5$&BK z(G9FOEZ2z01IXdVASt&eoLm6ecQi{x-%I@k|4Aa64`TCHjfk53)5)+;MD+O*{6m9? z+J}Lw_qmNL$1%;Du#l$V%$_OVm-^N}q2#yo;Ivx3+->IlYa$Y-Vb1W?^9t(=dsF-;sGA3%en& zPwUoq_A<+%8~VMmJ?(_mu;~{H?cc3nhmT+W;g0Us4vw$%A24F1v&$&g3GNd;-kjv= zGsD-<|8Fzjn)BY=c|r3REL`!y%2mOuL)L_EjMx+zwRuZid_rPU^3IgK`}QCB_~4<# zM^2`n`t-Am(`U|J%*xKm&AasF<)Y$}(rabcZ`{25?RWPotEy{iRq99IKmMWq$&dfg zH8r=i>f5;Xj+X_%W1s^%b*a7K2r-HNZ@~YE3@&aS8+cU`Cn7uI9#s~=9y@<5Mtv-x zh_M#>pNrCzOdQnzVx{{cn}G7(w@$4NN~`gWh*`OA#5ZZD+BWGN4pSdfMpo{=vQv|Z z&qSFgAkPa`HiiLJrU2y@N(Iv|WZ8&=Aj|5Et$PMH0030Xea6h@kY@oi12+OSAHyB4 zrvXjwG0KnWmZ>6wq)Tv@WywY4J2zH}3tyv@D!Q5>*0*$Rr6S6bHT=ky>18aPdc~2A zqq(ZHYh(k2{%l6^ar;ZGJjpAB717na+L(m4?Xm7rd!H_eX~oGM1Jis*?4EaPUFfF9 zO?ywhRxappVY94xmz@7fW@y<$7|;YXkTy3e*l@^Fn+71H(G6fq1~9aUR+e*v<$`^Z zzJlwk46CK}s}1|hO5{6eJ4WRUC^`BX!vZ?4Qdr`3xX9^|q&H_)f*~&v(IbZgnLjF4 z>B15sG=VMoR$h%?Y-Ts--YuSR+_*EHux(6&J8>J5;AB@y?IE?@~|=E8l2hT4T1({r`)Yz-worO!?dls$Vaqx7yl+Ml5s25(i*ceh0R8{ zzPL!q+33u)4<}cW3DHQm>hKA?B6=*Be(oO*55tm#zUr;goLM1GNARl6?=BwRyr|4g z26Xb<_NPiidT!{l2~lpHz8xOiY`3`bqQk@?{(9 z7tT6VvlE#e59PMPA=gv&j&$2riht5-fUPZ@&pdXZ*>}tN*KF&CiD*HU+8rmm$9@!T z4tzfy8U!$F+~ObFa~htCEu$QXt1whou5T2EE}g>W9z9k5ca4JG%^jT2#(t&mzCI%A z82MU_Z8h`WeVV#q;<3T~QD2BxR*AVW2MxpO!1svt1UEv@7Ev!t7~%%LJEedE&r65F z9=A$<*)pi(1Wcnp=`H*h2XB~vX-M(z6}^I8e}U!IxVUjg2c0B@D4E{={XDCZA`V5w zEZ@9Q>*q2e%}%xKxWkYoiNgn0HGw3typ3;0ApXkH^(r_Pi6Y|CAt12 zOJ1@Dq6ogUoO3TTR!Vw6mhugx^2^Abxx4`q6&5D&f6&d#Fu0&gH2JHerHWdo*m2y| z@F}%iM753jjqJD+DueSig#@p%l`&7hG56)l;3 zK4n{+sma~D^y|bi z__Vg+O5UYCZl30Q)bw}OP`BDfao*u%17Kz(D98dSq^*BNX_ESlb+AySZJmr*OZiQ> z@GVLegp1b*;Km668P+uE8^+C(>DCtX5`aD9Ly3cjFqC2s;~OKnm=kzyOcv=KXf2}a zK3Y1M+yn}2^5SKam9TDO>E{<8DB^*3B*?r|=NYx&3mxfYG@t9Ug<$^~I?~kfCmm@G z_8-xaAob7yc-N>SjkX=wFSO%Ou-_i|OYInMflxd&cJ75xX5Y@r_GQuzy{EnJ zck}-ItZu2(dMGA_(^Bug(91)J^~&Q@*u2E(2xVY(9=x0C)%Q`L?URRN*vQ?{pp49G zxqLNc&1Dr84Ey$6j?^~lXtDR;3Sq4KXJ4s!!_cO?|G25I3|V*n-1+q5-3K|(n_?+= z`;cA=s4ZJ|GHXg92bl8By4YRhK48}Ru-ZAKr=Q`XH}qcUL;6RhtDLpNB6Y)5eyL}; z$)FG|y?j~c1#v~5{@OGABp+2k8*7=ekq^z^8loM3EdBE89g7pj?4DlLo>Sp#ZvX%) zY^0htD!ynld}Ny}>$tE^!$-sF-iAUk5X}(`M00@wqA5PYlP>G`UG!8!tqSDE0vPz9}=z?o;X^a&A&4Nz*~)xjX+3ZVsaFNCn47*J3@n zRH$^{jt=G$bUyw7G?D7yJ)}D+TKWdJQzfDX&=j_KS(K(!k{#H=-r7ajF^yX-#B;MOR_g;Y$Dfc{|8KzVu7WBIt-Cq^uKILt?_SmA?-}RkQv36ca zjnAy1+3}_&L8o!a8U-8R)-f38fp8j7UQ-46&RGT$nJfvr(Xyc@NO?OLaV@zkxlmO| z$J04L5M-qAKHNZ6S>66p7jTubXbCi(4^<+DYi0A*A7>fz&v1eIZI!JyVIIW~t?n($ z;k^$=6f~(HPKrJ>C?J`M_x#@k(KR~^`WZWn{hjP!WSL*9G7NV5i5*^|AAfku`v3p{ literal 0 HcmV?d00001 diff --git a/test/test_files/test_orient7.tif b/test/test_files/test_orient7.tif new file mode 100755 index 0000000000000000000000000000000000000000..e0cc68b5a81dc7f91d5456b2c68e183118a7197c GIT binary patch literal 7761 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 literal 0 HcmV?d00001 diff --git a/test/test_files/test_orient8.tif b/test/test_files/test_orient8.tif new file mode 100755 index 0000000000000000000000000000000000000000..848e749311787fa4d597367a38f61b3d4091a13d GIT binary patch literal 7761 zcmeHLX;>83wmnROprR-cjo8j04kS?|5~Nf_uHhMCjN)8TBZ#Oxg9s{cR7O$k;1H*1 zU&REKXh)fh7)mBl6Gcpz)gFw&+@__Pp(&{9Q*SrwjqgkJCb@a}-j7>fH?^rgb;iBd zT6@o&>55uy5E5&|E6BzQO+iykO!^?P4q2I)AVeWTTu!9GXLPeAv8m)|3mXkP8RcF@ zPO#REpAgkR?B!P#i42=gsjPK!VVHL>omB58jHI$JYqX-{3&r^c5&38(x_*&@BTb}7MC5)%?0nwGFe}PQQk{tCGlGeT;?kLi7Lq&rF2X8U5M zG!}`dutL$iU0Q#HXkjjkZ1pknW{VRHW|WB(>m%V}B!au6u+mW&A8h=La_cxjvlkiF z1Q8{aipVCMoM}kFs)6JdJXj#201>Sr_e6Anz96ELu_D4HJ#gDTTDTJ?qR}aox*OGb z!;OS^h-iPQL}w;3taKF71Q`2VcLZUz~o zRHtOszvVSKL@Hya(sj}YdD?UlnIALk6Hy4Rqsu7vLcv7gZ8$1$!|w7_tm@B3#xc2! zs+Zv;c|FRkSf+ai{?^S)%ZNErwAB9gTB>5q;Ff~IhVmcpely`tEEC9?Re<}@nl{+9 zi*Rh#)G`_WmCUe)scshwJI; zCc*B39y&`3B}LebS}x-jQtTy4ZRaTTB89)F>%m9!gG5wSY><+xhmk&E+!Sy7D4DjvPZ&LRi&hcJ+aA#8Q^U00A1ZD^D}6H1&b4;EA&X zMKtZKL}w8o*n5zj4UGVMNdfv4z{9!eWbkRg)z4um(FRz@Po#o2SmzK~1P6<>^uyr6 z>%#clF!117J#)>$7}AvTD%Ekr%~0z>45b+Fo9+8ztYpf$*QMkm@Y#*vv&?#0@etzU zMLQ;MY9T#Vi0IQ3BD%L1H{AvJ@$DC=v=y8H2V7hXUonqsnYJ%Q6buMHcp-ohKsW?I zgA3FCp@MG*00QuSsZ(}Qn$e%-ihuj`{e&530iR%HCoFk{RbLoRFrBWMJWMujGgh9G zNU#!U4VN_4jo0sDlM10RS6_&;MU?7o9kQ7&oMm?P*g*DdSwi$AHbW`j{Y6C2X=P<} zZ?Bn=Zpo5BPI}I7%z1_HnyRYYiQ|$YSPB+;QJ4I+YANLWb9u=2i)8zG`H1vk9Bk=DJX4>zQH(Ja1tY@#khOFalk-MsWP zJBQX~BnzX%RCFI<6gOJA$ccKlKv!K10d%iaZC*(RhVJq2xABeou{o9LpVi-J@v(f| zW=~KXxEatexQf!2ZqgYk`NdCPdfa~w2I2qT6q~}@)=Bk?xxV}=p}VfUv4Z#KUL_8J zg>E}&b{8N=s8Y_&yu3o$q?L0%mshBoBwRRgrBGDT+m)?NSy6dKmwGBXM+k!=YrJ*{ z^&vrt0oQD~gfe0UU^rvEh>ncsmw`;13jg*7Vk@+!9$m#PL3j;Cl3jTb8Chui;@Be0 z&ca3#Dy7Vx(9k2mEN9|C3yT%I=st`Jd?q0r_%%`(!Zgo|9jsw$LbmhT20oKi)hbe ziEdznVYx;`9zYJ)2T8fz;p9BXz9U&8`a$X^_)QYgd=Q&AYem%TmrjO#Dxxoz;2#@B z)G-WPz0WONHI8Z7h=nu_XZA$-zSOt=2_?UsFMn>?B?SJ8l~uEr#`u9)5^GT(giOp3 zsCyIzUz4YHHrS?5Z7Z2q2787%LiI4n4R|o}N%m8Zd|)g7^<`>mVger%(`VPu zmZ?~RB(R|tPkMo|x-Jt_Gjoe>mR8-ZZJ+WA8J_bS-oE`#j^+=`$CyvU76tE`D{XsJNu`YT32xH|~7*ePva3O>Lb@{osd(KQ=u2=^wi0 zmew|XJJ-?qvH*ApbU>#rwKp6lCei;5_#ctM#m!>_u1MlUWJlbi%KX`*=Z?mxkNOue z)J!Sy%H3CXX)^JN zDDwp5d8W$7Frdm5pxi>KVEUOX8*u<+S-r7!&)`M?fQq?KnAsfiEMR8fMxf@SxYP9% zph+d8{Df|uA|gn-1b11MTtvQeW2Lz8HA<mIe|@sgM}oZLAu&3DAEc{kUFZfx4P z=j3bUf({q9$Xa&F`LAV$*3E-IRN$c)~H`&UC@HF$wO%ZAgNXT`9Gr#F%ltQcl*C8#As73qN7n zgQpo+e?ZDZ#*AxlW~Vm@8kn7Omx6sSjB^gtw&@}t(Au5+o482EtyD{E&B_!u8{GQh zA|+>|Gt=IGtBOpBM!KLw$MK5jv0VDue>mI^OA`93w@7nlg*Y9?L7U!NJiKL5nVSsg zo- z?d`%b8PQ9)xsd*65W9NHCVFJ$W&h(oKzZfbp1NT5j5xj1x;lehdt_qtvJ;o{-`^DO z_3@_%uTz;K(m6_nK6xaGmV$#Xk5G^WMp}ZiEqoO}ir|dLnCQF&a=)XJUpB37wc%fn ztzddmq4KSi4HXg)cVJ;@Q?c!?rH*+zy#28-_2f6lL&ra=_VAdPHuKb@mTTq9);BDi zb+C2^GCLN^ZGl5>pc)+M_AM0usLcRdTR5M2=s>gYmGiIJ)(;cWf@-xpPIiy|INBWe zei}6JXI8t#-?!&9JQZ6;ITBZ4sIFY!Bn(|Tnaw?Nvi$EF1-pwoFrSV6THk$LMAT98 zjT+l(=Dqhgb^XMngZrbt5U;Efb7Kw|hSh`b5$g$Vgq|&;UY0P#b$n-X0R^6y4ud^x zll-z}VCQj|Mt{;<_%9CLF#pPs;@vBH1-tG%%d2s5)Amj}NeEFgz5V)mRwqRqjEGsj zX@ho#%ZM~P)v{v_LzW~CA6VTClEm^BzBP_{tjFyYnoa|ZeIDN!!ze$K=|7O<`jISo z$!drq_|kIDz06oC=>b{Fw~)#&Be&=B21ry`n85!*H!s8Bf)}F6UmY#g)LO;%W3GnJ zsO2K6YtnCE#~oK0oUbY*ILKDYSa>;|iOSW?KF^*zqL!t|tfLnwY1`Fb1chAyqLRV}Fcgp_A%i(}sLITvC_Wo)XlViANJarK*m#1L%9R)YCyivtFMTb@s z374)8gG`HC1dg>gl(C7R`)Fd#3qW{o(`nSwQm0pWn>o7RgblN%HQWFQPt88HuAt(x zy2i_S7k9gPn(tQA-&;f7YAeNghm-YynUSC%3#5>?{uQN3>NnQGLY21lGGZ;|H{!y# zDODgYUM+wdCjewv)1+@0H&3QpQ_xEQ_KXiD4j#f#iams{kK|&G<25l^q<4U|h_3l) z>0ojLD6rX!m%XKgbsI}RzxY5A540me=3P3^s0E+tNH3%LRG%#b`_Iskrj9@BNNceF zh>irQhX%mAMjdIi?ZAGf9fyMb&cI)4$9M~b;-Rr~FN8Atc2&mzqYeL%HsqzG7r?;w z?_=-Mtbf>UI?HV4+3l--5IBw2Sas08-#<7Y%=5j&i?)S7kJreaK@l8D_=+medf zr~}#p`|l=X%Ct6b-l=NQQXzT1DbvmFQtBacZc-*m(?R9AJO3_j38ZgJ1;+xq&q2E`UbZ{C89>q6t;L-l%`aY9ni>}^qiQLIWlMSfvQ|OTiC8wDu(V)OLk3PW#2iL1$S$Q^PUo0F0%l=V$Oy0 z-bUZj77P-4bF@+t?`@u2S>Qybm5AZm*nIUTS%&=6T!4OSRhvziNAZ2D%4Ipc z_koClX7&9^(FX_lCo}P$|C=CQ%npN|V~4T7lO2pK^J`Ux!A?K3gA3SygdL21`@Hgm f9gMa$q~p)n;Wg;fcs;8q{PSKT{)Y`-#s>cbvqa1P literal 0 HcmV?d00001 diff --git a/test/test_source_tiff.py b/test/test_source_tiff.py index f39131774..1a8575ee4 100644 --- a/test/test_source_tiff.py +++ b/test/test_source_tiff.py @@ -468,3 +468,30 @@ def testTilesFromSCN(): assert tileMetadata['levels'] == 5 assert tileMetadata['magnification'] == 20 utilities.checkTilesZXY(source, tileMetadata) + + +def testOrientations(): + testDir = os.path.dirname(os.path.realpath(__file__)) + testResults = { + 0: {'shape': (100, 66, 4), 'pixels': (0, 0, 0, 255, 0, 255, 0, 255)}, + 1: {'shape': (100, 66, 4), 'pixels': (0, 0, 0, 255, 0, 255, 0, 255)}, + 2: {'shape': (100, 66, 4), 'pixels': (0, 0, 133, 0, 0, 255, 255, 0)}, + 3: {'shape': (100, 66, 4), 'pixels': (255, 0, 143, 0, 255, 0, 0, 0)}, + 4: {'shape': (100, 66, 4), 'pixels': (0, 255, 0, 255, 255, 0, 0, 0)}, + 5: {'shape': (66, 100, 4), 'pixels': (0, 0, 0, 255, 0, 255, 0, 255)}, + 6: {'shape': (66, 100, 4), 'pixels': (0, 255, 0, 255, 141, 0, 0, 0)}, + 7: {'shape': (66, 100, 4), 'pixels': (255, 0, 255, 0, 143, 0, 0, 0)}, + 8: {'shape': (66, 100, 4), 'pixels': (0, 0, 255, 0, 0, 255, 255, 0)}, + } + for orient in range(9): + imagePath = os.path.join(testDir, 'test_files', 'test_orient%d.tif' % orient) + source = large_image_source_tiff.TiffFileTileSource(imagePath) + image, _ = source.getRegion( + output={'maxWidth': 100, 'maxHeight': 100}, format=constants.TILE_FORMAT_NUMPY) + assert image.shape == testResults[orient]['shape'] + assert ( + image[11][11][0], image[11][-11][0], + image[image.shape[0] // 2][11][0], image[image.shape[0] // 2][-11][0], + image[11][image.shape[1] // 2][0], image[-11][image.shape[1] // 2][0], + image[-11][11][0], image[-11][-11][0] + ) == testResults[orient]['pixels'] From 165ae45c235f4a38d4e2658a8938ecdceffce588 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Thu, 24 Oct 2019 11:52:10 -0400 Subject: [PATCH 3/3] Add a test for multiple tiled images. --- test/data/JK-kidney_H3_4C_1-500sec.tif.sha512 | 1 + test/test_source_tiff.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100755 test/data/JK-kidney_H3_4C_1-500sec.tif.sha512 diff --git a/test/data/JK-kidney_H3_4C_1-500sec.tif.sha512 b/test/data/JK-kidney_H3_4C_1-500sec.tif.sha512 new file mode 100755 index 000000000..5762877eb --- /dev/null +++ b/test/data/JK-kidney_H3_4C_1-500sec.tif.sha512 @@ -0,0 +1 @@ +9d94deb45acd1af86dedd26e261e788bad6364e0243712cd9ac37ad6862b3ec7db1554bf9392b88dc2748a1d2147baaf1a8b00d5ab39c04aa1dfbc4218362550 diff --git a/test/test_source_tiff.py b/test/test_source_tiff.py index 1a8575ee4..42cc1e391 100644 --- a/test/test_source_tiff.py +++ b/test/test_source_tiff.py @@ -495,3 +495,16 @@ def testOrientations(): image[11][image.shape[1] // 2][0], image[-11][image.shape[1] // 2][0], image[-11][11][0], image[-11][-11][0] ) == testResults[orient]['pixels'] + + +def testTilesFromMultipleTiledTIF(): + imagePath = utilities.externaldata('data//JK-kidney_H3_4C_1-500sec.tif.sha512') + source = large_image_source_tiff.TiffFileTileSource(imagePath) + tileMetadata = source.getMetadata() + assert tileMetadata['tileWidth'] == 256 + assert tileMetadata['tileHeight'] == 256 + assert tileMetadata['sizeX'] == 16384 + assert tileMetadata['sizeY'] == 14848 + assert tileMetadata['levels'] == 7 + assert tileMetadata['magnification'] == 40 + utilities.checkTilesZXY(source, tileMetadata)