mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	
						commit
						4721c31b19
					
				| 
						 | 
					@ -51,7 +51,7 @@ build_script:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_script:
 | 
					test_script:
 | 
				
			||||||
- cd c:\pillow
 | 
					- cd c:\pillow
 | 
				
			||||||
- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov pytest-timeout defusedxml numpy olefile pyroma'
 | 
					- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov pytest-timeout defusedxml ipython numpy olefile pyroma'
 | 
				
			||||||
- c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE%
 | 
					- c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE%
 | 
				
			||||||
- '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"'
 | 
					- '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"'
 | 
				
			||||||
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests'
 | 
					- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ python3 -m pip install --upgrade pip
 | 
				
			||||||
python3 -m pip install --upgrade wheel
 | 
					python3 -m pip install --upgrade wheel
 | 
				
			||||||
python3 -m pip install coverage
 | 
					python3 -m pip install coverage
 | 
				
			||||||
python3 -m pip install defusedxml
 | 
					python3 -m pip install defusedxml
 | 
				
			||||||
 | 
					python3 -m pip install ipython
 | 
				
			||||||
python3 -m pip install olefile
 | 
					python3 -m pip install olefile
 | 
				
			||||||
python3 -m pip install -U pytest
 | 
					python3 -m pip install -U pytest
 | 
				
			||||||
python3 -m pip install -U pytest-cov
 | 
					python3 -m pip install -U pytest-cov
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								.github/workflows/macos-install.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/macos-install.sh
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -23,6 +23,7 @@ export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
python3 -m pip install coverage
 | 
					python3 -m pip install coverage
 | 
				
			||||||
python3 -m pip install defusedxml
 | 
					python3 -m pip install defusedxml
 | 
				
			||||||
 | 
					python3 -m pip install ipython
 | 
				
			||||||
python3 -m pip install olefile
 | 
					python3 -m pip install olefile
 | 
				
			||||||
python3 -m pip install -U pytest
 | 
					python3 -m pip install -U pytest
 | 
				
			||||||
