Skip to content

Commit a8381c6

Browse files
committed
Allow upgrading LONG to LONG8
1 parent 618339e commit a8381c6

2 files changed

Lines changed: 50 additions & 15 deletions

File tree

Tests/test_file_tiff.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ def im_generator(ims: list[Image.Image]) -> Generator[Image.Image, None, None]:
746746
assert reread.n_frames == 3
747747

748748
def test_fixoffsets(self) -> None:
749-
b = BytesIO(b"II\x2a\x00\x00\x00\x00\x00")
749+
b = BytesIO(b"II\x2A\x00\x00\x00\x00\x00")
750750
with TiffImagePlugin.AppendingTiffWriter(b) as a:
751751
b.seek(0)
752752
a.fixOffsets(1, isShort=True)
@@ -759,13 +759,37 @@ def test_fixoffsets(self) -> None:
759759
with pytest.raises(RuntimeError):
760760
a.fixOffsets(1)
761761

762+
b = BytesIO(b"II\x2A\x00\x00\x00\x00\x00")
763+
with TiffImagePlugin.AppendingTiffWriter(b) as a:
764+
a.offsetOfNewPage = 2**16
765+
766+
b.seek(0)
767+
a.fixOffsets(1, isShort=True)
768+
769+
b = BytesIO(b"II\x2B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
770+
with TiffImagePlugin.AppendingTiffWriter(b) as a:
771+
a.offsetOfNewPage = 2**32
772+
773+
b.seek(0)
774+
a.fixOffsets(1, isShort=True)
775+
776+
b.seek(0)
777+
a.fixOffsets(1, isLong=True)
778+
762779
def test_appending_tiff_writer_writelong(self) -> None:
763780
data = b"II\x2A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
764781
b = BytesIO(data)
765782
with TiffImagePlugin.AppendingTiffWriter(b) as a:
766783
a.writeLong(2**32 - 1)
767784
assert b.getvalue() == data + b"\xff\xff\xff\xff"
768785

786+
def test_appending_tiff_writer_rewritelastshorttolong(self) -> None:
787+
data = b"II\x2A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
788+
b = BytesIO(data)
789+
with TiffImagePlugin.AppendingTiffWriter(b) as a:
790+
a.rewriteLastShortToLong(2**32 - 1)
791+
assert b.getvalue() == data[:-2] + b"\xff\xff\xff\xff"
792+
769793
def test_saving_icc_profile(self, tmp_path: Path) -> None:
770794
# Tests saving TIFF with icc_profile set.
771795
# At the time of writing this will only work for non-compressed tiffs

src/PIL/TiffImagePlugin.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,17 +2175,19 @@ def _verify_bytes_written(bytes_written: int | None, expected: int) -> None:
21752175
msg = f"wrote only {bytes_written} bytes but wanted {expected}"
21762176
raise RuntimeError(msg)
21772177

2178-
def rewriteLastShortToLong(self, value: int) -> None:
2179-
self.f.seek(-2, os.SEEK_CUR)
2180-
bytes_written = self.f.write(struct.pack(self.longFmt, value))
2181-
self._verify_bytes_written(bytes_written, 4)
2182-
2183-
def _rewriteLast(self, value: int, field_size: int) -> None:
2178+
def _rewriteLast(
2179+
self, value: int, field_size: int, new_field_size: int = 0
2180+
) -> None:
21842181
self.f.seek(-field_size, os.SEEK_CUR)
2182+
if not new_field_size:
2183+
new_field_size = field_size
21852184
bytes_written = self.f.write(
2186-
struct.pack(self.endian + self._fmt(field_size), value)
2185+
struct.pack(self.endian + self._fmt(new_field_size), value)
21872186
)
2188-
self._verify_bytes_written(bytes_written, field_size)
2187+
self._verify_bytes_written(bytes_written, new_field_size)
2188+
2189+
def rewriteLastShortToLong(self, value: int) -> None:
2190+
self._rewriteLast(value, 2, 4)
21892191

21902192
def rewriteLastShort(self, value: int) -> None:
21912193
return self._rewriteLast(value, 2)
@@ -2245,18 +2247,27 @@ def _fixOffsets(self, count: int, field_size: int) -> None:
22452247
for i in range(count):
22462248
offset = self._read(field_size)
22472249
offset += self.offsetOfNewPage
2248-
if field_size == 2 and offset >= 65536:
2249-
# offset is now too large - we must convert shorts to longs
2250+
2251+
new_field_size = 0
2252+
if self._bigtiff and field_size in (2, 4) and offset >= 2**32:
2253+
# offset is now too large - we must convert long to long8
2254+
new_field_size = 8
2255+
elif field_size == 2 and offset >= 2**16:
2256+
# offset is now too large - we must convert short to long
2257+
new_field_size = 4
2258+
if new_field_size:
22502259
if count != 1:
22512260
msg = "not implemented"
22522261
raise RuntimeError(msg) # XXX TODO
22532262

22542263
# simple case - the offset is just one and therefore it is
22552264
# local (not referenced with another offset)
2256-
self.rewriteLastShortToLong(offset)
2257-
self.f.seek(-10, os.SEEK_CUR)
2258-
self.writeShort(TiffTags.LONG) # rewrite the type to LONG
2259-
self.f.seek(8, os.SEEK_CUR)
2265+
self._rewriteLast(offset, field_size, new_field_size)
2266+
# Move back past the new offset, past 'count', and before 'field_type'
2267+
rewind = -new_field_size - 4 - 2
2268+
self.f.seek(rewind, os.SEEK_CUR)
2269+
self.writeShort(new_field_size) # rewrite the type
2270+
self.f.seek(2 - rewind, os.SEEK_CUR)
22602271
else:
22612272
self._rewriteLast(offset, field_size)
22622273

0 commit comments

Comments
 (0)