@@ -624,12 +624,12 @@ def reset(self) -> None:
624624 self ._tagdata : dict [int , bytes ] = {}
625625 self .tagtype = {} # added 2008-06-05 by Florian Hoech
626626 self ._next = None
627- self ._offset = None
627+ self ._offset : int | None = None
628628
629629 def __str__ (self ) -> str :
630630 return str (dict (self ))
631631
632- def named (self ):
632+ def named (self ) -> dict [ str , Any ] :
633633 """
634634 :returns: dict of name|key: value
635635
@@ -643,7 +643,7 @@ def named(self):
643643 def __len__ (self ) -> int :
644644 return len (set (self ._tagdata ) | set (self ._tags_v2 ))
645645
646- def __getitem__ (self , tag ) :
646+ def __getitem__ (self , tag : int ) -> Any :
647647 if tag not in self ._tags_v2 : # unpack on the fly
648648 data = self ._tagdata [tag ]
649649 typ = self .tagtype [tag ]
@@ -855,7 +855,7 @@ def _ensure_read(self, fp: IO[bytes], size: int) -> bytes:
855855 raise OSError (msg )
856856 return ret
857857
858- def load (self , fp ) :
858+ def load (self , fp : IO [ bytes ]) -> None :
859859 self .reset ()
860860 self ._offset = fp .tell ()
861861
@@ -1098,7 +1098,7 @@ def __setitem__(self, tag: int, value: Any) -> None:
10981098 for legacy_api in (False , True ):
10991099 self ._setitem (tag , value , legacy_api )
11001100
1101- def __getitem__ (self , tag ) :
1101+ def __getitem__ (self , tag : int ) -> Any :
11021102 if tag not in self ._tags_v1 : # unpack on the fly
11031103 data = self ._tagdata [tag ]
11041104 typ = self .tagtype [tag ]
@@ -1124,11 +1124,8 @@ class TiffImageFile(ImageFile.ImageFile):
11241124 format_description = "Adobe TIFF"
11251125 _close_exclusive_fp_after_loading = False
11261126
1127- def __init__ (self , fp = None , filename = None ):
1128- self .tag_v2 = None
1129- """ Image file directory (tag dictionary) """
1130-
1131- self .tag = None
1127+ def __init__ (self , fp = None , filename = None ) -> None :
1128+ self .tag : ImageFileDirectory_v1 | None = None
11321129 """ Legacy tag entries """
11331130
11341131 super ().__init__ (fp , filename )
@@ -1396,8 +1393,11 @@ def _setup(self) -> None:
13961393 logger .debug ("- YCbCr subsampling: %s" , self .tag_v2 .get (YCBCRSUBSAMPLING ))
13971394
13981395 # size
1399- xsize = int (self .tag_v2 .get (IMAGEWIDTH ))
1400- ysize = int (self .tag_v2 .get (IMAGELENGTH ))
1396+ xsize = self .tag_v2 .get (IMAGEWIDTH )
1397+ ysize = self .tag_v2 .get (IMAGELENGTH )
1398+ if not isinstance (xsize , int ) or not isinstance (ysize , int ):
1399+ msg = "Invalid dimensions"
1400+ raise ValueError (msg )
14011401 self ._size = xsize , ysize
14021402
14031403 logger .debug ("- size: %s" , self .size )
@@ -1545,8 +1545,12 @@ def _setup(self) -> None:
15451545 else :
15461546 # tiled image
15471547 offsets = self .tag_v2 [TILEOFFSETS ]
1548- w = self .tag_v2 .get (TILEWIDTH )
1548+ tilewidth = self .tag_v2 .get (TILEWIDTH )
15491549 h = self .tag_v2 .get (TILELENGTH )
1550+ if not isinstance (tilewidth , int ) or not isinstance (h , int ):
1551+ msg = "Invalid tile dimensions"
1552+ raise ValueError (msg )
1553+ w = tilewidth
15501554
15511555 for offset in offsets :
15521556 if x + w > xsize :
@@ -1624,7 +1628,7 @@ def _setup(self) -> None:
16241628}
16251629
16261630
1627- def _save (im , fp , filename ) :
1631+ def _save (im : Image . Image , fp , filename : str | bytes ) -> None :
16281632 try :
16291633 rawmode , prefix , photo , format , bits , extra = SAVE_INFO [im .mode ]
16301634 except KeyError as e :
@@ -1760,10 +1764,11 @@ def _save(im, fp, filename):
17601764 if im .mode == "1" :
17611765 inverted_im = im .copy ()
17621766 px = inverted_im .load ()
1763- for y in range (inverted_im .height ):
1764- for x in range (inverted_im .width ):
1765- px [x , y ] = 0 if px [x , y ] == 255 else 255
1766- im = inverted_im
1767+ if px is not None :
1768+ for y in range (inverted_im .height ):
1769+ for x in range (inverted_im .width ):
1770+ px [x , y ] = 0 if px [x , y ] == 255 else 255
1771+ im = inverted_im
17671772 else :
17681773 im = ImageOps .invert (im )
17691774
@@ -1805,11 +1810,11 @@ def _save(im, fp, filename):
18051810 ifd [COMPRESSION ] = COMPRESSION_INFO_REV .get (compression , 1 )
18061811
18071812 if im .mode == "YCbCr" :
1808- for tag , value in {
1813+ for tag , default_value in {
18091814 YCBCRSUBSAMPLING : (1 , 1 ),
18101815 REFERENCEBLACKWHITE : (0 , 255 , 128 , 255 , 128 , 255 ),
18111816 }.items ():
1812- ifd .setdefault (tag , value )
1817+ ifd .setdefault (tag , default_value )
18131818
18141819 blocklist = [TILEWIDTH , TILELENGTH , TILEOFFSETS , TILEBYTECOUNTS ]
18151820 if libtiff :
@@ -1852,7 +1857,7 @@ def _save(im, fp, filename):
18521857 ]
18531858
18541859 # bits per sample is a single short in the tiff directory, not a list.
1855- atts = {BITSPERSAMPLE : bits [0 ]}
1860+ atts : dict [ int , Any ] = {BITSPERSAMPLE : bits [0 ]}
18561861 # Merge the ones that we have with (optional) more bits from
18571862 # the original file, e.g x,y resolution so that we can
18581863 # save(load('')) == original file.
@@ -1923,13 +1928,15 @@ def _save(im, fp, filename):
19231928 offset = ifd .save (fp )
19241929
19251930 ImageFile ._save (
1926- im , fp , [("raw" , (0 , 0 ) + im .size , offset , (rawmode , stride , 1 ))]
1931+ im ,
1932+ fp ,
1933+ [ImageFile ._Tile ("raw" , (0 , 0 ) + im .size , offset , (rawmode , stride , 1 ))],
19271934 )
19281935
19291936 # -- helper for multi-page save --
19301937 if "_debug_multipage" in encoderinfo :
19311938 # just to access o32 and o16 (using correct byte order)
1932- im . _debug_multipage = ifd
1939+ setattr ( im , " _debug_multipage" , ifd )
19331940
19341941
19351942class AppendingTiffWriter :
0 commit comments