python3 -m pip install -U pytest-cov
 | 
					python3 -m pip install -U pytest-cov
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								.github/workflows/test-cygwin.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/test-cygwin.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -74,6 +74,7 @@ jobs:
 | 
				
			||||||
            perl
 | 
					            perl
 | 
				
			||||||
            python3${{ matrix.python-minor-version }}-cython
 | 
					            python3${{ matrix.python-minor-version }}-cython
 | 
				
			||||||
            python3${{ matrix.python-minor-version }}-devel
 | 
					            python3${{ matrix.python-minor-version }}-devel
 | 
				
			||||||
 | 
					            python3${{ matrix.python-minor-version }}-ipython
 | 
				
			||||||
            python3${{ matrix.python-minor-version }}-numpy
 | 
					            python3${{ matrix.python-minor-version }}-numpy
 | 
				
			||||||
            python3${{ matrix.python-minor-version }}-sip
 | 
					            python3${{ matrix.python-minor-version }}-sip
 | 
				
			||||||
            python3${{ matrix.python-minor-version }}-tkinter
 | 
					            python3${{ matrix.python-minor-version }}-tkinter
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -684,6 +684,13 @@ class TestFileTiff:
 | 
				
			||||||
            with Image.open(outfile) as reloaded:
 | 
					            with Image.open(outfile) as reloaded:
 | 
				
			||||||
                assert_image_equal_tofile(reloaded, infile)
 | 
					                assert_image_equal_tofile(reloaded, infile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_tiled_dimensions(self) -> None:
 | 
				
			||||||
 | 
					        with open("Tests/images/tiff_tiled_planar_raw.tif", "rb") as fp:
 | 
				
			||||||
 | 
					            data = fp.read()
 | 
				
			||||||
 | 
					        b = BytesIO(data[:144] + b"\x02" + data[145:])
 | 
				
			||||||
 | 
					        with pytest.raises(ValueError):
 | 
				
			||||||
 | 
					            Image.open(b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.parametrize("mode", ("P", "PA"))
 | 
					    @pytest.mark.parametrize("mode", ("P", "PA"))
 | 
				
			||||||
    def test_palette(self, mode: str, tmp_path: Path) -> None:
 | 
					    def test_palette(self, mode: str, tmp_path: Path) -> None:
 | 
				
			||||||
        outfile = str(tmp_path / "temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,12 @@ try:
 | 
				
			||||||
except ImportError:
 | 
					except ImportError:
 | 
				
			||||||
    ElementTree = None
 | 
					    ElementTree = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PrettyPrinter: type | None
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    from IPython.lib.pretty import PrettyPrinter
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    PrettyPrinter = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Deprecation helper
 | 
					# Deprecation helper
 | 
				
			||||||
def helper_image_new(mode: str, size: tuple[int, int]) -> Image.Image:
 | 
					def helper_image_new(mode: str, size: tuple[int, int]) -> Image.Image:
 | 
				
			||||||
| 
						 | 
					@ -91,16 +97,15 @@ class TestImage:
 | 
				
			||||||
        # with pytest.raises(MemoryError):
 | 
					        # with pytest.raises(MemoryError):
 | 
				
			||||||
        #   Image.new("L", (1000000, 1000000))
 | 
					        #   Image.new("L", (1000000, 1000000))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.mark.skipif(PrettyPrinter is None, reason="IPython is not installed")
 | 
				
			||||||
    def test_repr_pretty(self) -> None:
 | 
					    def test_repr_pretty(self) -> None:
 | 
				
			||||||
        class Pretty:
 | 
					 | 
				
			||||||
            def text(self, text: str) -> None:
 | 
					 | 
				
			||||||
                self.pretty_output = text
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        im = Image.new("L", (100, 100))
 | 
					        im = Image.new("L", (100, 100))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p = Pretty()
 | 
					        output = io.StringIO()
 | 
				
			||||||
 | 
					        assert PrettyPrinter is not None
 | 
				
			||||||
 | 
					        p = PrettyPrinter(output)
 | 
				
			||||||
        im._repr_pretty_(p, False)
 | 
					        im._repr_pretty_(p, False)
 | 
				
			||||||
        assert p.pretty_output == "<PIL.Image.Image image mode=L size=100x100>"
 | 
					        assert output.getvalue() == "<PIL.Image.Image image mode=L size=100x100>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_open_formats(self) -> None:
 | 
					    def test_open_formats(self) -> None:
 | 
				
			||||||
        PNGFILE = "Tests/images/hopper.png"
 | 
					        PNGFILE = "Tests/images/hopper.png"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -412,9 +412,8 @@ class TestPyEncoder(CodecsTest):
 | 
				
			||||||
        with pytest.raises(NotImplementedError):
 | 
					        with pytest.raises(NotImplementedError):
 | 
				
			||||||
            encoder.encode_to_pyfd()
 | 
					            encoder.encode_to_pyfd()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fh = BytesIO()
 | 
					 | 
				
			||||||
        with pytest.raises(NotImplementedError):
 | 
					        with pytest.raises(NotImplementedError):
 | 
				
			||||||
            encoder.encode_to_file(fh, 0)
 | 
					            encoder.encode_to_file(0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_zero_height(self) -> None:
 | 
					    def test_zero_height(self) -> None:
 | 
				
			||||||
        with pytest.raises(UnidentifiedImageError):
 | 
					        with pytest.raises(UnidentifiedImageError):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,6 @@ import sys
 | 
				
			||||||
from io import BytesIO
 | 
					from io import BytesIO
 | 
				
			||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from PIL import Image, PSDraw
 | 
					from PIL import Image, PSDraw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,15 +47,14 @@ def test_draw_postscript(tmp_path: Path) -> None:
 | 
				
			||||||
    assert os.path.getsize(tempfile) > 0
 | 
					    assert os.path.getsize(tempfile) > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize("buffer", (True, False))
 | 
					def test_stdout() -> None:
 | 
				
			||||||
def test_stdout(buffer: bool) -> None:
 | 
					 | 
				
			||||||
    # Temporarily redirect stdout
 | 
					    # Temporarily redirect stdout
 | 
				
			||||||
    old_stdout = sys.stdout
 | 
					    old_stdout = sys.stdout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class MyStdOut:
 | 
					    class MyStdOut:
 | 
				
			||||||
        buffer = BytesIO()
 | 
					        buffer = BytesIO()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mystdout: MyStdOut | BytesIO = MyStdOut() if buffer else BytesIO()
 | 
					    mystdout = MyStdOut()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sys.stdout = mystdout
 | 
					    sys.stdout = mystdout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +64,4 @@ def test_stdout(buffer: bool) -> None:
 | 
				
			||||||
    # Reset stdout
 | 
					    # Reset stdout
 | 
				
			||||||
    sys.stdout = old_stdout
 | 
					    sys.stdout = old_stdout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if isinstance(mystdout, MyStdOut):
 | 
					    assert mystdout.buffer.getvalue() != b""
 | 
				
			||||||
        mystdout = mystdout.buffer
 | 
					 | 
				
			||||||
    assert mystdout.getvalue() != b""
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -362,6 +362,7 @@ Classes
 | 
				
			||||||
    :undoc-members:
 | 
					    :undoc-members:
 | 
				
			||||||
    :show-inheritance:
 | 
					    :show-inheritance:
 | 
				
			||||||
.. autoclass:: PIL.Image.ImagePointHandler
 | 
					.. autoclass:: PIL.Image.ImagePointHandler
 | 
				
			||||||
 | 
					.. autoclass:: PIL.Image.ImagePointTransform
 | 
				
			||||||
.. autoclass:: PIL.Image.ImageTransformHandler
 | 
					.. autoclass:: PIL.Image.ImageTransformHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Protocols
 | 
					Protocols
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -319,11 +319,11 @@ class IcoImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        self.load()
 | 
					        self.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def size(self):
 | 
					    def size(self) -> tuple[int, int]:
 | 
				
			||||||
        return self._size
 | 
					        return self._size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @size.setter
 | 
					    @size.setter
 | 
				
			||||||
    def size(self, value):
 | 
					    def size(self, value: tuple[int, int]) -> None:
 | 
				
			||||||
        if value not in self.info["sizes"]:
 | 
					        if value not in self.info["sizes"]:
 | 
				
			||||||
            msg = "This is not one of the allowed sizes of this image"
 | 
					            msg = "This is not one of the allowed sizes of this image"
 | 
				
			||||||
            raise ValueError(msg)
 | 
					            raise ValueError(msg)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -221,6 +221,8 @@ if TYPE_CHECKING:
 | 
				
			||||||
    import mmap
 | 
					    import mmap
 | 
				
			||||||
    from xml.etree.ElementTree import Element
 | 
					    from xml.etree.ElementTree import Element
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from IPython.lib.pretty import PrettyPrinter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from . import ImageFile, ImageFilter, ImagePalette, TiffImagePlugin
 | 
					    from . import ImageFile, ImageFilter, ImagePalette, TiffImagePlugin
 | 
				
			||||||
    from ._typing import NumpyArray, StrOrBytesPath, TypeGuard
 | 
					    from ._typing import NumpyArray, StrOrBytesPath, TypeGuard
 | 
				
			||||||
ID: list[str] = []
 | 
					ID: list[str] = []
 | 
				
			||||||
| 
						 | 
					@ -468,43 +470,53 @@ def _getencoder(
 | 
				
			||||||
# Simple expression analyzer
 | 
					# Simple expression analyzer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _E:
 | 
					class ImagePointTransform:
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Used with :py:meth:`~PIL.Image.Image.point` for single band images with more than
 | 
				
			||||||
 | 
					    8 bits, this represents an affine transformation, where the value is multiplied by
 | 
				
			||||||
 | 
					    ``scale`` and ``offset`` is added.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, scale: float, offset: float) -> None:
 | 
					    def __init__(self, scale: float, offset: float) -> None:
 | 
				
			||||||
        self.scale = scale
 | 
					        self.scale = scale
 | 
				
			||||||
        self.offset = offset
 | 
					        self.offset = offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __neg__(self) -> _E:
 | 
					    def __neg__(self) -> ImagePointTransform:
 | 
				
			||||||
        return _E(-self.scale, -self.offset)
 | 
					        return ImagePointTransform(-self.scale, -self.offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __add__(self, other: _E | float) -> _E:
 | 
					    def __add__(self, other: ImagePointTransform | float) -> ImagePointTransform:
 | 
				
			||||||
        if isinstance(other, _E):
 | 
					        if isinstance(other, ImagePointTransform):
 | 
				
			||||||
            return _E(self.scale + other.scale, self.offset + other.offset)
 | 
					            return ImagePointTransform(
 | 
				
			||||||
        return _E(self.scale, self.offset + other)
 | 
					                self.scale + other.scale, self.offset + other.offset
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        return ImagePointTransform(self.scale, self.offset + other)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __radd__ = __add__
 | 
					    __radd__ = __add__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __sub__(self, other: _E | float) -> _E:
 | 
					    def __sub__(self, other: ImagePointTransform | float) -> ImagePointTransform:
 | 
				
			||||||
        return self + -other
 | 
					        return self + -other
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __rsub__(self, other: _E | float) -> _E:
 | 
					    def __rsub__(self, other: ImagePointTransform | float) -> ImagePointTransform:
 | 
				
			||||||
        return other + -self
 | 
					        return other + -self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __mul__(self, other: _E | float) -> _E:
 | 
					    def __mul__(self, other: ImagePointTransform | float) -> ImagePointTransform:
 | 
				
			||||||
        if isinstance(other, _E):
 | 
					        if isinstance(other, ImagePointTransform):
 | 
				
			||||||
            return NotImplemented
 | 
					            return NotImplemented
 | 
				
			||||||
        return _E(self.scale * other, self.offset * other)
 | 
					        return ImagePointTransform(self.scale * other, self.offset * other)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __rmul__ = __mul__
 | 
					    __rmul__ = __mul__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __truediv__(self, other: _E | float) -> _E:
 | 
					    def __truediv__(self, other: ImagePointTransform | float) -> ImagePointTransform:
 | 
				
			||||||
        if isinstance(other, _E):
 | 
					        if isinstance(other, ImagePointTransform):
 | 
				
			||||||
            return NotImplemented
 | 
					            return NotImplemented
 | 
				
			||||||
        return _E(self.scale / other, self.offset / other)
 | 
					        return ImagePointTransform(self.scale / other, self.offset / other)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _getscaleoffset(expr) -> tuple[float, float]:
 | 
					def _getscaleoffset(
 | 
				
			||||||
    a = expr(_E(1, 0))
 | 
					    expr: Callable[[ImagePointTransform], ImagePointTransform | float]
 | 
				
			||||||
    return (a.scale, a.offset) if isinstance(a, _E) else (0, a)
 | 
					) -> tuple[float, float]:
 | 
				
			||||||
 | 
					    a = expr(ImagePointTransform(1, 0))
 | 
				
			||||||
 | 
					    return (a.scale, a.offset) if isinstance(a, ImagePointTransform) else (0, a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# --------------------------------------------------------------------
 | 
					# --------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -677,7 +689,7 @@ class Image:
 | 
				
			||||||
            id(self),
 | 
					            id(self),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _repr_pretty_(self, p, cycle: bool) -> None:
 | 
					    def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None:
 | 
				
			||||||
        """IPython plain text display support"""
 | 
					        """IPython plain text display support"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Same as __repr__ but without unpredictable id(self),
 | 
					        # Same as __repr__ but without unpredictable id(self),
 | 
				
			||||||
| 
						 | 
					@ -1880,7 +1892,13 @@ class Image:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def point(
 | 
					    def point(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        lut: Sequence[float] | NumpyArray | Callable[[int], float] | ImagePointHandler,
 | 
					        lut: (
 | 
				
			||||||
 | 
					            Sequence[float]
 | 
				
			||||||
 | 
					            | NumpyArray
 | 
				
			||||||
 | 
					            | Callable[[int], float]
 | 
				
			||||||
 | 
					            | Callable[[ImagePointTransform], ImagePointTransform | float]
 | 
				
			||||||
 | 
					            | ImagePointHandler
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
        mode: str | None = None,
 | 
					        mode: str | None = None,
 | 
				
			||||||
    ) -> Image:
 | 
					    ) -> Image:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -1897,7 +1915,7 @@ class Image:
 | 
				
			||||||
           object::
 | 
					           object::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
               class Example(Image.ImagePointHandler):
 | 
					               class Example(Image.ImagePointHandler):
 | 
				
			||||||
                 def point(self, data):
 | 
					                 def point(self, im: Image) -> Image:
 | 
				
			||||||
                   # Return result
 | 
					                   # Return result
 | 
				
			||||||
        :param mode: Output mode (default is same as input). This can only be used if
 | 
					        :param mode: Output mode (default is same as input). This can only be used if
 | 
				
			||||||
           the source image has mode "L" or "P", and the output has mode "1" or the
 | 
					           the source image has mode "L" or "P", and the output has mode "1" or the
 | 
				
			||||||
| 
						 | 
					@ -1916,10 +1934,10 @@ class Image:
 | 
				
			||||||
                # check if the function can be used with point_transform
 | 
					                # check if the function can be used with point_transform
 | 
				
			||||||
                # UNDONE wiredfool -- I think this prevents us from ever doing
 | 
					                # UNDONE wiredfool -- I think this prevents us from ever doing
 | 
				
			||||||
                # a gamma function point transform on > 8bit images.
 | 
					                # a gamma function point transform on > 8bit images.
 | 
				
			||||||
                scale, offset = _getscaleoffset(lut)
 | 
					                scale, offset = _getscaleoffset(lut)  # type: ignore[arg-type]
 | 
				
			||||||
                return self._new(self.im.point_transform(scale, offset))
 | 
					                return self._new(self.im.point_transform(scale, offset))
 | 
				
			||||||
            # for other modes, convert the function to a table
 | 
					            # for other modes, convert the function to a table
 | 
				
			||||||
            flatLut = [lut(i) for i in range(256)] * self.im.bands
 | 
					            flatLut = [lut(i) for i in range(256)] * self.im.bands  # type: ignore[arg-type]
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            flatLut = lut
 | 
					            flatLut = lut
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2855,11 +2873,11 @@ class Image:
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        box: tuple[int, int, int, int],
 | 
					        box: tuple[int, int, int, int],
 | 
				
			||||||
        image: Image,
 | 
					        image: Image,
 | 
				
			||||||
        method,
 | 
					        method: Transform,
 | 
				
			||||||
        data,
 | 
					        data: Sequence[float],
 | 
				
			||||||
        resample: int = Resampling.NEAREST,
 | 
					        resample: int = Resampling.NEAREST,
 | 
				
			||||||
        fill: bool = True,
 | 
					        fill: bool = True,
 | 
				
			||||||
    ):
 | 
					    ) -> None:
 | 
				
			||||||
        w = box[2] - box[0]
 | 
					        w = box[2] - box[0]
 | 
				
			||||||
        h = box[3] - box[1]
 | 
					        h = box[3] - box[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3994,15 +4012,19 @@ class Exif(_ExifBase):
 | 
				
			||||||
            ifd[tag] = value
 | 
					            ifd[tag] = value
 | 
				
			||||||
        return b"Exif\x00\x00" + head + ifd.tobytes(offset)
 | 
					        return b"Exif\x00\x00" + head + ifd.tobytes(offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_ifd(self, tag):
 | 
					    def get_ifd(self, tag: int) -> dict[int, Any]:
 | 
				
			||||||
        if tag not in self._ifds:
 | 
					        if tag not in self._ifds:
 | 
				
			||||||
            if tag == ExifTags.IFD.IFD1:
 | 
					            if tag == ExifTags.IFD.IFD1:
 | 
				
			||||||
                if self._info is not None and self._info.next != 0:
 | 
					                if self._info is not None and self._info.next != 0:
 | 
				
			||||||
                    self._ifds[tag] = self._get_ifd_dict(self._info.next)
 | 
					                    ifd = self._get_ifd_dict(self._info.next)
 | 
				
			||||||
 | 
					                    if ifd is not None:
 | 
				
			||||||
 | 
					                        self._ifds[tag] = ifd
 | 
				
			||||||
            elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
 | 
					            elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
 | 
				
			||||||
                offset = self._hidden_data.get(tag, self.get(tag))
 | 
					                offset = self._hidden_data.get(tag, self.get(tag))
 | 
				
			||||||
                if offset is not None:
 | 
					                if offset is not None:
 | 
				
			||||||
                    self._ifds[tag] = self._get_ifd_dict(offset, tag)
 | 
					                    ifd = self._get_ifd_dict(offset, tag)
 | 
				
			||||||
 | 
					                    if ifd is not None:
 | 
				
			||||||
 | 
					                        self._ifds[tag] = ifd
 | 
				
			||||||
            elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.Makernote]:
 | 
					            elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.Makernote]:
 | 
				
			||||||
                if ExifTags.IFD.Exif not in self._ifds:
 | 
					                if ExifTags.IFD.Exif not in self._ifds:
 | 
				
			||||||
                    self.get_ifd(ExifTags.IFD.Exif)
 | 
					                    self.get_ifd(ExifTags.IFD.Exif)
 | 
				
			||||||
| 
						 | 
					@ -4059,7 +4081,9 @@ class Exif(_ExifBase):
 | 
				
			||||||
                                (offset,) = struct.unpack(">L", data)
 | 
					                                (offset,) = struct.unpack(">L", data)
 | 
				
			||||||
                                self.fp.seek(offset)
 | 
					                                self.fp.seek(offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                camerainfo = {"ModelID": self.fp.read(4)}
 | 
					                                camerainfo: dict[str, int | bytes] = {
 | 
				
			||||||
 | 
					                                    "ModelID": self.fp.read(4)
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                self.fp.read(4)
 | 
					                                self.fp.read(4)
 | 
				
			||||||
                                # Seconds since 2000
 | 
					                                # Seconds since 2000
 | 
				
			||||||
| 
						 | 
					@ -4075,16 +4099,18 @@ class Exif(_ExifBase):
 | 
				
			||||||
                                ][1]
 | 
					                                ][1]
 | 
				
			||||||
                                camerainfo["Parallax"] = handler(
 | 
					                                camerainfo["Parallax"] = handler(
 | 
				
			||||||
                                    ImageFileDirectory_v2(), parallax, False
 | 
					                                    ImageFileDirectory_v2(), parallax, False
 | 
				
			||||||
                                )
 | 
					                                )[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                self.fp.read(4)
 | 
					                                self.fp.read(4)
 | 
				
			||||||
                                camerainfo["Category"] = self.fp.read(2)
 | 
					                                camerainfo["Category"] = self.fp.read(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                makernote = {0x1101: dict(self._fixup_dict(camerainfo))}
 | 
					                                makernote = {0x1101: camerainfo}
 | 
				
			||||||
                        self._ifds[tag] = makernote
 | 
					                        self._ifds[tag] = makernote
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    # Interop
 | 
					                    # Interop
 | 
				
			||||||
                    self._ifds[tag] = self._get_ifd_dict(tag_data, tag)
 | 
					                    ifd = self._get_ifd_dict(tag_data, tag)
 | 
				
			||||||
 | 
					                    if ifd is not None:
 | 
				
			||||||
 | 
					                        self._ifds[tag] = ifd
 | 
				
			||||||
        ifd = self._ifds.get(tag, {})
 | 
					        ifd = self._ifds.get(tag, {})
 | 
				
			||||||
        if tag == ExifTags.IFD.Exif and self._hidden_data:
 | 
					        if tag == ExifTags.IFD.Exif and self._hidden_data:
 | 
				
			||||||
            ifd = {
 | 
					            ifd = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ from __future__ import annotations
 | 
				
			||||||
import abc
 | 
					import abc
 | 
				
			||||||
import io
 | 
					import io
 | 
				
			||||||
import itertools
 | 
					import itertools
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
import struct
 | 
					import struct
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
from typing import IO, Any, NamedTuple
 | 
					from typing import IO, Any, NamedTuple
 | 
				
			||||||
| 
						 | 
					@ -555,7 +556,7 @@ def _encode_tile(
 | 
				
			||||||
    fp: IO[bytes],
 | 
					    fp: IO[bytes],
 | 
				
			||||||
    tile: list[_Tile],
 | 
					    tile: list[_Tile],
 | 
				
			||||||
    bufsize: int,
 | 
					    bufsize: int,
 | 
				
			||||||
    fh,
 | 
					    fh: int | None,
 | 
				
			||||||
    exc: BaseException | None = None,
 | 
					    exc: BaseException | None = None,
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
    for encoder_name, extents, offset, args in tile:
 | 
					    for encoder_name, extents, offset, args in tile:
 | 
				
			||||||
| 
						 | 
					@ -577,6 +578,7 @@ def _encode_tile(
 | 
				
			||||||
                            break
 | 
					                            break
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    # slight speedup: compress to real file object
 | 
					                    # slight speedup: compress to real file object
 | 
				
			||||||
 | 
					                    assert fh is not None
 | 
				
			||||||
                    errcode = encoder.encode_to_file(fh, bufsize)
 | 
					                    errcode = encoder.encode_to_file(fh, bufsize)
 | 
				
			||||||
            if errcode < 0:
 | 
					            if errcode < 0:
 | 
				
			||||||
                raise _get_oserror(errcode, encoder=True) from exc
 | 
					                raise _get_oserror(errcode, encoder=True) from exc
 | 
				
			||||||
| 
						 | 
					@ -801,7 +803,7 @@ class PyEncoder(PyCodec):
 | 
				
			||||||
            self.fd.write(data)
 | 
					            self.fd.write(data)
 | 
				
			||||||
        return bytes_consumed, errcode
 | 
					        return bytes_consumed, errcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def encode_to_file(self, fh: IO[bytes], bufsize: int) -> int:
 | 
					    def encode_to_file(self, fh: int, bufsize: int) -> int:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        :param fh: File handle.
 | 
					        :param fh: File handle.
 | 
				
			||||||
        :param bufsize: Buffer size.
 | 
					        :param bufsize: Buffer size.
 | 
				
			||||||
| 
						 | 
					@ -814,5 +816,5 @@ class PyEncoder(PyCodec):
 | 
				
			||||||
        while errcode == 0:
 | 
					        while errcode == 0:
 | 
				
			||||||
            status, errcode, buf = self.encode(bufsize)
 | 
					            status, errcode, buf = self.encode(bufsize)
 | 
				
			||||||
            if status > 0:
 | 
					            if status > 0:
 | 
				
			||||||
                fh.write(buf[status:])
 | 
					                os.write(fh, buf[status:])
 | 
				
			||||||
        return errcode
 | 
					        return errcode
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,7 +214,7 @@ def getiptcinfo(
 | 
				
			||||||
        # as 4-byte integers, so we cannot use the get method...)
 | 
					        # as 4-byte integers, so we cannot use the get method...)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            data = im.tag_v2[TiffImagePlugin.IPTC_NAA_CHUNK]
 | 
					            data = im.tag_v2[TiffImagePlugin.IPTC_NAA_CHUNK]
 | 
				
			||||||
        except (AttributeError, KeyError):
 | 
					        except KeyError:
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if data is None:
 | 
					    if data is None:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@
 | 
				
			||||||
from __future__ import annotations
 | 
					from __future__ import annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
from typing import TYPE_CHECKING
 | 
					from typing import IO, TYPE_CHECKING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import EpsImagePlugin
 | 
					from . import EpsImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,15 +28,12 @@ from . import EpsImagePlugin
 | 
				
			||||||
class PSDraw:
 | 
					class PSDraw:
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Sets up printing to the given file. If ``fp`` is omitted,
 | 
					    Sets up printing to the given file. If ``fp`` is omitted,
 | 
				
			||||||
    ``sys.stdout.buffer`` or ``sys.stdout`` is assumed.
 | 
					    ``sys.stdout.buffer`` is assumed.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, fp=None):
 | 
					    def __init__(self, fp: IO[bytes] | None = None) -> None:
 | 
				
			||||||
        if not fp:
 | 
					        if not fp:
 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
            fp = sys.stdout.buffer
 | 
					            fp = sys.stdout.buffer
 | 
				
			||||||
            except AttributeError:
 | 
					 | 
				
			||||||
                fp = sys.stdout
 | 
					 | 
				
			||||||
        self.fp = fp
 | 
					        self.fp = fp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def begin_document(self, id: str | None = None) -> None:
 | 
					    def begin_document(self, id: str | None = None) -> None:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -624,12 +624,12 @@ class ImageFileDirectory_v2(_IFDv2Base):
 | 
				
			||||||
        self._tagdata: dict[int, bytes] = {}
 | 
					        self._tagdata: dict[int, bytes] = {}
 | 
				
			||||||
        self.tagtype = {}  # added 2008-06-05 by Florian Hoech
 | 
					        self.tagtype = {}  # added 2008-06-05 by Florian Hoech
 | 
				
			||||||
        self._next = None
 | 
					        self._next = None
 | 
				
			||||||
        self._offset = None
 | 
					        self._offset: int | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self) -> str:
 | 
					    def __str__(self) -> str:
 | 
				
			||||||
        return str(dict(self))
 | 
					        return str(dict(self))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def named(self):
 | 
					    def named(self) -> dict[str, Any]:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        :returns: dict of name|key: value
 | 
					        :returns: dict of name|key: value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -643,7 +643,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
 | 
				
			||||||
    def __len__(self) -> int:
 | 
					    def __len__(self) -> int:
 | 
				
			||||||
        return len(set(self._tagdata) | set(self._tags_v2))
 | 
					        return len(set(self._tagdata) | set(self._tags_v2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, tag):
 | 
					    def __getitem__(self, tag: int) -> Any:
 | 
				
			||||||
        if tag not in self._tags_v2:  # unpack on the fly
 | 
					        if tag not in self._tags_v2:  # unpack on the fly
 | 
				
			||||||
            data = self._tagdata[tag]
 | 
					            data = self._tagdata[tag]
 | 
				
			||||||
            typ = self.tagtype[tag]
 | 
					            typ = self.tagtype[tag]
 | 
				
			||||||
| 
						 | 
					@ -855,7 +855,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
 | 
				
			||||||
            raise OSError(msg)
 | 
					            raise OSError(msg)
 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load(self, fp):
 | 
					    def load(self, fp: IO[bytes]) -> None:
 | 
				
			||||||
        self.reset()
 | 
					        self.reset()
 | 
				
			||||||
        self._offset = fp.tell()
 | 
					        self._offset = fp.tell()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1098,7 +1098,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
 | 
				
			||||||
        for legacy_api in (False, True):
 | 
					        for legacy_api in (False, True):
 | 
				
			||||||
            self._setitem(tag, value, legacy_api)
 | 
					            self._setitem(tag, value, legacy_api)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, tag):
 | 
					    def __getitem__(self, tag: int) -> Any:
 | 
				
			||||||
        if tag not in self._tags_v1:  # unpack on the fly
 | 
					        if tag not in self._tags_v1:  # unpack on the fly
 | 
				
			||||||
            data = self._tagdata[tag]
 | 
					            data = self._tagdata[tag]
 | 
				
			||||||
            typ = self.tagtype[tag]
 | 
					            typ = self.tagtype[tag]
 | 
				
			||||||
| 
						 | 
					@ -1124,11 +1124,15 @@ class TiffImageFile(ImageFile.ImageFile):
 | 
				
			||||||
    format_description = "Adobe TIFF"
 | 
					    format_description = "Adobe TIFF"
 | 
				
			||||||
    _close_exclusive_fp_after_loading = False
 | 
					    _close_exclusive_fp_after_loading = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, fp=None, filename=None):
 | 
					    def __init__(
 | 
				
			||||||
        self.tag_v2 = None
 | 
					        self,
 | 
				
			||||||
 | 
					        fp: StrOrBytesPath | IO[bytes] | None = None,
 | 
				
			||||||
 | 
					        filename: str | bytes | None = None,
 | 
				
			||||||
 | 
					    ) -> None:
 | 
				
			||||||
 | 
					        self.tag_v2: ImageFileDirectory_v2
 | 
				
			||||||
        """ Image file directory (tag dictionary) """
 | 
					        """ Image file directory (tag dictionary) """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tag = None
 | 
					        self.tag: ImageFileDirectory_v1
 | 
				
			||||||
        """ Legacy tag entries """
 | 
					        """ Legacy tag entries """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        super().__init__(fp, filename)
 | 
					        super().__init__(fp, filename)
 | 
				
			||||||
| 
						 | 
					@ -1143,9 +1147,6 @@ class TiffImageFile(ImageFile.ImageFile):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tag_v2 = ImageFileDirectory_v2(ifh)
 | 
					        self.tag_v2 = ImageFileDirectory_v2(ifh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # legacy IFD entries will be filled in later
 | 
					 | 
				
			||||||
        self.ifd: ImageFileDirectory_v1 | None = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # setup frame pointers
 | 
					        # setup frame pointers
 | 
				
			||||||
        self.__first = self.__next = self.tag_v2.next
 | 
					        self.__first = self.__next = self.tag_v2.next
 | 
				
			||||||
        self.__frame = -1
 | 
					        self.__frame = -1
 | 
				
			||||||
| 
						 | 
					@ -1396,8 +1397,11 @@ class TiffImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        logger.debug("- YCbCr subsampling: %s", self.tag_v2.get(YCBCRSUBSAMPLING))
 | 
					        logger.debug("- YCbCr subsampling: %s", self.tag_v2.get(YCBCRSUBSAMPLING))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # size
 | 
					        # size
 | 
				
			||||||
        xsize = int(self.tag_v2.get(IMAGEWIDTH))
 | 
					        xsize = self.tag_v2.get(IMAGEWIDTH)
 | 
				
			||||||
        ysize = int(self.tag_v2.get(IMAGELENGTH))
 | 
					        ysize = self.tag_v2.get(IMAGELENGTH)
 | 
				
			||||||
 | 
					        if not isinstance(xsize, int) or not isinstance(ysize, int):
 | 
				
			||||||
 | 
					            msg = "Invalid dimensions"
 | 
				
			||||||
 | 
					            raise ValueError(msg)
 | 
				
			||||||
        self._size = xsize, ysize
 | 
					        self._size = xsize, ysize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logger.debug("- size: %s", self.size)
 | 
					        logger.debug("- size: %s", self.size)
 | 
				
			||||||
| 
						 | 
					@ -1545,8 +1549,12 @@ class TiffImageFile(ImageFile.ImageFile):
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                # tiled image
 | 
					                # tiled image
 | 
				
			||||||
                offsets = self.tag_v2[TILEOFFSETS]
 | 
					                offsets = self.tag_v2[TILEOFFSETS]
 | 
				
			||||||
                w = self.tag_v2.get(TILEWIDTH)
 | 
					                tilewidth = self.tag_v2.get(TILEWIDTH)
 | 
				
			||||||
                h = self.tag_v2.get(TILELENGTH)
 | 
					                h = self.tag_v2.get(TILELENGTH)
 | 
				
			||||||
 | 
					                if not isinstance(tilewidth, int) or not isinstance(h, int):
 | 
				
			||||||
 | 
					                    msg = "Invalid tile dimensions"
 | 
				
			||||||
 | 
					                    raise ValueError(msg)
 | 
				
			||||||
 | 
					                w = tilewidth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for offset in offsets:
 | 
					            for offset in offsets:
 | 
				
			||||||
                if x + w > xsize:
 | 
					                if x + w > xsize:
 | 
				
			||||||
| 
						 | 
					@ -1624,7 +1632,7 @@ SAVE_INFO = {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _save(im, fp, filename):
 | 
					def _save(im: Image.Image, fp, filename: str | bytes) -> None:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
 | 
					        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
 | 
				
			||||||
    except KeyError as e:
 | 
					    except KeyError as e:
 | 
				
			||||||
| 
						 | 
					@ -1760,6 +1768,7 @@ def _save(im, fp, filename):
 | 
				
			||||||
        if im.mode == "1":
 | 
					        if im.mode == "1":
 | 
				
			||||||
            inverted_im = im.copy()
 | 
					            inverted_im = im.copy()
 | 
				
			||||||
            px = inverted_im.load()
 | 
					            px = inverted_im.load()
 | 
				
			||||||
 | 
					            if px is not None:
 | 
				
			||||||
                for y in range(inverted_im.height):
 | 
					                for y in range(inverted_im.height):
 | 
				
			||||||
                    for x in range(inverted_im.width):
 | 
					                    for x in range(inverted_im.width):
 | 
				
			||||||
                        px[x, y] = 0 if px[x, y] == 255 else 255
 | 
					                        px[x, y] = 0 if px[x, y] == 255 else 255
 | 
				
			||||||
| 
						 | 
					@ -1805,11 +1814,11 @@ def _save(im, fp, filename):
 | 
				
			||||||
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
 | 
					    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if im.mode == "YCbCr":
 | 
					    if im.mode == "YCbCr":
 | 
				
			||||||
        for tag, value in {
 | 
					        for tag, default_value in {
 | 
				
			||||||
            YCBCRSUBSAMPLING: (1, 1),
 | 
					            YCBCRSUBSAMPLING: (1, 1),
 | 
				
			||||||
            REFERENCEBLACKWHITE: (0, 255, 128, 255, 128, 255),
 | 
					            REFERENCEBLACKWHITE: (0, 255, 128, 255, 128, 255),
 | 
				
			||||||
        }.items():
 | 
					        }.items():
 | 
				
			||||||
            ifd.setdefault(tag, value)
 | 
					            ifd.setdefault(tag, default_value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blocklist = [TILEWIDTH, TILELENGTH, TILEOFFSETS, TILEBYTECOUNTS]
 | 
					    blocklist = [TILEWIDTH, TILELENGTH, TILEOFFSETS, TILEBYTECOUNTS]
 | 
				
			||||||
    if libtiff:
 | 
					    if libtiff:
 | 
				
			||||||
| 
						 | 
					@ -1852,7 +1861,7 @@ def _save(im, fp, filename):
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # bits per sample is a single short in the tiff directory, not a list.
 | 
					        # bits per sample is a single short in the tiff directory, not a list.
 | 
				
			||||||
        atts = {BITSPERSAMPLE: bits[0]}
 | 
					        atts: dict[int, Any] = {BITSPERSAMPLE: bits[0]}
 | 
				
			||||||
        # Merge the ones that we have with (optional) more bits from
 | 
					        # Merge the ones that we have with (optional) more bits from
 | 
				
			||||||
        # the original file, e.g x,y resolution so that we can
 | 
					        # the original file, e.g x,y resolution so that we can
 | 
				
			||||||
        # save(load('')) == original file.
 | 
					        # save(load('')) == original file.
 | 
				
			||||||
| 
						 | 
					@ -1923,13 +1932,15 @@ def _save(im, fp, filename):
 | 
				
			||||||
        offset = ifd.save(fp)
 | 
					        offset = ifd.save(fp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ImageFile._save(
 | 
					        ImageFile._save(
 | 
				
			||||||
            im, fp, [("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))]
 | 
					            im,
 | 
				
			||||||
 | 
					            fp,
 | 
				
			||||||
 | 
					            [ImageFile._Tile("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # -- helper for multi-page save --
 | 
					    # -- helper for multi-page save --
 | 
				
			||||||
    if "_debug_multipage" in encoderinfo:
 | 
					    if "_debug_multipage" in encoderinfo:
 | 
				
			||||||
        # just to access o32 and o16 (using correct byte order)
 | 
					        # just to access o32 and o16 (using correct byte order)
 | 
				
			||||||
        im._debug_multipage = ifd
 | 
					        setattr(im, "_debug_multipage", ifd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AppendingTiffWriter:
 | 
					class AppendingTiffWriter:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user