Merge pull request #5514 from kmilos/fix_tiff_rowsperstrip

This commit is contained in:
Hugo van Kemenade 2021-06-30 17:31:42 +03:00 committed by GitHub
commit 861a031304
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 5 deletions

View File

@ -9,7 +9,7 @@ from ctypes import c_float
import pytest import pytest
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features
from PIL.TiffImagePlugin import SUBIFD from PIL.TiffImagePlugin import STRIPOFFSETS, SUBIFD
from .helper import ( from .helper import (
assert_image_equal, assert_image_equal,
@ -967,3 +967,12 @@ class TestFileLibTiff(LibTiffTestCase):
# Assert that the error code is IMAGING_CODEC_MEMORY # Assert that the error code is IMAGING_CODEC_MEMORY
assert str(e.value) == "-9" assert str(e.value) == "-9"
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False
def test_save_multistrip(self, tmp_path):
im = hopper("RGB").resize((256, 256))
out = str(tmp_path / "temp.tif")
im.save(out, compression="tiff_adobe_deflate")
with Image.open(out) as im:
# Assert that there are multiple strips
assert len(im.tag_v2[STRIPOFFSETS]) > 1

View File

@ -1574,12 +1574,22 @@ def _save(im, fp, filename):
ifd[COLORMAP] = tuple(v * 256 for v in lut) ifd[COLORMAP] = tuple(v * 256 for v in lut)
# data orientation # data orientation
stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8) stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
ifd[ROWSPERSTRIP] = im.size[1] # aim for 64 KB strips when using libtiff writer
strip_byte_counts = stride * im.size[1] if libtiff:
rows_per_strip = min((2 ** 16 + stride - 1) // stride, im.size[1])
else:
rows_per_strip = im.size[1]
strip_byte_counts = stride * rows_per_strip
strips_per_image = (im.size[1] + rows_per_strip - 1) // rows_per_strip
ifd[ROWSPERSTRIP] = rows_per_strip
if strip_byte_counts >= 2 ** 16: if strip_byte_counts >= 2 ** 16:
ifd.tagtype[STRIPBYTECOUNTS] = TiffTags.LONG ifd.tagtype[STRIPBYTECOUNTS] = TiffTags.LONG
ifd[STRIPBYTECOUNTS] = strip_byte_counts ifd[STRIPBYTECOUNTS] = (strip_byte_counts,) * (strips_per_image - 1) + (
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer stride * im.size[1] - strip_byte_counts * (strips_per_image - 1),
)
ifd[STRIPOFFSETS] = tuple(
range(0, strip_byte_counts * strips_per_image, strip_byte_counts)
) # this is adjusted by IFD writer
# no compression by default: # no compression by default:
ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1) ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)