mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
Added BigTIFF reading
This commit is contained in:
parent
37d28ce514
commit
fc7319318e
BIN
Tests/images/hopper_bigtiff.tif
Normal file
BIN
Tests/images/hopper_bigtiff.tif
Normal file
Binary file not shown.
|
@ -87,6 +87,10 @@ class TestFileTiff:
|
|||
|
||||
assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
|
||||
|
||||
def test_bigtiff(self):
|
||||
with Image.open("Tests/images/hopper_bigtiff.tif") as im:
|
||||
assert_image_equal_tofile(im, "Tests/images/hopper.tif")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name,mode,size,offset",
|
||||
[
|
||||
|
|
|
@ -49,7 +49,7 @@ except ImportError:
|
|||
# PILLOW_VERSION was removed in Pillow 9.0.0.
|
||||
# Use __version__ instead.
|
||||
from . import ImageMode, TiffTags, UnidentifiedImageError, __version__, _plugins
|
||||
from ._binary import i32le
|
||||
from ._binary import i32le, o32be, o32le
|
||||
from ._util import deferred_error, isPath
|
||||
|
||||
|
||||
|
@ -1416,6 +1416,7 @@ class Image:
|
|||
"".join(self.info["Raw profile type exif"].split("\n")[3:])
|
||||
)
|
||||
elif hasattr(self, "tag_v2"):
|
||||
self._exif.bigtiff = self.tag_v2._bigtiff
|
||||
self._exif.endian = self.tag_v2._endian
|
||||
self._exif.load_from_fp(self.fp, self.tag_v2._offset)
|
||||
if exif_info is not None:
|
||||
|
@ -3423,6 +3424,7 @@ atexit.register(core.clear_cache)
|
|||
|
||||
class Exif(MutableMapping):
|
||||
endian = None
|
||||
bigtiff = False
|
||||
|
||||
def __init__(self):
|
||||
self._data = {}
|
||||
|
@ -3458,10 +3460,15 @@ class Exif(MutableMapping):
|
|||
return self._fixup_dict(info)
|
||||
|
||||
def _get_head(self):
|
||||
version = b"\x2B" if self.bigtiff else b"\x2A"
|
||||
if self.endian == "<":
|
||||
return b"II\x2A\x00\x08\x00\x00\x00"
|
||||
head = b"II" + version + b"\x00" + o32le(8)
|
||||
else:
|
||||
return b"MM\x00\x2A\x00\x00\x00\x08"
|
||||
head = b"MM\x00" + version + o32be(8)
|
||||
if self.bigtiff:
|
||||
head += o32le(8) if self.endian == "<" else o32be(8)
|
||||
head += b"\x00\x00\x00\x00"
|
||||
return head
|
||||
|
||||
def load(self, data):
|
||||
# Extract EXIF information. This is highly experimental,
|
||||
|
|
|
@ -260,6 +260,8 @@ PREFIXES = [
|
|||
b"II\x2A\x00", # Valid TIFF header with little-endian byte order
|
||||
b"MM\x2A\x00", # Invalid TIFF header, assume big-endian
|
||||
b"II\x00\x2A", # Invalid TIFF header, assume little-endian
|
||||
b"MM\x00\x2B", # BigTIFF with big-endian byte order
|
||||
b"II\x2B\x00", # BigTIFF with little-endian byte order
|
||||
]
|
||||
|
||||
|
||||
|
@ -502,11 +504,14 @@ class ImageFileDirectory_v2(MutableMapping):
|
|||
self._endian = "<"
|
||||
else:
|
||||
raise SyntaxError("not a TIFF IFD")
|
||||
self._bigtiff = ifh[2] == 43
|
||||
self.group = group
|
||||
self.tagtype = {}
|
||||
""" Dictionary of tag types """
|
||||
self.reset()
|
||||
(self.next,) = self._unpack("L", ifh[4:])
|
||||
(self.next,) = (
|
||||
self._unpack("Q", ifh[8:]) if self._bigtiff else self._unpack("L", ifh[4:])
|
||||
)
|
||||
self._legacy_api = False
|
||||
|
||||
prefix = property(lambda self: self._prefix)
|
||||
|
@ -699,6 +704,7 @@ class ImageFileDirectory_v2(MutableMapping):
|
|||
(TiffTags.FLOAT, "f", "float"),
|
||||
(TiffTags.DOUBLE, "d", "double"),
|
||||
(TiffTags.IFD, "L", "long"),
|
||||
(TiffTags.LONG8, "Q", "long8"),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -776,8 +782,17 @@ class ImageFileDirectory_v2(MutableMapping):
|
|||
self._offset = fp.tell()
|
||||
|
||||
try:
|
||||
for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]):
|
||||
tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12))
|
||||
tag_count = (
|
||||
self._unpack("Q", self._ensure_read(fp, 8))
|
||||
if self._bigtiff
|
||||
else self._unpack("H", self._ensure_read(fp, 2))
|
||||
)[0]
|
||||
for i in range(tag_count):
|
||||
tag, typ, count, data = (
|
||||
self._unpack("HHQ8s", self._ensure_read(fp, 20))
|
||||
if self._bigtiff
|
||||
else self._unpack("HHL4s", self._ensure_read(fp, 12))
|
||||
)
|
||||
|
||||
tagname = TiffTags.lookup(tag, self.group).name
|
||||
typname = TYPES.get(typ, "unknown")
|
||||
|
@ -789,9 +804,9 @@ class ImageFileDirectory_v2(MutableMapping):
|
|||
logger.debug(msg + f" - unsupported type {typ}")
|
||||
continue # ignore unsupported type
|
||||
size = count * unit_size
|
||||
if size > 4:
|
||||
if size > (8 if self._bigtiff else 4):
|
||||
here = fp.tell()
|
||||
(offset,) = self._unpack("L", data)
|
||||
(offset,) = self._unpack("Q" if self._bigtiff else "L", data)
|
||||
msg += f" Tag Location: {here} - Data Location: {offset}"
|
||||
fp.seek(offset)
|
||||
data = ImageFile._safe_read(fp, size)
|
||||
|
@ -820,7 +835,11 @@ class ImageFileDirectory_v2(MutableMapping):
|
|||
)
|
||||
logger.debug(msg)
|
||||
|
||||
(self.next,) = self._unpack("L", self._ensure_read(fp, 4))
|
||||
(self.next,) = (
|
||||
self._unpack("Q", self._ensure_read(fp, 8))
|
||||
if self._bigtiff
|
||||
else self._unpack("L", self._ensure_read(fp, 4))
|
||||
)
|
||||
except OSError as msg:
|
||||
warnings.warn(str(msg))
|
||||
return
|
||||
|
@ -1042,6 +1061,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
|
||||
# Header
|
||||
ifh = self.fp.read(8)
|
||||
if ifh[2] == 43:
|
||||
ifh += self.fp.read(8)
|
||||
|
||||
self.tag_v2 = ImageFileDirectory_v2(ifh)
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ SIGNED_RATIONAL = 10
|
|||
FLOAT = 11
|
||||
DOUBLE = 12
|
||||
IFD = 13
|
||||
LONG8 = 16
|
||||
|
||||
TAGS_V2 = {
|
||||
254: ("NewSubfileType", LONG, 1),
|
||||
|
|
Loading…
Reference in New Issue
Block a user