@@ -962,13 +962,16 @@ def tobytes(self, offset: int = 0) -> bytes:
962962 result = self ._pack ("Q" if self ._bigtiff else "H" , len (self ._tags_v2 ))
963963
964964 entries : list [tuple [int , int , int , bytes , bytes ]] = []
965- offset += len (result ) + len (self ._tags_v2 ) * (20 if self ._bigtiff else 12 ) + 4
965+
966+ fmt = "Q" if self ._bigtiff else "L"
967+ fmt_size = 8 if self ._bigtiff else 4
968+ offset += (
969+ len (result ) + len (self ._tags_v2 ) * (20 if self ._bigtiff else 12 ) + fmt_size
970+ )
966971 stripoffsets = None
967972
968973 # pass 1: convert tags to binary format
969974 # always write tags in ascending order
970- fmt = "Q" if self ._bigtiff else "L"
971- fmt_size = 8 if self ._bigtiff else 4
972975 for tag , value in sorted (self ._tags_v2 .items ()):
973976 if tag == STRIPOFFSETS :
974977 stripoffsets = len (entries )
@@ -1024,7 +1027,7 @@ def tobytes(self, offset: int = 0) -> bytes:
10241027 )
10251028
10261029 # -- overwrite here for multi-page --
1027- result += b" \0 \0 \0 \0 " # end of entries
1030+ result += self . _pack ( fmt , 0 ) # end of entries
10281031
10291032 # pass 3: write auxiliary data to file
10301033 for tag , typ , count , value , data in entries :
@@ -2043,20 +2046,21 @@ def setup(self) -> None:
20432046 self .offsetOfNewPage = 0
20442047
20452048 self .IIMM = iimm = self .f .read (4 )
2049+ self ._bigtiff = b"\x2B " in iimm
20462050 if not iimm :
20472051 # empty file - first page
20482052 self .isFirst = True
20492053 return
20502054
20512055 self .isFirst = False
2052- if iimm == b"II\x2a \x00 " :
2053- self .setEndian ("<" )
2054- elif iimm == b"MM\x00 \x2a " :
2055- self .setEndian (">" )
2056- else :
2056+ if iimm not in PREFIXES :
20572057 msg = "Invalid TIFF file header"
20582058 raise RuntimeError (msg )
20592059
2060+ self .setEndian ("<" if iimm .startswith (II ) else ">" )
2061+
2062+ if self ._bigtiff :
2063+ self .f .seek (4 , os .SEEK_CUR )
20602064 self .skipIFDs ()
20612065 self .goToEnd ()
20622066
@@ -2076,11 +2080,13 @@ def finalize(self) -> None:
20762080 msg = "IIMM of new page doesn't match IIMM of first page"
20772081 raise RuntimeError (msg )
20782082
2079- ifd_offset = self .readLong ()
2083+ if self ._bigtiff :
2084+ self .f .seek (4 , os .SEEK_CUR )
2085+ ifd_offset = self ._read (8 if self ._bigtiff else 4 )
20802086 ifd_offset += self .offsetOfNewPage
20812087 assert self .whereToWriteNewIFDOffset is not None
20822088 self .f .seek (self .whereToWriteNewIFDOffset )
2083- self .writeLong (ifd_offset )
2089+ self ._write (ifd_offset , 8 if self . _bigtiff else 4 )
20842090 self .f .seek (ifd_offset )
20852091 self .fixIFD ()
20862092
@@ -2126,18 +2132,20 @@ def setEndian(self, endian: str) -> None:
21262132 self .endian = endian
21272133 self .longFmt = f"{ self .endian } L"
21282134 self .shortFmt = f"{ self .endian } H"
2129- self .tagFormat = f"{ self .endian } HHL"
2135+ self .tagFormat = f"{ self .endian } HH" + ( "Q" if self . _bigtiff else "L" )
21302136
21312137 def skipIFDs (self ) -> None :
21322138 while True :
2133- ifd_offset = self .readLong ( )
2139+ ifd_offset = self ._read ( 8 if self . _bigtiff else 4 )
21342140 if ifd_offset == 0 :
2135- self .whereToWriteNewIFDOffset = self .f .tell () - 4
2141+ self .whereToWriteNewIFDOffset = self .f .tell () - (
2142+ 8 if self ._bigtiff else 4
2143+ )
21362144 break
21372145
21382146 self .f .seek (ifd_offset )
2139- num_tags = self .readShort ( )
2140- self .f .seek (num_tags * 12 , os .SEEK_CUR )
2147+ num_tags = self ._read ( 8 if self . _bigtiff else 2 )
2148+ self .f .seek (num_tags * ( 20 if self . _bigtiff else 12 ) , os .SEEK_CUR )
21412149
21422150 def write (self , data : Buffer , / ) -> int :
21432151 return self .f .write (data )
@@ -2185,46 +2193,53 @@ def rewriteLastShort(self, value: int) -> None:
21852193 def rewriteLastLong (self , value : int ) -> None :
21862194 return self ._rewriteLast (value , 4 )
21872195
2196+ def _write (self , value : int , field_size : int ) -> None :
2197+ bytes_written = self .f .write (
2198+ struct .pack (self .endian + self ._fmt (field_size ), value )
2199+ )
2200+ self ._verify_bytes_written (bytes_written , field_size )
2201+
21882202 def writeShort (self , value : int ) -> None :
2189- bytes_written = self .f .write (struct .pack (self .shortFmt , value ))
2190- self ._verify_bytes_written (bytes_written , 2 )
2203+ self ._write (value , 2 )
21912204
21922205 def writeLong (self , value : int ) -> None :
2193- bytes_written = self .f .write (struct .pack (self .longFmt , value ))
2194- self ._verify_bytes_written (bytes_written , 4 )
2206+ self ._write (value , 4 )
21952207
21962208 def close (self ) -> None :
21972209 self .finalize ()
21982210 if self .close_fp :
21992211 self .f .close ()
22002212
22012213 def fixIFD (self ) -> None :
2202- num_tags = self .readShort ( )
2214+ num_tags = self ._read ( 8 if self . _bigtiff else 2 )
22032215
22042216 for i in range (num_tags ):
2205- tag , field_type , count = struct .unpack (self .tagFormat , self .f .read (8 ))
2217+ tag , field_type , count = struct .unpack (
2218+ self .tagFormat , self .f .read (12 if self ._bigtiff else 8 )
2219+ )
22062220
22072221 field_size = self .fieldSizes [field_type ]
22082222 total_size = field_size * count
2209- is_local = total_size <= 4
2223+ fmt_size = 8 if self ._bigtiff else 4
2224+ is_local = total_size <= fmt_size
22102225 if not is_local :
2211- offset = self .readLong ( ) + self .offsetOfNewPage
2212- self .rewriteLastLong (offset )
2226+ offset = self ._read ( fmt_size ) + self .offsetOfNewPage
2227+ self ._rewriteLast (offset , fmt_size )
22132228
22142229 if tag in self .Tags :
22152230 cur_pos = self .f .tell ()
22162231
22172232 if is_local :
22182233 self ._fixOffsets (count , field_size )
2219- self .f .seek (cur_pos + 4 )
2234+ self .f .seek (cur_pos + fmt_size )
22202235 else :
22212236 self .f .seek (offset )
22222237 self ._fixOffsets (count , field_size )
22232238 self .f .seek (cur_pos )
22242239
22252240 elif is_local :
22262241 # skip the locally stored value that is not an offset
2227- self .f .seek (4 , os .SEEK_CUR )
2242+ self .f .seek (fmt_size , os .SEEK_CUR )
22282243
22292244 def _fixOffsets (self , count : int , field_size : int ) -> None :
22302245 for i in range (count ):
0 commit comments