|
36 | 36 | import sys
|
37 | 37 | from typing import IO, TYPE_CHECKING, Any, NamedTuple, cast
|
38 | 38 |
|
39 |
| -from . import Image |
| 39 | +from . import ExifTags, Image |
40 | 40 | from ._deprecate import deprecate
|
41 | 41 | from ._util import is_path
|
42 | 42 |
|
@@ -163,6 +163,57 @@ def __init__(
|
163 | 163 | def _open(self) -> None:
|
164 | 164 | pass
|
165 | 165 |
|
| 166 | + def get_child_images(self) -> list[ImageFile]: |
| 167 | + child_images = [] |
| 168 | + exif = self.getexif() |
| 169 | + ifds = [] |
| 170 | + if ExifTags.Base.SubIFDs in exif: |
| 171 | + subifd_offsets = exif[ExifTags.Base.SubIFDs] |
| 172 | + if subifd_offsets: |
| 173 | + if not isinstance(subifd_offsets, tuple): |
| 174 | + subifd_offsets = (subifd_offsets,) |
| 175 | + for subifd_offset in subifd_offsets: |
| 176 | + ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset)) |
| 177 | + ifd1 = exif.get_ifd(ExifTags.IFD.IFD1) |
| 178 | + if ifd1 and ifd1.get(ExifTags.Base.JpegIFOffset): |
| 179 | + assert exif._info is not None |
| 180 | + ifds.append((ifd1, exif._info.next)) |
| 181 | + |
| 182 | + offset = None |
| 183 | + for ifd, ifd_offset in ifds: |
| 184 | + assert self.fp is not None |
| 185 | + current_offset = self.fp.tell() |
| 186 | + if offset is None: |
| 187 | + offset = current_offset |
| 188 | + |
| 189 | + fp = self.fp |
| 190 | + if ifd is not None: |
| 191 | + thumbnail_offset = ifd.get(ExifTags.Base.JpegIFOffset) |
| 192 | + if thumbnail_offset is not None: |
| 193 | + thumbnail_offset += getattr(self, "_exif_offset", 0) |
| 194 | + self.fp.seek(thumbnail_offset) |
| 195 | + |
| 196 | + length = ifd.get(ExifTags.Base.JpegIFByteCount) |
| 197 | + assert isinstance(length, int) |
| 198 | + data = self.fp.read(length) |
| 199 | + fp = io.BytesIO(data) |
| 200 | + |
| 201 | + with Image.open(fp) as im: |
| 202 | + from . import TiffImagePlugin |
| 203 | + |
| 204 | + if thumbnail_offset is None and isinstance( |
| 205 | + im, TiffImagePlugin.TiffImageFile |
| 206 | + ): |
| 207 | + im._frame_pos = [ifd_offset] |
| 208 | + im._seek(0) |
| 209 | + im.load() |
| 210 | + child_images.append(im) |
| 211 | + |
| 212 | + if offset is not None: |
| 213 | + assert self.fp is not None |
| 214 | + self.fp.seek(offset) |
| 215 | + return child_images |
| 216 | + |
166 | 217 | def get_format_mimetype(self) -> str | None:
|
167 | 218 | if self.custom_mimetype:
|
168 | 219 | return self.custom_mimetype
|
|
0 commit comments