Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,45 @@ def test_bigtiff_save_big_endian_ifd(self, tmp_path: Path) -> None:
ifd.load(BytesIO(data))
assert ifd.tagtype[32768] == TiffTags.LONG8

def test_bigtiff_save_two_strips(self, tmp_path: Path) -> None:
outfile = tmp_path / "temp.tif"
im = hopper("L")

# Two LONG strip offsets fit within a BigTIFF entry
im.save(outfile, big_tiff=True, tiffinfo={TiffImagePlugin.ROWSPERSTRIP: 64})

with Image.open(outfile) as reloaded:
assert isinstance(reloaded, TiffImagePlugin.TiffImageFile)
assert len(reloaded.tag_v2[TiffImagePlugin.STRIPOFFSETS]) == 2
assert_image_equal(reloaded, im)

def test_bigtiff_save_big_endian_strip_offset(self, tmp_path: Path) -> None:
outfile = tmp_path / "temp.tif"
# I;16B is saved as big-endian
im = hopper("I;16B")

# The single LONG strip offset fits within a BigTIFF entry
im.save(outfile, big_tiff=True)

with Image.open(outfile) as reloaded:
assert isinstance(reloaded, TiffImagePlugin.TiffImageFile)
assert reloaded.tag_v2.prefix == b"MM"
assert reloaded.tag_v2._bigtiff is True
assert (
reloaded.tag_v2.tagtype[TiffImagePlugin.STRIPOFFSETS] == TiffTags.LONG
)
assert len(reloaded.tag_v2[TiffImagePlugin.STRIPOFFSETS]) == 1
assert_image_equal(reloaded, im)

# Check that the strip offset is upgraded to LONG8
# when it is too large for a LONG
data = reloaded.tag_v2.tobytes(2**32)

ifd = TiffImagePlugin.ImageFileDirectory_v2(b"MM\x00\x2b" + b"\x00" * 12)
ifd.load(BytesIO(data))
assert ifd.tagtype[TiffImagePlugin.STRIPOFFSETS] == TiffTags.LONG8
assert ifd[TiffImagePlugin.STRIPOFFSETS][0] > 2**32

def test_seek_too_large(self) -> None:
with pytest.raises(ValueError, match="Unable to seek to frame"):
Image.open("Tests/images/seek_too_large.tif")
Expand Down
19 changes: 16 additions & 3 deletions src/PIL/TiffImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,12 +1054,25 @@ def tobytes(self, offset: int = 0) -> bytes:
# update strip offset data to point beyond auxiliary data
if stripoffsets is not None:
tag, typ, count, value, data = entries[stripoffsets]
size, handler = self._load_dispatch[typ]
values = [
val + offset for val in handler(self, data or value, self.legacy_api)
]
if data:
size, handler = self._load_dispatch[typ]
values = [val + offset for val in handler(self, data, self.legacy_api)]
data = self._write_dispatch[typ](self, *values)
else:
value = self._pack(fmt, self._unpack(fmt, value)[0] + offset)
# The offsets fit within the entry
# May be one offset, or two LONG offsets in BigTIFF
if (
self._bigtiff
and typ == TiffTags.LONG
and count == 1
and values[0] >= 2**32
):
# If a single offset is too large for a LONG,
# in BigTIFF there is room to change the entry to LONG8
typ = TiffTags.LONG8
value = self._write_dispatch[typ](self, *values).ljust(fmt_size, b"\0")
entries[stripoffsets] = tag, typ, count, value, data

# pass 2: write entries to file
Expand Down
Loading