diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index fc1831d99df..6ac90f7789d 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -987,6 +987,20 @@ def test_save_multistrip(self, compression, tmp_path): # Assert that there are multiple strips assert len(im.tag_v2[STRIPOFFSETS]) > 1 + def test_save_single_strip(self, tmp_path): + im = hopper("RGB").resize((256, 256)) + out = str(tmp_path / "temp.tif") + + TiffImagePlugin.STRIP_SIZE = 2 ** 18 + try: + + im.save(out, compression="tiff_adobe_deflate") + + with Image.open(out) as im: + assert len(im.tag_v2[STRIPOFFSETS]) == 1 + finally: + TiffImagePlugin.STRIP_SIZE = 65536 + @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", None)) def test_save_zero(self, compression, tmp_path): im = Image.new("RGB", (0, 0)) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index baaa709d8b1..6b311bbf5b9 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -58,6 +58,7 @@ READ_LIBTIFF = False WRITE_LIBTIFF = False IFD_LEGACY_API = True +STRIP_SIZE = 65536 II = b"II" # little-endian (Intel style) MM = b"MM" # big-endian (Motorola style) @@ -1617,11 +1618,9 @@ def _save(im, fp, filename): ifd[COLORMAP] = tuple(v * 256 for v in lut) # data orientation stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8) - # aim for 64 KB strips when using libtiff writer + # aim for given strip size (64 KB by default) when using libtiff writer if libtiff: - rows_per_strip = ( - 1 if stride == 0 else min((2 ** 16 + stride - 1) // stride, im.size[1]) - ) + rows_per_strip = 1 if stride == 0 else min(STRIP_SIZE // stride, im.size[1]) # JPEG encoder expects multiple of 8 rows if compression == "jpeg": rows_per_strip = min(((rows_per_strip + 7) // 8) * 8, im.size[1])