Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PIL/Image.py: 45%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1716 statements  

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# the Image class wrapper 

6# 

7# partial release history: 

8# 1995-09-09 fl Created 

9# 1996-03-11 fl PIL release 0.0 (proof of concept) 

10# 1996-04-30 fl PIL release 0.1b1 

11# 1999-07-28 fl PIL release 1.0 final 

12# 2000-06-07 fl PIL release 1.1 

13# 2000-10-20 fl PIL release 1.1.1 

14# 2001-05-07 fl PIL release 1.1.2 

15# 2002-03-15 fl PIL release 1.1.3 

16# 2003-05-10 fl PIL release 1.1.4 

17# 2005-03-28 fl PIL release 1.1.5 

18# 2006-12-02 fl PIL release 1.1.6 

19# 2009-11-15 fl PIL release 1.1.7 

20# 

21# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved. 

22# Copyright (c) 1995-2009 by Fredrik Lundh. 

23# 

24# See the README file for information on usage and redistribution. 

25# 

26 

27from __future__ import annotations 

28 

29import abc 

30import atexit 

31import builtins 

32import io 

33import logging 

34import math 

35import os 

36import re 

37import struct 

38import sys 

39import tempfile 

40import warnings 

41from collections.abc import MutableMapping 

42from enum import IntEnum 

43from typing import IO, Protocol, cast 

44 

45# VERSION was removed in Pillow 6.0.0. 

46# PILLOW_VERSION was removed in Pillow 9.0.0. 

47# Use __version__ instead. 

48from . import ( 

49 ExifTags, 

50 ImageMode, 

51 TiffTags, 

52 UnidentifiedImageError, 

53 __version__, 

54 _plugins, 

55) 

56from ._binary import i32le, o32be, o32le 

57from ._deprecate import deprecate 

58from ._util import DeferredError, is_path 

59 

60ElementTree: ModuleType | None 

61try: 

62 from defusedxml import ElementTree 

63except ImportError: 

64 ElementTree = None 

65 

66TYPE_CHECKING = False 

67if TYPE_CHECKING: 

68 from collections.abc import Callable, Iterator, Sequence 

69 from types import ModuleType 

70 from typing import Any, Literal 

71 

72logger = logging.getLogger(__name__) 

73 

74 

75class DecompressionBombWarning(RuntimeWarning): 

76 pass 

77 

78 

79class DecompressionBombError(Exception): 

80 pass 

81 

82 

83WARN_POSSIBLE_FORMATS: bool = False 

84 

85# Limit to around a quarter gigabyte for a 24-bit (3 bpp) image 

86MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3) 

87 

88 

89try: 

90 # If the _imaging C module is not present, Pillow will not load. 

91 # Note that other modules should not refer to _imaging directly; 

92 # import Image and use the Image.core variable instead. 

93 # Also note that Image.core is not a publicly documented interface, 

94 # and should be considered private and subject to change. 

95 from . import _imaging as core 

96 

97 if __version__ != getattr(core, "PILLOW_VERSION", None): 

98 msg = ( 

99 "The _imaging extension was built for another version of Pillow or PIL:\n" 

100 f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n" 

101 f"Pillow version: {__version__}" 

102 ) 

103 raise ImportError(msg) 

104 

105except ImportError as v: 

106 # Explanations for ways that we know we might have an import error 

107 if str(v).startswith("Module use of python"): 

108 # The _imaging C module is present, but not compiled for 

109 # the right version (windows only). Print a warning, if 

110 # possible. 

111 warnings.warn( 

112 "The _imaging extension was built for another version of Python.", 

113 RuntimeWarning, 

114 ) 

115 elif str(v).startswith("The _imaging extension"): 

116 warnings.warn(str(v), RuntimeWarning) 

117 # Fail here anyway. Don't let people run with a mostly broken Pillow. 

118 # see docs/porting.rst 

119 raise 

120 

121 

122# 

123# Constants 

124 

125 

126# transpose 

127class Transpose(IntEnum): 

128 FLIP_LEFT_RIGHT = 0 

129 FLIP_TOP_BOTTOM = 1 

130 ROTATE_90 = 2 

131 ROTATE_180 = 3 

132 ROTATE_270 = 4 

133 TRANSPOSE = 5 

134 TRANSVERSE = 6 

135 

136 

137# transforms (also defined in Imaging.h) 

138class Transform(IntEnum): 

139 AFFINE = 0 

140 EXTENT = 1 

141 PERSPECTIVE = 2 

142 QUAD = 3 

143 MESH = 4 

144 

145 

146# resampling filters (also defined in Imaging.h) 

147class Resampling(IntEnum): 

148 NEAREST = 0 

149 BOX = 4 

150 BILINEAR = 2 

151 HAMMING = 5 

152 BICUBIC = 3 

153 LANCZOS = 1 

154 

155 

156_filters_support = { 

157 Resampling.BOX: 0.5, 

158 Resampling.BILINEAR: 1.0, 

159 Resampling.HAMMING: 1.0, 

160 Resampling.BICUBIC: 2.0, 

161 Resampling.LANCZOS: 3.0, 

162} 

163 

164 

165# dithers 

166class Dither(IntEnum): 

167 NONE = 0 

168 ORDERED = 1 # Not yet implemented 

169 RASTERIZE = 2 # Not yet implemented 

170 FLOYDSTEINBERG = 3 # default 

171 

172 

173# palettes/quantizers 

174class Palette(IntEnum): 

175 WEB = 0 

176 ADAPTIVE = 1 

177 

178 

179class Quantize(IntEnum): 

180 MEDIANCUT = 0 

181 MAXCOVERAGE = 1 

182 FASTOCTREE = 2 

183 LIBIMAGEQUANT = 3 

184 

185 

186module = sys.modules[__name__] 

187for enum in (Transpose, Transform, Resampling, Dither, Palette, Quantize): 

188 for item in enum: 

189 setattr(module, item.name, item.value) 

190 

191 

192if hasattr(core, "DEFAULT_STRATEGY"): 

193 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

194 FILTERED = core.FILTERED 

195 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

196 RLE = core.RLE 

197 FIXED = core.FIXED 

198 

199 

200# -------------------------------------------------------------------- 

201# Registries 

202 

203TYPE_CHECKING = False 

204if TYPE_CHECKING: 

205 import mmap 

206 from xml.etree.ElementTree import Element 

207 

208 from IPython.lib.pretty import PrettyPrinter 

209 

210 from . import ImageFile, ImageFilter, ImagePalette, ImageQt, TiffImagePlugin 

211 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath 

212ID: list[str] = [] 

213OPEN: dict[ 

214 str, 

215 tuple[ 

216 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile], 

217 Callable[[bytes], bool | str] | None, 

218 ], 

219] = {} 

220MIME: dict[str, str] = {} 

221SAVE: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {} 

222SAVE_ALL: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {} 

223EXTENSION: dict[str, str] = {} 

224DECODERS: dict[str, type[ImageFile.PyDecoder]] = {} 

225ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {} 

226 

227# -------------------------------------------------------------------- 

228# Modes 

229 

230_ENDIAN = "<" if sys.byteorder == "little" else ">" 

231 

232 

233def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]: 

234 m = ImageMode.getmode(im.mode) 

235 shape: tuple[int, ...] = (im.height, im.width) 

236 extra = len(m.bands) 

237 if extra != 1: 

238 shape += (extra,) 

239 return shape, m.typestr 

240 

241 

242MODES = [ 

243 "1", 

244 "CMYK", 

245 "F", 

246 "HSV", 

247 "I", 

248 "I;16", 

249 "I;16B", 

250 "I;16L", 

251 "I;16N", 

252 "L", 

253 "LA", 

254 "La", 

255 "LAB", 

256 "P", 

257 "PA", 

258 "RGB", 

259 "RGBA", 

260 "RGBa", 

261 "RGBX", 

262 "YCbCr", 

263] 

264 

265# raw modes that may be memory mapped. NOTE: if you change this, you 

266# may have to modify the stride calculation in map.c too! 

267_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B") 

268 

269 

270def getmodebase(mode: str) -> str: 

271 """ 

272 Gets the "base" mode for given mode. This function returns "L" for 

273 images that contain grayscale data, and "RGB" for images that 

274 contain color data. 

275 

276 :param mode: Input mode. 

277 :returns: "L" or "RGB". 

278 :exception KeyError: If the input mode was not a standard mode. 

279 """ 

280 return ImageMode.getmode(mode).basemode 

281 

282 

283def getmodetype(mode: str) -> str: 

284 """ 

285 Gets the storage type mode. Given a mode, this function returns a 

286 single-layer mode suitable for storing individual bands. 

287 

288 :param mode: Input mode. 

289 :returns: "L", "I", or "F". 

290 :exception KeyError: If the input mode was not a standard mode. 

291 """ 

292 return ImageMode.getmode(mode).basetype 

293 

294 

295def getmodebandnames(mode: str) -> tuple[str, ...]: 

296 """ 

297 Gets a list of individual band names. Given a mode, this function returns 

298 a tuple containing the names of individual bands (use 

299 :py:method:`~PIL.Image.getmodetype` to get the mode used to store each 

300 individual band. 

301 

302 :param mode: Input mode. 

303 :returns: A tuple containing band names. The length of the tuple 

304 gives the number of bands in an image of the given mode. 

305 :exception KeyError: If the input mode was not a standard mode. 

306 """ 

307 return ImageMode.getmode(mode).bands 

308 

309 

310def getmodebands(mode: str) -> int: 

311 """ 

312 Gets the number of individual bands for this mode. 

313 

314 :param mode: Input mode. 

315 :returns: The number of bands in this mode. 

316 :exception KeyError: If the input mode was not a standard mode. 

317 """ 

318 return len(ImageMode.getmode(mode).bands) 

319 

320 

321# -------------------------------------------------------------------- 

322# Helpers 

323 

324_initialized = 0 

325 

326 

327def preinit() -> None: 

328 """ 

329 Explicitly loads BMP, GIF, JPEG, PPM and PPM file format drivers. 

330 

331 It is called when opening or saving images. 

332 """ 

333 

334 global _initialized 

335 if _initialized >= 1: 

336 return 

337 

338 try: 

339 from . import BmpImagePlugin 

340 

341 assert BmpImagePlugin 

342 except ImportError: 

343 pass 

344 try: 

345 from . import GifImagePlugin 

346 

347 assert GifImagePlugin 

348 except ImportError: 

349 pass 

350 try: 

351 from . import JpegImagePlugin 

352 

353 assert JpegImagePlugin 

354 except ImportError: 

355 pass 

356 try: 

357 from . import PpmImagePlugin 

358 

359 assert PpmImagePlugin 

360 except ImportError: 

361 pass 

362 try: 

363 from . import PngImagePlugin 

364 

365 assert PngImagePlugin 

366 except ImportError: 

367 pass 

368 

369 _initialized = 1 

370 

371 

372def init() -> bool: 

373 """ 

374 Explicitly initializes the Python Imaging Library. This function 

375 loads all available file format drivers. 

376 

377 It is called when opening or saving images if :py:meth:`~preinit()` is 

378 insufficient, and by :py:meth:`~PIL.features.pilinfo`. 

379 """ 

380 

381 global _initialized 

382 if _initialized >= 2: 

383 return False 

384 

385 parent_name = __name__.rpartition(".")[0] 

386 for plugin in _plugins: 

387 try: 

388 logger.debug("Importing %s", plugin) 

389 __import__(f"{parent_name}.{plugin}", globals(), locals(), []) 

390 except ImportError as e: 

391 logger.debug("Image: failed to import %s: %s", plugin, e) 

392 

393 if OPEN or SAVE: 

394 _initialized = 2 

395 return True 

396 return False 

397 

398 

399# -------------------------------------------------------------------- 

400# Codec factories (used by tobytes/frombytes and ImageFile.load) 

401 

402 

403def _getdecoder( 

404 mode: str, decoder_name: str, args: Any, extra: tuple[Any, ...] = () 

405) -> core.ImagingDecoder | ImageFile.PyDecoder: 

406 # tweak arguments 

407 if args is None: 

408 args = () 

409 elif not isinstance(args, tuple): 

410 args = (args,) 

411 

412 try: 

413 decoder = DECODERS[decoder_name] 

414 except KeyError: 

415 pass 

416 else: 

417 return decoder(mode, *args + extra) 

418 

419 try: 

420 # get decoder 

421 decoder = getattr(core, f"{decoder_name}_decoder") 

422 except AttributeError as e: 

423 msg = f"decoder {decoder_name} not available" 

424 raise OSError(msg) from e 

425 return decoder(mode, *args + extra) 

426 

427 

428def _getencoder( 

429 mode: str, encoder_name: str, args: Any, extra: tuple[Any, ...] = () 

430) -> core.ImagingEncoder | ImageFile.PyEncoder: 

431 # tweak arguments 

432 if args is None: 

433 args = () 

434 elif not isinstance(args, tuple): 

435 args = (args,) 

436 

437 try: 

438 encoder = ENCODERS[encoder_name] 

439 except KeyError: 

440 pass 

441 else: 

442 return encoder(mode, *args + extra) 

443 

444 try: 

445 # get encoder 

446 encoder = getattr(core, f"{encoder_name}_encoder") 

447 except AttributeError as e: 

448 msg = f"encoder {encoder_name} not available" 

449 raise OSError(msg) from e 

450 return encoder(mode, *args + extra) 

451 

452 

453# -------------------------------------------------------------------- 

454# Simple expression analyzer 

455 

456 

457class ImagePointTransform: 

458 """ 

459 Used with :py:meth:`~PIL.Image.Image.point` for single band images with more than 

460 8 bits, this represents an affine transformation, where the value is multiplied by 

461 ``scale`` and ``offset`` is added. 

462 """ 

463 

464 def __init__(self, scale: float, offset: float) -> None: 

465 self.scale = scale 

466 self.offset = offset 

467 

468 def __neg__(self) -> ImagePointTransform: 

469 return ImagePointTransform(-self.scale, -self.offset) 

470 

471 def __add__(self, other: ImagePointTransform | float) -> ImagePointTransform: 

472 if isinstance(other, ImagePointTransform): 

473 return ImagePointTransform( 

474 self.scale + other.scale, self.offset + other.offset 

475 ) 

476 return ImagePointTransform(self.scale, self.offset + other) 

477 

478 __radd__ = __add__ 

479 

480 def __sub__(self, other: ImagePointTransform | float) -> ImagePointTransform: 

481 return self + -other 

482 

483 def __rsub__(self, other: ImagePointTransform | float) -> ImagePointTransform: 

484 return other + -self 

485 

486 def __mul__(self, other: ImagePointTransform | float) -> ImagePointTransform: 

487 if isinstance(other, ImagePointTransform): 

488 return NotImplemented 

489 return ImagePointTransform(self.scale * other, self.offset * other) 

490 

491 __rmul__ = __mul__ 

492 

493 def __truediv__(self, other: ImagePointTransform | float) -> ImagePointTransform: 

494 if isinstance(other, ImagePointTransform): 

495 return NotImplemented 

496 return ImagePointTransform(self.scale / other, self.offset / other) 

497 

498 

499def _getscaleoffset( 

500 expr: Callable[[ImagePointTransform], ImagePointTransform | float], 

501) -> tuple[float, float]: 

502 a = expr(ImagePointTransform(1, 0)) 

503 return (a.scale, a.offset) if isinstance(a, ImagePointTransform) else (0, a) 

504 

505 

506# -------------------------------------------------------------------- 

507# Implementation wrapper 

508 

509 

510class SupportsGetData(Protocol): 

511 def getdata( 

512 self, 

513 ) -> tuple[Transform, Sequence[int]]: ... 

514 

515 

516class Image: 

517 """ 

518 This class represents an image object. To create 

519 :py:class:`~PIL.Image.Image` objects, use the appropriate factory 

520 functions. There's hardly ever any reason to call the Image constructor 

521 directly. 

522 

523 * :py:func:`~PIL.Image.open` 

524 * :py:func:`~PIL.Image.new` 

525 * :py:func:`~PIL.Image.frombytes` 

526 """ 

527 

528 format: str | None = None 

529 format_description: str | None = None 

530 _close_exclusive_fp_after_loading = True 

531 

532 def __init__(self) -> None: 

533 # FIXME: take "new" parameters / other image? 

534 self._im: core.ImagingCore | DeferredError | None = None 

535 self._mode = "" 

536 self._size = (0, 0) 

537 self.palette: ImagePalette.ImagePalette | None = None 

538 self.info: dict[str | tuple[int, int], Any] = {} 

539 self.readonly = 0 

540 self._exif: Exif | None = None 

541 

542 @property 

543 def im(self) -> core.ImagingCore: 

544 if isinstance(self._im, DeferredError): 

545 raise self._im.ex 

546 assert self._im is not None 

547 return self._im 

548 

549 @im.setter 

550 def im(self, im: core.ImagingCore) -> None: 

551 self._im = im 

552 

553 @property 

554 def width(self) -> int: 

555 return self.size[0] 

556 

557 @property 

558 def height(self) -> int: 

559 return self.size[1] 

560 

561 @property 

562 def size(self) -> tuple[int, int]: 

563 return self._size 

564 

565 @property 

566 def mode(self) -> str: 

567 return self._mode 

568 

569 @property 

570 def readonly(self) -> int: 

571 return (self._im and self._im.readonly) or self._readonly 

572 

573 @readonly.setter 

574 def readonly(self, readonly: int) -> None: 

575 self._readonly = readonly 

576 

577 def _new(self, im: core.ImagingCore) -> Image: 

578 new = Image() 

579 new.im = im 

580 new._mode = im.mode 

581 new._size = im.size 

582 if im.mode in ("P", "PA"): 

583 if self.palette: 

584 new.palette = self.palette.copy() 

585 else: 

586 from . import ImagePalette 

587 

588 new.palette = ImagePalette.ImagePalette() 

589 new.info = self.info.copy() 

590 return new 

591 

592 # Context manager support 

593 def __enter__(self): 

594 return self 

595 

596 def __exit__(self, *args): 

597 from . import ImageFile 

598 

599 if isinstance(self, ImageFile.ImageFile): 

600 if getattr(self, "_exclusive_fp", False): 

601 self._close_fp() 

602 self.fp = None 

603 

604 def close(self) -> None: 

605 """ 

606 This operation will destroy the image core and release its memory. 

607 The image data will be unusable afterward. 

608 

609 This function is required to close images that have multiple frames or 

610 have not had their file read and closed by the 

611 :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for 

612 more information. 

613 """ 

614 if getattr(self, "map", None): 

615 if sys.platform == "win32" and hasattr(sys, "pypy_version_info"): 

616 self.map.close() 

617 self.map: mmap.mmap | None = None 

618 

619 # Instead of simply setting to None, we're setting up a 

620 # deferred error that will better explain that the core image 

621 # object is gone. 

622 self._im = DeferredError(ValueError("Operation on closed image")) 

623 

624 def _copy(self) -> None: 

625 self.load() 

626 self.im = self.im.copy() 

627 self.readonly = 0 

628 

629 def _ensure_mutable(self) -> None: 

630 if self.readonly: 

631 self._copy() 

632 else: 

633 self.load() 

634 

635 def _dump( 

636 self, file: str | None = None, format: str | None = None, **options: Any 

637 ) -> str: 

638 suffix = "" 

639 if format: 

640 suffix = f".{format}" 

641 

642 if not file: 

643 f, filename = tempfile.mkstemp(suffix) 

644 os.close(f) 

645 else: 

646 filename = file 

647 if not filename.endswith(suffix): 

648 filename = filename + suffix 

649 

650 self.load() 

651 

652 if not format or format == "PPM": 

653 self.im.save_ppm(filename) 

654 else: 

655 self.save(filename, format, **options) 

656 

657 return filename 

658 

659 def __eq__(self, other: object) -> bool: 

660 if self.__class__ is not other.__class__: 

661 return False 

662 assert isinstance(other, Image) 

663 return ( 

664 self.mode == other.mode 

665 and self.size == other.size 

666 and self.info == other.info 

667 and self.getpalette() == other.getpalette() 

668 and self.tobytes() == other.tobytes() 

669 ) 

670 

671 def __repr__(self) -> str: 

672 return ( 

673 f"<{self.__class__.__module__}.{self.__class__.__name__} " 

674 f"image mode={self.mode} size={self.size[0]}x{self.size[1]} " 

675 f"at 0x{id(self):X}>" 

676 ) 

677 

678 def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None: 

679 """IPython plain text display support""" 

680 

681 # Same as __repr__ but without unpredictable id(self), 

682 # to keep Jupyter notebook `text/plain` output stable. 

683 p.text( 

684 f"<{self.__class__.__module__}.{self.__class__.__name__} " 

685 f"image mode={self.mode} size={self.size[0]}x{self.size[1]}>" 

686 ) 

687 

688 def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None: 

689 """Helper function for iPython display hook. 

690 

691 :param image_format: Image format. 

692 :returns: image as bytes, saved into the given format. 

693 """ 

694 b = io.BytesIO() 

695 try: 

696 self.save(b, image_format, **kwargs) 

697 except Exception: 

698 return None 

699 return b.getvalue() 

700 

701 def _repr_png_(self) -> bytes | None: 

702 """iPython display hook support for PNG format. 

703 

704 :returns: PNG version of the image as bytes 

705 """ 

706 return self._repr_image("PNG", compress_level=1) 

707 

708 def _repr_jpeg_(self) -> bytes | None: 

709 """iPython display hook support for JPEG format. 

710 

711 :returns: JPEG version of the image as bytes 

712 """ 

713 return self._repr_image("JPEG") 

714 

715 @property 

716 def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]: 

717 # numpy array interface support 

718 new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3} 

719 if self.mode == "1": 

720 # Binary images need to be extended from bits to bytes 

721 # See: https://github.com/python-pillow/Pillow/issues/350 

722 new["data"] = self.tobytes("raw", "L") 

723 else: 

724 new["data"] = self.tobytes() 

725 new["shape"], new["typestr"] = _conv_type_shape(self) 

726 return new 

727 

728 def __arrow_c_schema__(self) -> object: 

729 self.load() 

730 return self.im.__arrow_c_schema__() 

731 

732 def __arrow_c_array__( 

733 self, requested_schema: object | None = None 

734 ) -> tuple[object, object]: 

735 self.load() 

736 return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__()) 

737 

738 def __getstate__(self) -> list[Any]: 

739 im_data = self.tobytes() # load image first 

740 return [self.info, self.mode, self.size, self.getpalette(), im_data] 

741 

742 def __setstate__(self, state: list[Any]) -> None: 

743 Image.__init__(self) 

744 info, mode, size, palette, data = state[:5] 

745 self.info = info 

746 self._mode = mode 

747 self._size = size 

748 self.im = core.new(mode, size) 

749 if mode in ("L", "LA", "P", "PA") and palette: 

750 self.putpalette(palette) 

751 self.frombytes(data) 

752 

753 def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes: 

754 """ 

755 Return image as a bytes object. 

756 

757 .. warning:: 

758 

759 This method returns raw image data derived from Pillow's internal 

760 storage. For compressed image data (e.g. PNG, JPEG) use 

761 :meth:`~.save`, with a BytesIO parameter for in-memory data. 

762 

763 :param encoder_name: What encoder to use. 

764 

765 The default is to use the standard "raw" encoder. 

766 To see how this packs pixel data into the returned 

767 bytes, see :file:`libImaging/Pack.c`. 

768 

769 A list of C encoders can be seen under codecs 

770 section of the function array in 

771 :file:`_imaging.c`. Python encoders are registered 

772 within the relevant plugins. 

773 :param args: Extra arguments to the encoder. 

774 :returns: A :py:class:`bytes` object. 

775 """ 

776 

777 encoder_args: Any = args 

778 if len(encoder_args) == 1 and isinstance(encoder_args[0], tuple): 

779 # may pass tuple instead of argument list 

780 encoder_args = encoder_args[0] 

781 

782 if encoder_name == "raw" and encoder_args == (): 

783 encoder_args = self.mode 

784 

785 self.load() 

786 

787 if self.width == 0 or self.height == 0: 

788 return b"" 

789 

790 # unpack data 

791 e = _getencoder(self.mode, encoder_name, encoder_args) 

792 e.setimage(self.im) 

793 

794 from . import ImageFile 

795 

796 bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c 

797 

798 output = [] 

799 while True: 

800 bytes_consumed, errcode, data = e.encode(bufsize) 

801 output.append(data) 

802 if errcode: 

803 break 

804 if errcode < 0: 

805 msg = f"encoder error {errcode} in tobytes" 

806 raise RuntimeError(msg) 

807 

808 return b"".join(output) 

809 

810 def tobitmap(self, name: str = "image") -> bytes: 

811 """ 

812 Returns the image converted to an X11 bitmap. 

813 

814 .. note:: This method only works for mode "1" images. 

815 

816 :param name: The name prefix to use for the bitmap variables. 

817 :returns: A string containing an X11 bitmap. 

818 :raises ValueError: If the mode is not "1" 

819 """ 

820 

821 self.load() 

822 if self.mode != "1": 

823 msg = "not a bitmap" 

824 raise ValueError(msg) 

825 data = self.tobytes("xbm") 

826 return b"".join( 

827 [ 

828 f"#define {name}_width {self.size[0]}\n".encode("ascii"), 

829 f"#define {name}_height {self.size[1]}\n".encode("ascii"), 

830 f"static char {name}_bits[] = {{\n".encode("ascii"), 

831 data, 

832 b"};", 

833 ] 

834 ) 

835 

836 def frombytes( 

837 self, 

838 data: bytes | bytearray | SupportsArrayInterface, 

839 decoder_name: str = "raw", 

840 *args: Any, 

841 ) -> None: 

842 """ 

843 Loads this image with pixel data from a bytes object. 

844 

845 This method is similar to the :py:func:`~PIL.Image.frombytes` function, 

846 but loads data into this image instead of creating a new image object. 

847 """ 

848 

849 if self.width == 0 or self.height == 0: 

850 return 

851 

852 decoder_args: Any = args 

853 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

854 # may pass tuple instead of argument list 

855 decoder_args = decoder_args[0] 

856 

857 # default format 

858 if decoder_name == "raw" and decoder_args == (): 

859 decoder_args = self.mode 

860 

861 # unpack data 

862 d = _getdecoder(self.mode, decoder_name, decoder_args) 

863 d.setimage(self.im) 

864 s = d.decode(data) 

865 

866 if s[0] >= 0: 

867 msg = "not enough image data" 

868 raise ValueError(msg) 

869 if s[1] != 0: 

870 msg = "cannot decode image data" 

871 raise ValueError(msg) 

872 

873 def load(self) -> core.PixelAccess | None: 

874 """ 

875 Allocates storage for the image and loads the pixel data. In 

876 normal cases, you don't need to call this method, since the 

877 Image class automatically loads an opened image when it is 

878 accessed for the first time. 

879 

880 If the file associated with the image was opened by Pillow, then this 

881 method will close it. The exception to this is if the image has 

882 multiple frames, in which case the file will be left open for seek 

883 operations. See :ref:`file-handling` for more information. 

884 

885 :returns: An image access object. 

886 :rtype: :py:class:`.PixelAccess` 

887 """ 

888 if self._im is not None and self.palette and self.palette.dirty: 

889 # realize palette 

890 mode, arr = self.palette.getdata() 

891 self.im.putpalette(self.palette.mode, mode, arr) 

892 self.palette.dirty = 0 

893 self.palette.rawmode = None 

894 if "transparency" in self.info and mode in ("LA", "PA"): 

895 if isinstance(self.info["transparency"], int): 

896 self.im.putpalettealpha(self.info["transparency"], 0) 

897 else: 

898 self.im.putpalettealphas(self.info["transparency"]) 

899 self.palette.mode = "RGBA" 

900 else: 

901 self.palette.palette = self.im.getpalette( 

902 self.palette.mode, self.palette.mode 

903 ) 

904 

905 if self._im is not None: 

906 return self.im.pixel_access(self.readonly) 

907 return None 

908 

909 def verify(self) -> None: 

910 """ 

911 Verifies the contents of a file. For data read from a file, this 

912 method attempts to determine if the file is broken, without 

913 actually decoding the image data. If this method finds any 

914 problems, it raises suitable exceptions. If you need to load 

915 the image after using this method, you must reopen the image 

916 file. 

917 """ 

918 pass 

919 

920 def convert( 

921 self, 

922 mode: str | None = None, 

923 matrix: tuple[float, ...] | None = None, 

924 dither: Dither | None = None, 

925 palette: Palette = Palette.WEB, 

926 colors: int = 256, 

927 ) -> Image: 

928 """ 

929 Returns a converted copy of this image. For the "P" mode, this 

930 method translates pixels through the palette. If mode is 

931 omitted, a mode is chosen so that all information in the image 

932 and the palette can be represented without a palette. 

933 

934 This supports all possible conversions between "L", "RGB" and "CMYK". The 

935 ``matrix`` argument only supports "L" and "RGB". 

936 

937 When translating a color image to grayscale (mode "L"), 

938 the library uses the ITU-R 601-2 luma transform:: 

939 

940 L = R * 299/1000 + G * 587/1000 + B * 114/1000 

941 

942 The default method of converting a grayscale ("L") or "RGB" 

943 image into a bilevel (mode "1") image uses Floyd-Steinberg 

944 dither to approximate the original image luminosity levels. If 

945 dither is ``None``, all values larger than 127 are set to 255 (white), 

946 all other values to 0 (black). To use other thresholds, use the 

947 :py:meth:`~PIL.Image.Image.point` method. 

948 

949 When converting from "RGBA" to "P" without a ``matrix`` argument, 

950 this passes the operation to :py:meth:`~PIL.Image.Image.quantize`, 

951 and ``dither`` and ``palette`` are ignored. 

952 

953 When converting from "PA", if an "RGBA" palette is present, the alpha 

954 channel from the image will be used instead of the values from the palette. 

955 

956 :param mode: The requested mode. See: :ref:`concept-modes`. 

957 :param matrix: An optional conversion matrix. If given, this 

958 should be 4- or 12-tuple containing floating point values. 

959 :param dither: Dithering method, used when converting from 

960 mode "RGB" to "P" or from "RGB" or "L" to "1". 

961 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG` 

962 (default). Note that this is not used when ``matrix`` is supplied. 

963 :param palette: Palette to use when converting from mode "RGB" 

964 to "P". Available palettes are :data:`Palette.WEB` or 

965 :data:`Palette.ADAPTIVE`. 

966 :param colors: Number of colors to use for the :data:`Palette.ADAPTIVE` 

967 palette. Defaults to 256. 

968 :rtype: :py:class:`~PIL.Image.Image` 

969 :returns: An :py:class:`~PIL.Image.Image` object. 

970 """ 

971 

972 self.load() 

973 

974 has_transparency = "transparency" in self.info 

975 if not mode and self.mode == "P": 

976 # determine default mode 

977 if self.palette: 

978 mode = self.palette.mode 

979 else: 

980 mode = "RGB" 

981 if mode == "RGB" and has_transparency: 

982 mode = "RGBA" 

983 if not mode or (mode == self.mode and not matrix): 

984 return self.copy() 

985 

986 if matrix: 

987 # matrix conversion 

988 if mode not in ("L", "RGB"): 

989 msg = "illegal conversion" 

990 raise ValueError(msg) 

991 im = self.im.convert_matrix(mode, matrix) 

992 new_im = self._new(im) 

993 if has_transparency and self.im.bands == 3: 

994 transparency = new_im.info["transparency"] 

995 

996 def convert_transparency( 

997 m: tuple[float, ...], v: tuple[int, int, int] 

998 ) -> int: 

999 value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5 

1000 return max(0, min(255, int(value))) 

1001 

1002 if mode == "L": 

1003 transparency = convert_transparency(matrix, transparency) 

1004 elif len(mode) == 3: 

1005 transparency = tuple( 

1006 convert_transparency(matrix[i * 4 : i * 4 + 4], transparency) 

1007 for i in range(len(transparency)) 

1008 ) 

1009 new_im.info["transparency"] = transparency 

1010 return new_im 

1011 

1012 if mode == "P" and self.mode == "RGBA": 

1013 return self.quantize(colors) 

1014 

1015 trns = None 

1016 delete_trns = False 

1017 # transparency handling 

1018 if has_transparency: 

1019 if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or ( 

1020 self.mode == "RGB" and mode in ("La", "LA", "RGBa", "RGBA") 

1021 ): 

1022 # Use transparent conversion to promote from transparent 

1023 # color to an alpha channel. 

1024 new_im = self._new( 

1025 self.im.convert_transparent(mode, self.info["transparency"]) 

1026 ) 

1027 del new_im.info["transparency"] 

1028 return new_im 

1029 elif self.mode in ("L", "RGB", "P") and mode in ("L", "RGB", "P"): 

1030 t = self.info["transparency"] 

1031 if isinstance(t, bytes): 

1032 # Dragons. This can't be represented by a single color 

1033 warnings.warn( 

1034 "Palette images with Transparency expressed in bytes should be " 

1035 "converted to RGBA images" 

1036 ) 

1037 delete_trns = True 

1038 else: 

1039 # get the new transparency color. 

1040 # use existing conversions 

1041 trns_im = new(self.mode, (1, 1)) 

1042 if self.mode == "P": 

1043 assert self.palette is not None 

1044 trns_im.putpalette(self.palette, self.palette.mode) 

1045 if isinstance(t, tuple): 

1046 err = "Couldn't allocate a palette color for transparency" 

1047 assert trns_im.palette is not None 

1048 try: 

1049 t = trns_im.palette.getcolor(t, self) 

1050 except ValueError as e: 

1051 if str(e) == "cannot allocate more than 256 colors": 

1052 # If all 256 colors are in use, 

1053 # then there is no need for transparency 

1054 t = None 

1055 else: 

1056 raise ValueError(err) from e 

1057 if t is None: 

1058 trns = None 

1059 else: 

1060 trns_im.putpixel((0, 0), t) 

1061 

1062 if mode in ("L", "RGB"): 

1063 trns_im = trns_im.convert(mode) 

1064 else: 

1065 # can't just retrieve the palette number, got to do it 

1066 # after quantization. 

1067 trns_im = trns_im.convert("RGB") 

1068 trns = trns_im.getpixel((0, 0)) 

1069 

1070 elif self.mode == "P" and mode in ("LA", "PA", "RGBA"): 

1071 t = self.info["transparency"] 

1072 delete_trns = True 

1073 

1074 if isinstance(t, bytes): 

1075 self.im.putpalettealphas(t) 

1076 elif isinstance(t, int): 

1077 self.im.putpalettealpha(t, 0) 

1078 else: 

1079 msg = "Transparency for P mode should be bytes or int" 

1080 raise ValueError(msg) 

1081 

1082 if mode == "P" and palette == Palette.ADAPTIVE: 

1083 im = self.im.quantize(colors) 

1084 new_im = self._new(im) 

1085 from . import ImagePalette 

1086 

1087 new_im.palette = ImagePalette.ImagePalette( 

1088 "RGB", new_im.im.getpalette("RGB") 

1089 ) 

1090 if delete_trns: 

1091 # This could possibly happen if we requantize to fewer colors. 

1092 # The transparency would be totally off in that case. 

1093 del new_im.info["transparency"] 

1094 if trns is not None: 

1095 try: 

1096 new_im.info["transparency"] = new_im.palette.getcolor( 

1097 cast(tuple[int, ...], trns), # trns was converted to RGB 

1098 new_im, 

1099 ) 

1100 except Exception: 

1101 # if we can't make a transparent color, don't leave the old 

1102 # transparency hanging around to mess us up. 

1103 del new_im.info["transparency"] 

1104 warnings.warn("Couldn't allocate palette entry for transparency") 

1105 return new_im 

1106 

1107 if "LAB" in (self.mode, mode): 

1108 im = self 

1109 if mode == "LAB": 

1110 if im.mode not in ("RGB", "RGBA", "RGBX"): 

1111 im = im.convert("RGBA") 

1112 other_mode = im.mode 

1113 else: 

1114 other_mode = mode 

1115 if other_mode in ("RGB", "RGBA", "RGBX"): 

1116 from . import ImageCms 

1117 

1118 srgb = ImageCms.createProfile("sRGB") 

1119 lab = ImageCms.createProfile("LAB") 

1120 profiles = [lab, srgb] if im.mode == "LAB" else [srgb, lab] 

1121 transform = ImageCms.buildTransform( 

1122 profiles[0], profiles[1], im.mode, mode 

1123 ) 

1124 return transform.apply(im) 

1125 

1126 # colorspace conversion 

1127 if dither is None: 

1128 dither = Dither.FLOYDSTEINBERG 

1129 

1130 try: 

1131 im = self.im.convert(mode, dither) 

1132 except ValueError: 

1133 try: 

1134 # normalize source image and try again 

1135 modebase = getmodebase(self.mode) 

1136 if modebase == self.mode: 

1137 raise 

1138 im = self.im.convert(modebase) 

1139 im = im.convert(mode, dither) 

1140 except KeyError as e: 

1141 msg = "illegal conversion" 

1142 raise ValueError(msg) from e 

1143 

1144 new_im = self._new(im) 

1145 if mode == "P" and palette != Palette.ADAPTIVE: 

1146 from . import ImagePalette 

1147 

1148 new_im.palette = ImagePalette.ImagePalette("RGB", im.getpalette("RGB")) 

1149 if delete_trns: 

1150 # crash fail if we leave a bytes transparency in an rgb/l mode. 

1151 del new_im.info["transparency"] 

1152 if trns is not None: 

1153 if new_im.mode == "P" and new_im.palette: 

1154 try: 

1155 new_im.info["transparency"] = new_im.palette.getcolor( 

1156 cast(tuple[int, ...], trns), new_im # trns was converted to RGB 

1157 ) 

1158 except ValueError as e: 

1159 del new_im.info["transparency"] 

1160 if str(e) != "cannot allocate more than 256 colors": 

1161 # If all 256 colors are in use, 

1162 # then there is no need for transparency 

1163 warnings.warn( 

1164 "Couldn't allocate palette entry for transparency" 

1165 ) 

1166 else: 

1167 new_im.info["transparency"] = trns 

1168 return new_im 

1169 

1170 def quantize( 

1171 self, 

1172 colors: int = 256, 

1173 method: int | None = None, 

1174 kmeans: int = 0, 

1175 palette: Image | None = None, 

1176 dither: Dither = Dither.FLOYDSTEINBERG, 

1177 ) -> Image: 

1178 """ 

1179 Convert the image to 'P' mode with the specified number 

1180 of colors. 

1181 

1182 :param colors: The desired number of colors, <= 256 

1183 :param method: :data:`Quantize.MEDIANCUT` (median cut), 

1184 :data:`Quantize.MAXCOVERAGE` (maximum coverage), 

1185 :data:`Quantize.FASTOCTREE` (fast octree), 

1186 :data:`Quantize.LIBIMAGEQUANT` (libimagequant; check support 

1187 using :py:func:`PIL.features.check_feature` with 

1188 ``feature="libimagequant"``). 

1189 

1190 By default, :data:`Quantize.MEDIANCUT` will be used. 

1191 

1192 The exception to this is RGBA images. :data:`Quantize.MEDIANCUT` 

1193 and :data:`Quantize.MAXCOVERAGE` do not support RGBA images, so 

1194 :data:`Quantize.FASTOCTREE` is used by default instead. 

1195 :param kmeans: Integer greater than or equal to zero. 

1196 :param palette: Quantize to the palette of given 

1197 :py:class:`PIL.Image.Image`. 

1198 :param dither: Dithering method, used when converting from 

1199 mode "RGB" to "P" or from "RGB" or "L" to "1". 

1200 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG` 

1201 (default). 

1202 :returns: A new image 

1203 """ 

1204 

1205 self.load() 

1206 

1207 if method is None: 

1208 # defaults: 

1209 method = Quantize.MEDIANCUT 

1210 if self.mode == "RGBA": 

1211 method = Quantize.FASTOCTREE 

1212 

1213 if self.mode == "RGBA" and method not in ( 

1214 Quantize.FASTOCTREE, 

1215 Quantize.LIBIMAGEQUANT, 

1216 ): 

1217 # Caller specified an invalid mode. 

1218 msg = ( 

1219 "Fast Octree (method == 2) and libimagequant (method == 3) " 

1220 "are the only valid methods for quantizing RGBA images" 

1221 ) 

1222 raise ValueError(msg) 

1223 

1224 if palette: 

1225 # use palette from reference image 

1226 palette.load() 

1227 if palette.mode != "P": 

1228 msg = "bad mode for palette image" 

1229 raise ValueError(msg) 

1230 if self.mode not in {"RGB", "L"}: 

1231 msg = "only RGB or L mode images can be quantized to a palette" 

1232 raise ValueError(msg) 

1233 im = self.im.convert("P", dither, palette.im) 

1234 new_im = self._new(im) 

1235 assert palette.palette is not None 

1236 new_im.palette = palette.palette.copy() 

1237 return new_im 

1238 

1239 if kmeans < 0: 

1240 msg = "kmeans must not be negative" 

1241 raise ValueError(msg) 

1242 

1243 im = self._new(self.im.quantize(colors, method, kmeans)) 

1244 

1245 from . import ImagePalette 

1246 

1247 mode = im.im.getpalettemode() 

1248 palette_data = im.im.getpalette(mode, mode)[: colors * len(mode)] 

1249 im.palette = ImagePalette.ImagePalette(mode, palette_data) 

1250 

1251 return im 

1252 

1253 def copy(self) -> Image: 

1254 """ 

1255 Copies this image. Use this method if you wish to paste things 

1256 into an image, but still retain the original. 

1257 

1258 :rtype: :py:class:`~PIL.Image.Image` 

1259 :returns: An :py:class:`~PIL.Image.Image` object. 

1260 """ 

1261 self.load() 

1262 return self._new(self.im.copy()) 

1263 

1264 __copy__ = copy 

1265 

1266 def crop(self, box: tuple[float, float, float, float] | None = None) -> Image: 

1267 """ 

1268 Returns a rectangular region from this image. The box is a 

1269 4-tuple defining the left, upper, right, and lower pixel 

1270 coordinate. See :ref:`coordinate-system`. 

1271 

1272 Note: Prior to Pillow 3.4.0, this was a lazy operation. 

1273 

1274 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple. 

1275 :rtype: :py:class:`~PIL.Image.Image` 

1276 :returns: An :py:class:`~PIL.Image.Image` object. 

1277 """ 

1278 

1279 if box is None: 

1280 return self.copy() 

1281 

1282 if box[2] < box[0]: 

1283 msg = "Coordinate 'right' is less than 'left'" 

1284 raise ValueError(msg) 

1285 elif box[3] < box[1]: 

1286 msg = "Coordinate 'lower' is less than 'upper'" 

1287 raise ValueError(msg) 

1288 

1289 self.load() 

1290 return self._new(self._crop(self.im, box)) 

1291 

1292 def _crop( 

1293 self, im: core.ImagingCore, box: tuple[float, float, float, float] 

1294 ) -> core.ImagingCore: 

1295 """ 

1296 Returns a rectangular region from the core image object im. 

1297 

1298 This is equivalent to calling im.crop((x0, y0, x1, y1)), but 

1299 includes additional sanity checks. 

1300 

1301 :param im: a core image object 

1302 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple. 

1303 :returns: A core image object. 

1304 """ 

1305 

1306 x0, y0, x1, y1 = map(int, map(round, box)) 

1307 

1308 absolute_values = (abs(x1 - x0), abs(y1 - y0)) 

1309 

1310 _decompression_bomb_check(absolute_values) 

1311 

1312 return im.crop((x0, y0, x1, y1)) 

1313 

1314 def draft( 

1315 self, mode: str | None, size: tuple[int, int] | None 

1316 ) -> tuple[str, tuple[int, int, float, float]] | None: 

1317 """ 

1318 Configures the image file loader so it returns a version of the 

1319 image that as closely as possible matches the given mode and 

1320 size. For example, you can use this method to convert a color 

1321 JPEG to grayscale while loading it. 

1322 

1323 If any changes are made, returns a tuple with the chosen ``mode`` and 

1324 ``box`` with coordinates of the original image within the altered one. 

1325 

1326 Note that this method modifies the :py:class:`~PIL.Image.Image` object 

1327 in place. If the image has already been loaded, this method has no 

1328 effect. 

1329 

1330 Note: This method is not implemented for most images. It is 

1331 currently implemented only for JPEG and MPO images. 

1332 

1333 :param mode: The requested mode. 

1334 :param size: The requested size in pixels, as a 2-tuple: 

1335 (width, height). 

1336 """ 

1337 pass 

1338 

1339 def _expand(self, xmargin: int, ymargin: int | None = None) -> Image: 

1340 if ymargin is None: 

1341 ymargin = xmargin 

1342 self.load() 

1343 return self._new(self.im.expand(xmargin, ymargin)) 

1344 

1345 def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image: 

1346 """ 

1347 Filters this image using the given filter. For a list of 

1348 available filters, see the :py:mod:`~PIL.ImageFilter` module. 

1349 

1350 :param filter: Filter kernel. 

1351 :returns: An :py:class:`~PIL.Image.Image` object.""" 

1352 

1353 from . import ImageFilter 

1354 

1355 self.load() 

1356 

1357 if callable(filter): 

1358 filter = filter() 

1359 if not hasattr(filter, "filter"): 

1360 msg = "filter argument should be ImageFilter.Filter instance or class" 

1361 raise TypeError(msg) 

1362 

1363 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

1364 if self.im.bands == 1 or multiband: 

1365 return self._new(filter.filter(self.im)) 

1366 

1367 ims = [ 

1368 self._new(filter.filter(self.im.getband(c))) for c in range(self.im.bands) 

1369 ] 

1370 return merge(self.mode, ims) 

1371 

1372 def getbands(self) -> tuple[str, ...]: 

1373 """ 

1374 Returns a tuple containing the name of each band in this image. 

1375 For example, ``getbands`` on an RGB image returns ("R", "G", "B"). 

1376 

1377 :returns: A tuple containing band names. 

1378 :rtype: tuple 

1379 """ 

1380 return ImageMode.getmode(self.mode).bands 

1381 

1382 def getbbox(self, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None: 

1383 """ 

1384 Calculates the bounding box of the non-zero regions in the 

1385 image. 

1386 

1387 :param alpha_only: Optional flag, defaulting to ``True``. 

1388 If ``True`` and the image has an alpha channel, trim transparent pixels. 

1389 Otherwise, trim pixels when all channels are zero. 

1390 Keyword-only argument. 

1391 :returns: The bounding box is returned as a 4-tuple defining the 

1392 left, upper, right, and lower pixel coordinate. See 

1393 :ref:`coordinate-system`. If the image is completely empty, this 

1394 method returns None. 

1395 

1396 """ 

1397 

1398 self.load() 

1399 return self.im.getbbox(alpha_only) 

1400 

1401 def getcolors( 

1402 self, maxcolors: int = 256 

1403 ) -> list[tuple[int, tuple[int, ...]]] | list[tuple[int, float]] | None: 

1404 """ 

1405 Returns a list of colors used in this image. 

1406 

1407 The colors will be in the image's mode. For example, an RGB image will 

1408 return a tuple of (red, green, blue) color values, and a P image will 

1409 return the index of the color in the palette. 

1410 

1411 :param maxcolors: Maximum number of colors. If this number is 

1412 exceeded, this method returns None. The default limit is 

1413 256 colors. 

1414 :returns: An unsorted list of (count, pixel) values. 

1415 """ 

1416 

1417 self.load() 

1418 if self.mode in ("1", "L", "P"): 

1419 h = self.im.histogram() 

1420 out: list[tuple[int, float]] = [(h[i], i) for i in range(256) if h[i]] 

1421 if len(out) > maxcolors: 

1422 return None 

1423 return out 

1424 return self.im.getcolors(maxcolors) 

1425 

1426 def getdata(self, band: int | None = None) -> core.ImagingCore: 

1427 """ 

1428 Returns the contents of this image as a sequence object 

1429 containing pixel values. The sequence object is flattened, so 

1430 that values for line one follow directly after the values of 

1431 line zero, and so on. 

1432 

1433 Note that the sequence object returned by this method is an 

1434 internal PIL data type, which only supports certain sequence 

1435 operations. To convert it to an ordinary sequence (e.g. for 

1436 printing), use ``list(im.getdata())``. 

1437 

1438 :param band: What band to return. The default is to return 

1439 all bands. To return a single band, pass in the index 

1440 value (e.g. 0 to get the "R" band from an "RGB" image). 

1441 :returns: A sequence-like object. 

1442 """ 

1443 

1444 self.load() 

1445 if band is not None: 

1446 return self.im.getband(band) 

1447 return self.im # could be abused 

1448 

1449 def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]: 

1450 """ 

1451 Gets the minimum and maximum pixel values for each band in 

1452 the image. 

1453 

1454 :returns: For a single-band image, a 2-tuple containing the 

1455 minimum and maximum pixel value. For a multi-band image, 

1456 a tuple containing one 2-tuple for each band. 

1457 """ 

1458 

1459 self.load() 

1460 if self.im.bands > 1: 

1461 return tuple(self.im.getband(i).getextrema() for i in range(self.im.bands)) 

1462 return self.im.getextrema() 

1463 

1464 def getxmp(self) -> dict[str, Any]: 

1465 """ 

1466 Returns a dictionary containing the XMP tags. 

1467 Requires defusedxml to be installed. 

1468 

1469 :returns: XMP tags in a dictionary. 

1470 """ 

1471 

1472 def get_name(tag: str) -> str: 

1473 return re.sub("^{[^}]+}", "", tag) 

1474 

1475 def get_value(element: Element) -> str | dict[str, Any] | None: 

1476 value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()} 

1477 children = list(element) 

1478 if children: 

1479 for child in children: 

1480 name = get_name(child.tag) 

1481 child_value = get_value(child) 

1482 if name in value: 

1483 if not isinstance(value[name], list): 

1484 value[name] = [value[name]] 

1485 value[name].append(child_value) 

1486 else: 

1487 value[name] = child_value 

1488 elif value: 

1489 if element.text: 

1490 value["text"] = element.text 

1491 else: 

1492 return element.text 

1493 return value 

1494 

1495 if ElementTree is None: 

1496 warnings.warn("XMP data cannot be read without defusedxml dependency") 

1497 return {} 

1498 if "xmp" not in self.info: 

1499 return {} 

1500 root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 ")) 

1501 return {get_name(root.tag): get_value(root)} 

1502 

1503 def getexif(self) -> Exif: 

1504 """ 

1505 Gets EXIF data from the image. 

1506 

1507 :returns: an :py:class:`~PIL.Image.Exif` object. 

1508 """ 

1509 if self._exif is None: 

1510 self._exif = Exif() 

1511 elif self._exif._loaded: 

1512 return self._exif 

1513 self._exif._loaded = True 

1514 

1515 exif_info = self.info.get("exif") 

1516 if exif_info is None: 

1517 if "Raw profile type exif" in self.info: 

1518 exif_info = bytes.fromhex( 

1519 "".join(self.info["Raw profile type exif"].split("\n")[3:]) 

1520 ) 

1521 elif hasattr(self, "tag_v2"): 

1522 self._exif.bigtiff = self.tag_v2._bigtiff 

1523 self._exif.endian = self.tag_v2._endian 

1524 self._exif.load_from_fp(self.fp, self.tag_v2._offset) 

1525 if exif_info is not None: 

1526 self._exif.load(exif_info) 

1527 

1528 # XMP tags 

1529 if ExifTags.Base.Orientation not in self._exif: 

1530 xmp_tags = self.info.get("XML:com.adobe.xmp") 

1531 pattern: str | bytes = r'tiff:Orientation(="|>)([0-9])' 

1532 if not xmp_tags and (xmp_tags := self.info.get("xmp")): 

1533 pattern = rb'tiff:Orientation(="|>)([0-9])' 

1534 if xmp_tags: 

1535 match = re.search(pattern, xmp_tags) 

1536 if match: 

1537 self._exif[ExifTags.Base.Orientation] = int(match[2]) 

1538 

1539 return self._exif 

1540 

1541 def _reload_exif(self) -> None: 

1542 if self._exif is None or not self._exif._loaded: 

1543 return 

1544 self._exif._loaded = False 

1545 self.getexif() 

1546 

1547 def get_child_images(self) -> list[ImageFile.ImageFile]: 

1548 from . import ImageFile 

1549 

1550 deprecate("Image.Image.get_child_images", 13) 

1551 return ImageFile.ImageFile.get_child_images(self) # type: ignore[arg-type] 

1552 

1553 def getim(self) -> CapsuleType: 

1554 """ 

1555 Returns a capsule that points to the internal image memory. 

1556 

1557 :returns: A capsule object. 

1558 """ 

1559 

1560 self.load() 

1561 return self.im.ptr 

1562 

1563 def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None: 

1564 """ 

1565 Returns the image palette as a list. 

1566 

1567 :param rawmode: The mode in which to return the palette. ``None`` will 

1568 return the palette in its current mode. 

1569 

1570 .. versionadded:: 9.1.0 

1571 

1572 :returns: A list of color values [r, g, b, ...], or None if the 

1573 image has no palette. 

1574 """ 

1575 

1576 self.load() 

1577 try: 

1578 mode = self.im.getpalettemode() 

1579 except ValueError: 

1580 return None # no palette 

1581 if rawmode is None: 

1582 rawmode = mode 

1583 return list(self.im.getpalette(mode, rawmode)) 

1584 

1585 @property 

1586 def has_transparency_data(self) -> bool: 

1587 """ 

1588 Determine if an image has transparency data, whether in the form of an 

1589 alpha channel, a palette with an alpha channel, or a "transparency" key 

1590 in the info dictionary. 

1591 

1592 Note the image might still appear solid, if all of the values shown 

1593 within are opaque. 

1594 

1595 :returns: A boolean. 

1596 """ 

1597 if ( 

1598 self.mode in ("LA", "La", "PA", "RGBA", "RGBa") 

1599 or "transparency" in self.info 

1600 ): 

1601 return True 

1602 if self.mode == "P": 

1603 assert self.palette is not None 

1604 return self.palette.mode.endswith("A") 

1605 return False 

1606 

1607 def apply_transparency(self) -> None: 

1608 """ 

1609 If a P mode image has a "transparency" key in the info dictionary, 

1610 remove the key and instead apply the transparency to the palette. 

1611 Otherwise, the image is unchanged. 

1612 """ 

1613 if self.mode != "P" or "transparency" not in self.info: 

1614 return 

1615 

1616 from . import ImagePalette 

1617 

1618 palette = self.getpalette("RGBA") 

1619 assert palette is not None 

1620 transparency = self.info["transparency"] 

1621 if isinstance(transparency, bytes): 

1622 for i, alpha in enumerate(transparency): 

1623 palette[i * 4 + 3] = alpha 

1624 else: 

1625 palette[transparency * 4 + 3] = 0 

1626 self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette)) 

1627 self.palette.dirty = 1 

1628 

1629 del self.info["transparency"] 

1630 

1631 def getpixel( 

1632 self, xy: tuple[int, int] | list[int] 

1633 ) -> float | tuple[int, ...] | None: 

1634 """ 

1635 Returns the pixel value at a given position. 

1636 

1637 :param xy: The coordinate, given as (x, y). See 

1638 :ref:`coordinate-system`. 

1639 :returns: The pixel value. If the image is a multi-layer image, 

1640 this method returns a tuple. 

1641 """ 

1642 

1643 self.load() 

1644 return self.im.getpixel(tuple(xy)) 

1645 

1646 def getprojection(self) -> tuple[list[int], list[int]]: 

1647 """ 

1648 Get projection to x and y axes 

1649 

1650 :returns: Two sequences, indicating where there are non-zero 

1651 pixels along the X-axis and the Y-axis, respectively. 

1652 """ 

1653 

1654 self.load() 

1655 x, y = self.im.getprojection() 

1656 return list(x), list(y) 

1657 

1658 def histogram( 

1659 self, mask: Image | None = None, extrema: tuple[float, float] | None = None 

1660 ) -> list[int]: 

1661 """ 

1662 Returns a histogram for the image. The histogram is returned as a 

1663 list of pixel counts, one for each pixel value in the source 

1664 image. Counts are grouped into 256 bins for each band, even if 

1665 the image has more than 8 bits per band. If the image has more 

1666 than one band, the histograms for all bands are concatenated (for 

1667 example, the histogram for an "RGB" image contains 768 values). 

1668 

1669 A bilevel image (mode "1") is treated as a grayscale ("L") image 

1670 by this method. 

1671 

1672 If a mask is provided, the method returns a histogram for those 

1673 parts of the image where the mask image is non-zero. The mask 

1674 image must have the same size as the image, and be either a 

1675 bi-level image (mode "1") or a grayscale image ("L"). 

1676 

1677 :param mask: An optional mask. 

1678 :param extrema: An optional tuple of manually-specified extrema. 

1679 :returns: A list containing pixel counts. 

1680 """ 

1681 self.load() 

1682 if mask: 

1683 mask.load() 

1684 return self.im.histogram((0, 0), mask.im) 

1685 if self.mode in ("I", "F"): 

1686 return self.im.histogram( 

1687 extrema if extrema is not None else self.getextrema() 

1688 ) 

1689 return self.im.histogram() 

1690 

1691 def entropy( 

1692 self, mask: Image | None = None, extrema: tuple[float, float] | None = None 

1693 ) -> float: 

1694 """ 

1695 Calculates and returns the entropy for the image. 

1696 

1697 A bilevel image (mode "1") is treated as a grayscale ("L") 

1698 image by this method. 

1699 

1700 If a mask is provided, the method employs the histogram for 

1701 those parts of the image where the mask image is non-zero. 

1702 The mask image must have the same size as the image, and be 

1703 either a bi-level image (mode "1") or a grayscale image ("L"). 

1704 

1705 :param mask: An optional mask. 

1706 :param extrema: An optional tuple of manually-specified extrema. 

1707 :returns: A float value representing the image entropy 

1708 """ 

1709 self.load() 

1710 if mask: 

1711 mask.load() 

1712 return self.im.entropy((0, 0), mask.im) 

1713 if self.mode in ("I", "F"): 

1714 return self.im.entropy( 

1715 extrema if extrema is not None else self.getextrema() 

1716 ) 

1717 return self.im.entropy() 

1718 

1719 def paste( 

1720 self, 

1721 im: Image | str | float | tuple[float, ...], 

1722 box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None, 

1723 mask: Image | None = None, 

1724 ) -> None: 

1725 """ 

1726 Pastes another image into this image. The box argument is either 

1727 a 2-tuple giving the upper left corner, a 4-tuple defining the 

1728 left, upper, right, and lower pixel coordinate, or None (same as 

1729 (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size 

1730 of the pasted image must match the size of the region. 

1731 

1732 If the modes don't match, the pasted image is converted to the mode of 

1733 this image (see the :py:meth:`~PIL.Image.Image.convert` method for 

1734 details). 

1735 

1736 Instead of an image, the source can be a integer or tuple 

1737 containing pixel values. The method then fills the region 

1738 with the given color. When creating RGB images, you can 

1739 also use color strings as supported by the ImageColor module. See 

1740 :ref:`colors` for more information. 

1741 

1742 If a mask is given, this method updates only the regions 

1743 indicated by the mask. You can use either "1", "L", "LA", "RGBA" 

1744 or "RGBa" images (if present, the alpha band is used as mask). 

1745 Where the mask is 255, the given image is copied as is. Where 

1746 the mask is 0, the current value is preserved. Intermediate 

1747 values will mix the two images together, including their alpha 

1748 channels if they have them. 

1749 

1750 See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to 

1751 combine images with respect to their alpha channels. 

1752 

1753 :param im: Source image or pixel value (integer, float or tuple). 

1754 :param box: An optional 4-tuple giving the region to paste into. 

1755 If a 2-tuple is used instead, it's treated as the upper left 

1756 corner. If omitted or None, the source is pasted into the 

1757 upper left corner. 

1758 

1759 If an image is given as the second argument and there is no 

1760 third, the box defaults to (0, 0), and the second argument 

1761 is interpreted as a mask image. 

1762 :param mask: An optional mask image. 

1763 """ 

1764 

1765 if isinstance(box, Image): 

1766 if mask is not None: 

1767 msg = "If using second argument as mask, third argument must be None" 

1768 raise ValueError(msg) 

1769 # abbreviated paste(im, mask) syntax 

1770 mask = box 

1771 box = None 

1772 

1773 if box is None: 

1774 box = (0, 0) 

1775 

1776 if len(box) == 2: 

1777 # upper left corner given; get size from image or mask 

1778 if isinstance(im, Image): 

1779 size = im.size 

1780 elif isinstance(mask, Image): 

1781 size = mask.size 

1782 else: 

1783 # FIXME: use self.size here? 

1784 msg = "cannot determine region size; use 4-item box" 

1785 raise ValueError(msg) 

1786 box += (box[0] + size[0], box[1] + size[1]) 

1787 

1788 source: core.ImagingCore | str | float | tuple[float, ...] 

1789 if isinstance(im, str): 

1790 from . import ImageColor 

1791 

1792 source = ImageColor.getcolor(im, self.mode) 

1793 elif isinstance(im, Image): 

1794 im.load() 

1795 if self.mode != im.mode: 

1796 if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"): 

1797 # should use an adapter for this! 

1798 im = im.convert(self.mode) 

1799 source = im.im 

1800 else: 

1801 source = im 

1802 

1803 self._ensure_mutable() 

1804 

1805 if mask: 

1806 mask.load() 

1807 self.im.paste(source, box, mask.im) 

1808 else: 

1809 self.im.paste(source, box) 

1810 

1811 def alpha_composite( 

1812 self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0) 

1813 ) -> None: 

1814 """'In-place' analog of Image.alpha_composite. Composites an image 

1815 onto this image. 

1816 

1817 :param im: image to composite over this one 

1818 :param dest: Optional 2 tuple (left, top) specifying the upper 

1819 left corner in this (destination) image. 

1820 :param source: Optional 2 (left, top) tuple for the upper left 

1821 corner in the overlay source image, or 4 tuple (left, top, right, 

1822 bottom) for the bounds of the source rectangle 

1823 

1824 Performance Note: Not currently implemented in-place in the core layer. 

1825 """ 

1826 

1827 if not isinstance(source, (list, tuple)): 

1828 msg = "Source must be a list or tuple" 

1829 raise ValueError(msg) 

1830 if not isinstance(dest, (list, tuple)): 

1831 msg = "Destination must be a list or tuple" 

1832 raise ValueError(msg) 

1833 

1834 if len(source) == 4: 

1835 overlay_crop_box = tuple(source) 

1836 elif len(source) == 2: 

1837 overlay_crop_box = tuple(source) + im.size 

1838 else: 

1839 msg = "Source must be a sequence of length 2 or 4" 

1840 raise ValueError(msg) 

1841 

1842 if not len(dest) == 2: 

1843 msg = "Destination must be a sequence of length 2" 

1844 raise ValueError(msg) 

1845 if min(source) < 0: 

1846 msg = "Source must be non-negative" 

1847 raise ValueError(msg) 

1848 

1849 # over image, crop if it's not the whole image. 

1850 if overlay_crop_box == (0, 0) + im.size: 

1851 overlay = im 

1852 else: 

1853 overlay = im.crop(overlay_crop_box) 

1854 

1855 # target for the paste 

1856 box = tuple(dest) + (dest[0] + overlay.width, dest[1] + overlay.height) 

1857 

1858 # destination image. don't copy if we're using the whole image. 

1859 if box == (0, 0) + self.size: 

1860 background = self 

1861 else: 

1862 background = self.crop(box) 

1863 

1864 result = alpha_composite(background, overlay) 

1865 self.paste(result, box) 

1866 

1867 def point( 

1868 self, 

1869 lut: ( 

1870 Sequence[float] 

1871 | NumpyArray 

1872 | Callable[[int], float] 

1873 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1874 | ImagePointHandler 

1875 ), 

1876 mode: str | None = None, 

1877 ) -> Image: 

1878 """ 

1879 Maps this image through a lookup table or function. 

1880 

1881 :param lut: A lookup table, containing 256 (or 65536 if 

1882 self.mode=="I" and mode == "L") values per band in the 

1883 image. A function can be used instead, it should take a 

1884 single argument. The function is called once for each 

1885 possible pixel value, and the resulting table is applied to 

1886 all bands of the image. 

1887 

1888 It may also be an :py:class:`~PIL.Image.ImagePointHandler` 

1889 object:: 

1890 

1891 class Example(Image.ImagePointHandler): 

1892 def point(self, im: Image) -> Image: 

1893 # Return result 

1894 :param mode: Output mode (default is same as input). This can only be used if 

1895 the source image has mode "L" or "P", and the output has mode "1" or the 

1896 source image mode is "I" and the output mode is "L". 

1897 :returns: An :py:class:`~PIL.Image.Image` object. 

1898 """ 

1899 

1900 self.load() 

1901 

1902 if isinstance(lut, ImagePointHandler): 

1903 return lut.point(self) 

1904 

1905 if callable(lut): 

1906 # if it isn't a list, it should be a function 

1907 if self.mode in ("I", "I;16", "F"): 

1908 # check if the function can be used with point_transform 

1909 # UNDONE wiredfool -- I think this prevents us from ever doing 

1910 # a gamma function point transform on > 8bit images. 

1911 scale, offset = _getscaleoffset(lut) # type: ignore[arg-type] 

1912 return self._new(self.im.point_transform(scale, offset)) 

1913 # for other modes, convert the function to a table 

1914 flatLut = [lut(i) for i in range(256)] * self.im.bands # type: ignore[arg-type] 

1915 else: 

1916 flatLut = lut 

1917 

1918 if self.mode == "F": 

1919 # FIXME: _imaging returns a confusing error message for this case 

1920 msg = "point operation not supported for this mode" 

1921 raise ValueError(msg) 

1922 

1923 if mode != "F": 

1924 flatLut = [round(i) for i in flatLut] 

1925 return self._new(self.im.point(flatLut, mode)) 

1926 

1927 def putalpha(self, alpha: Image | int) -> None: 

1928 """ 

1929 Adds or replaces the alpha layer in this image. If the image 

1930 does not have an alpha layer, it's converted to "LA" or "RGBA". 

1931 The new layer must be either "L" or "1". 

1932 

1933 :param alpha: The new alpha layer. This can either be an "L" or "1" 

1934 image having the same size as this image, or an integer. 

1935 """ 

1936 

1937 self._ensure_mutable() 

1938 

1939 if self.mode not in ("LA", "PA", "RGBA"): 

1940 # attempt to promote self to a matching alpha mode 

1941 try: 

1942 mode = getmodebase(self.mode) + "A" 

1943 try: 

1944 self.im.setmode(mode) 

1945 except (AttributeError, ValueError) as e: 

1946 # do things the hard way 

1947 im = self.im.convert(mode) 

1948 if im.mode not in ("LA", "PA", "RGBA"): 

1949 msg = "alpha channel could not be added" 

1950 raise ValueError(msg) from e # sanity check 

1951 self.im = im 

1952 self._mode = self.im.mode 

1953 except KeyError as e: 

1954 msg = "illegal image mode" 

1955 raise ValueError(msg) from e 

1956 

1957 if self.mode in ("LA", "PA"): 

1958 band = 1 

1959 else: 

1960 band = 3 

1961 

1962 if isinstance(alpha, Image): 

1963 # alpha layer 

1964 if alpha.mode not in ("1", "L"): 

1965 msg = "illegal image mode" 

1966 raise ValueError(msg) 

1967 alpha.load() 

1968 if alpha.mode == "1": 

1969 alpha = alpha.convert("L") 

1970 else: 

1971 # constant alpha 

1972 try: 

1973 self.im.fillband(band, alpha) 

1974 except (AttributeError, ValueError): 

1975 # do things the hard way 

1976 alpha = new("L", self.size, alpha) 

1977 else: 

1978 return 

1979 

1980 self.im.putband(alpha.im, band) 

1981 

1982 def putdata( 

1983 self, 

1984 data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray, 

1985 scale: float = 1.0, 

1986 offset: float = 0.0, 

1987 ) -> None: 

1988 """ 

1989 Copies pixel data from a flattened sequence object into the image. The 

1990 values should start at the upper left corner (0, 0), continue to the 

1991 end of the line, followed directly by the first value of the second 

1992 line, and so on. Data will be read until either the image or the 

1993 sequence ends. The scale and offset values are used to adjust the 

1994 sequence values: **pixel = value*scale + offset**. 

1995 

1996 :param data: A flattened sequence object. See :ref:`colors` for more 

1997 information about values. 

1998 :param scale: An optional scale value. The default is 1.0. 

1999 :param offset: An optional offset value. The default is 0.0. 

2000 """ 

2001 

2002 self._ensure_mutable() 

2003 

2004 self.im.putdata(data, scale, offset) 

2005 

2006 def putpalette( 

2007 self, 

2008 data: ImagePalette.ImagePalette | bytes | Sequence[int], 

2009 rawmode: str = "RGB", 

2010 ) -> None: 

2011 """ 

2012 Attaches a palette to this image. The image must be a "P", "PA", "L" 

2013 or "LA" image. 

2014 

2015 The palette sequence must contain at most 256 colors, made up of one 

2016 integer value for each channel in the raw mode. 

2017 For example, if the raw mode is "RGB", then it can contain at most 768 

2018 values, made up of red, green and blue values for the corresponding pixel 

2019 index in the 256 colors. 

2020 If the raw mode is "RGBA", then it can contain at most 1024 values, 

2021 containing red, green, blue and alpha values. 

2022 

2023 Alternatively, an 8-bit string may be used instead of an integer sequence. 

2024 

2025 :param data: A palette sequence (either a list or a string). 

2026 :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", or a mode 

2027 that can be transformed to "RGB" or "RGBA" (e.g. "R", "BGR;15", "RGBA;L"). 

2028 """ 

2029 from . import ImagePalette 

2030 

2031 if self.mode not in ("L", "LA", "P", "PA"): 

2032 msg = "illegal image mode" 

2033 raise ValueError(msg) 

2034 if isinstance(data, ImagePalette.ImagePalette): 

2035 if data.rawmode is not None: 

2036 palette = ImagePalette.raw(data.rawmode, data.palette) 

2037 else: 

2038 palette = ImagePalette.ImagePalette(palette=data.palette) 

2039 palette.dirty = 1 

2040 else: 

2041 if not isinstance(data, bytes): 

2042 data = bytes(data) 

2043 palette = ImagePalette.raw(rawmode, data) 

2044 self._mode = "PA" if "A" in self.mode else "P" 

2045 self.palette = palette 

2046 self.palette.mode = "RGBA" if "A" in rawmode else "RGB" 

2047 self.load() # install new palette 

2048 

2049 def putpixel( 

2050 self, xy: tuple[int, int], value: float | tuple[int, ...] | list[int] 

2051 ) -> None: 

2052 """ 

2053 Modifies the pixel at the given position. The color is given as 

2054 a single numerical value for single-band images, and a tuple for 

2055 multi-band images. In addition to this, RGB and RGBA tuples are 

2056 accepted for P and PA images. See :ref:`colors` for more information. 

2057 

2058 Note that this method is relatively slow. For more extensive changes, 

2059 use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw` 

2060 module instead. 

2061 

2062 See: 

2063 

2064 * :py:meth:`~PIL.Image.Image.paste` 

2065 * :py:meth:`~PIL.Image.Image.putdata` 

2066 * :py:mod:`~PIL.ImageDraw` 

2067 

2068 :param xy: The pixel coordinate, given as (x, y). See 

2069 :ref:`coordinate-system`. 

2070 :param value: The pixel value. 

2071 """ 

2072 

2073 if self.readonly: 

2074 self._copy() 

2075 self.load() 

2076 

2077 if ( 

2078 self.mode in ("P", "PA") 

2079 and isinstance(value, (list, tuple)) 

2080 and len(value) in [3, 4] 

2081 ): 

2082 # RGB or RGBA value for a P or PA image 

2083 if self.mode == "PA": 

2084 alpha = value[3] if len(value) == 4 else 255 

2085 value = value[:3] 

2086 assert self.palette is not None 

2087 palette_index = self.palette.getcolor(tuple(value), self) 

2088 value = (palette_index, alpha) if self.mode == "PA" else palette_index 

2089 return self.im.putpixel(xy, value) 

2090 

2091 def remap_palette( 

2092 self, dest_map: list[int], source_palette: bytes | bytearray | None = None 

2093 ) -> Image: 

2094 """ 

2095 Rewrites the image to reorder the palette. 

2096 

2097 :param dest_map: A list of indexes into the original palette. 

2098 e.g. ``[1,0]`` would swap a two item palette, and ``list(range(256))`` 

2099 is the identity transform. 

2100 :param source_palette: Bytes or None. 

2101 :returns: An :py:class:`~PIL.Image.Image` object. 

2102 

2103 """ 

2104 from . import ImagePalette 

2105 

2106 if self.mode not in ("L", "P"): 

2107 msg = "illegal image mode" 

2108 raise ValueError(msg) 

2109 

2110 bands = 3 

2111 palette_mode = "RGB" 

2112 if source_palette is None: 

2113 if self.mode == "P": 

2114 self.load() 

2115 palette_mode = self.im.getpalettemode() 

2116 if palette_mode == "RGBA": 

2117 bands = 4 

2118 source_palette = self.im.getpalette(palette_mode, palette_mode) 

2119 else: # L-mode 

2120 source_palette = bytearray(i // 3 for i in range(768)) 

2121 elif len(source_palette) > 768: 

2122 bands = 4 

2123 palette_mode = "RGBA" 

2124 

2125 palette_bytes = b"" 

2126 new_positions = [0] * 256 

2127 

2128 # pick only the used colors from the palette 

2129 for i, oldPosition in enumerate(dest_map): 

2130 palette_bytes += source_palette[ 

2131 oldPosition * bands : oldPosition * bands + bands 

2132 ] 

2133 new_positions[oldPosition] = i 

2134 

2135 # replace the palette color id of all pixel with the new id 

2136 

2137 # Palette images are [0..255], mapped through a 1 or 3 

2138 # byte/color map. We need to remap the whole image 

2139 # from palette 1 to palette 2. New_positions is 

2140 # an array of indexes into palette 1. Palette 2 is 

2141 # palette 1 with any holes removed. 

2142 

2143 # We're going to leverage the convert mechanism to use the 

2144 # C code to remap the image from palette 1 to palette 2, 

2145 # by forcing the source image into 'L' mode and adding a 

2146 # mapping 'L' mode palette, then converting back to 'L' 

2147 # sans palette thus converting the image bytes, then 

2148 # assigning the optimized RGB palette. 

2149 

2150 # perf reference, 9500x4000 gif, w/~135 colors 

2151 # 14 sec prepatch, 1 sec postpatch with optimization forced. 

2152 

2153 mapping_palette = bytearray(new_positions) 

2154 

2155 m_im = self.copy() 

2156 m_im._mode = "P" 

2157 

2158 m_im.palette = ImagePalette.ImagePalette( 

2159 palette_mode, palette=mapping_palette * bands 

2160 ) 

2161 # possibly set palette dirty, then 

2162 # m_im.putpalette(mapping_palette, 'L') # converts to 'P' 

2163 # or just force it. 

2164 # UNDONE -- this is part of the general issue with palettes 

2165 m_im.im.putpalette(palette_mode, palette_mode + ";L", m_im.palette.tobytes()) 

2166 

2167 m_im = m_im.convert("L") 

2168 

2169 m_im.putpalette(palette_bytes, palette_mode) 

2170 m_im.palette = ImagePalette.ImagePalette(palette_mode, palette=palette_bytes) 

2171 

2172 if "transparency" in self.info: 

2173 try: 

2174 m_im.info["transparency"] = dest_map.index(self.info["transparency"]) 

2175 except ValueError: 

2176 if "transparency" in m_im.info: 

2177 del m_im.info["transparency"] 

2178 

2179 return m_im 

2180 

2181 def _get_safe_box( 

2182 self, 

2183 size: tuple[int, int], 

2184 resample: Resampling, 

2185 box: tuple[float, float, float, float], 

2186 ) -> tuple[int, int, int, int]: 

2187 """Expands the box so it includes adjacent pixels 

2188 that may be used by resampling with the given resampling filter. 

2189 """ 

2190 filter_support = _filters_support[resample] - 0.5 

2191 scale_x = (box[2] - box[0]) / size[0] 

2192 scale_y = (box[3] - box[1]) / size[1] 

2193 support_x = filter_support * scale_x 

2194 support_y = filter_support * scale_y 

2195 

2196 return ( 

2197 max(0, int(box[0] - support_x)), 

2198 max(0, int(box[1] - support_y)), 

2199 min(self.size[0], math.ceil(box[2] + support_x)), 

2200 min(self.size[1], math.ceil(box[3] + support_y)), 

2201 ) 

2202 

2203 def resize( 

2204 self, 

2205 size: tuple[int, int] | list[int] | NumpyArray, 

2206 resample: int | None = None, 

2207 box: tuple[float, float, float, float] | None = None, 

2208 reducing_gap: float | None = None, 

2209 ) -> Image: 

2210 """ 

2211 Returns a resized copy of this image. 

2212 

2213 :param size: The requested size in pixels, as a tuple or array: 

2214 (width, height). 

2215 :param resample: An optional resampling filter. This can be 

2216 one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, 

2217 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, 

2218 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. 

2219 If the image has mode "1" or "P", it is always set to 

2220 :py:data:`Resampling.NEAREST`. Otherwise, the default filter is 

2221 :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`. 

2222 :param box: An optional 4-tuple of floats providing 

2223 the source image region to be scaled. 

2224 The values must be within (0, 0, width, height) rectangle. 

2225 If omitted or None, the entire source is used. 

2226 :param reducing_gap: Apply optimization by resizing the image 

2227 in two steps. First, reducing the image by integer times 

2228 using :py:meth:`~PIL.Image.Image.reduce`. 

2229 Second, resizing using regular resampling. The last step 

2230 changes size no less than by ``reducing_gap`` times. 

2231 ``reducing_gap`` may be None (no first step is performed) 

2232 or should be greater than 1.0. The bigger ``reducing_gap``, 

2233 the closer the result to the fair resampling. 

2234 The smaller ``reducing_gap``, the faster resizing. 

2235 With ``reducing_gap`` greater or equal to 3.0, the result is 

2236 indistinguishable from fair resampling in most cases. 

2237 The default value is None (no optimization). 

2238 :returns: An :py:class:`~PIL.Image.Image` object. 

2239 """ 

2240 

2241 if resample is None: 

2242 resample = Resampling.BICUBIC 

2243 elif resample not in ( 

2244 Resampling.NEAREST, 

2245 Resampling.BILINEAR, 

2246 Resampling.BICUBIC, 

2247 Resampling.LANCZOS, 

2248 Resampling.BOX, 

2249 Resampling.HAMMING, 

2250 ): 

2251 msg = f"Unknown resampling filter ({resample})." 

2252 

2253 filters = [ 

2254 f"{filter[1]} ({filter[0]})" 

2255 for filter in ( 

2256 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

2257 (Resampling.LANCZOS, "Image.Resampling.LANCZOS"), 

2258 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

2259 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

2260 (Resampling.BOX, "Image.Resampling.BOX"), 

2261 (Resampling.HAMMING, "Image.Resampling.HAMMING"), 

2262 ) 

2263 ] 

2264 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

2265 raise ValueError(msg) 

2266 

2267 if reducing_gap is not None and reducing_gap < 1.0: 

2268 msg = "reducing_gap must be 1.0 or greater" 

2269 raise ValueError(msg) 

2270 

2271 if box is None: 

2272 box = (0, 0) + self.size 

2273 

2274 size = tuple(size) 

2275 if self.size == size and box == (0, 0) + self.size: 

2276 return self.copy() 

2277 

2278 if self.mode in ("1", "P"): 

2279 resample = Resampling.NEAREST 

2280 

2281 if self.mode in ["LA", "RGBA"] and resample != Resampling.NEAREST: 

2282 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2283 im = im.resize(size, resample, box) 

2284 return im.convert(self.mode) 

2285 

2286 self.load() 

2287 

2288 if reducing_gap is not None and resample != Resampling.NEAREST: 

2289 factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1 

2290 factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1 

2291 if factor_x > 1 or factor_y > 1: 

2292 reduce_box = self._get_safe_box(size, cast(Resampling, resample), box) 

2293 factor = (factor_x, factor_y) 

2294 self = ( 

2295 self.reduce(factor, box=reduce_box) 

2296 if callable(self.reduce) 

2297 else Image.reduce(self, factor, box=reduce_box) 

2298 ) 

2299 box = ( 

2300 (box[0] - reduce_box[0]) / factor_x, 

2301 (box[1] - reduce_box[1]) / factor_y, 

2302 (box[2] - reduce_box[0]) / factor_x, 

2303 (box[3] - reduce_box[1]) / factor_y, 

2304 ) 

2305 

2306 return self._new(self.im.resize(size, resample, box)) 

2307 

2308 def reduce( 

2309 self, 

2310 factor: int | tuple[int, int], 

2311 box: tuple[int, int, int, int] | None = None, 

2312 ) -> Image: 

2313 """ 

2314 Returns a copy of the image reduced ``factor`` times. 

2315 If the size of the image is not dividable by ``factor``, 

2316 the resulting size will be rounded up. 

2317 

2318 :param factor: A greater than 0 integer or tuple of two integers 

2319 for width and height separately. 

2320 :param box: An optional 4-tuple of ints providing 

2321 the source image region to be reduced. 

2322 The values must be within ``(0, 0, width, height)`` rectangle. 

2323 If omitted or ``None``, the entire source is used. 

2324 """ 

2325 if not isinstance(factor, (list, tuple)): 

2326 factor = (factor, factor) 

2327 

2328 if box is None: 

2329 box = (0, 0) + self.size 

2330 

2331 if factor == (1, 1) and box == (0, 0) + self.size: 

2332 return self.copy() 

2333 

2334 if self.mode in ["LA", "RGBA"]: 

2335 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2336 im = im.reduce(factor, box) 

2337 return im.convert(self.mode) 

2338 

2339 self.load() 

2340 

2341 return self._new(self.im.reduce(factor, box)) 

2342 

2343 def rotate( 

2344 self, 

2345 angle: float, 

2346 resample: Resampling = Resampling.NEAREST, 

2347 expand: int | bool = False, 

2348 center: tuple[float, float] | None = None, 

2349 translate: tuple[int, int] | None = None, 

2350 fillcolor: float | tuple[float, ...] | str | None = None, 

2351 ) -> Image: 

2352 """ 

2353 Returns a rotated copy of this image. This method returns a 

2354 copy of this image, rotated the given number of degrees counter 

2355 clockwise around its centre. 

2356 

2357 :param angle: In degrees counter clockwise. 

2358 :param resample: An optional resampling filter. This can be 

2359 one of :py:data:`Resampling.NEAREST` (use nearest neighbour), 

2360 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 

2361 environment), or :py:data:`Resampling.BICUBIC` (cubic spline 

2362 interpolation in a 4x4 environment). If omitted, or if the image has 

2363 mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. 

2364 See :ref:`concept-filters`. 

2365 :param expand: Optional expansion flag. If true, expands the output 

2366 image to make it large enough to hold the entire rotated image. 

2367 If false or omitted, make the output image the same size as the 

2368 input image. Note that the expand flag assumes rotation around 

2369 the center and no translation. 

2370 :param center: Optional center of rotation (a 2-tuple). Origin is 

2371 the upper left corner. Default is the center of the image. 

2372 :param translate: An optional post-rotate translation (a 2-tuple). 

2373 :param fillcolor: An optional color for area outside the rotated image. 

2374 :returns: An :py:class:`~PIL.Image.Image` object. 

2375 """ 

2376 

2377 angle = angle % 360.0 

2378 

2379 # Fast paths regardless of filter, as long as we're not 

2380 # translating or changing the center. 

2381 if not (center or translate): 

2382 if angle == 0: 

2383 return self.copy() 

2384 if angle == 180: 

2385 return self.transpose(Transpose.ROTATE_180) 

2386 if angle in (90, 270) and (expand or self.width == self.height): 

2387 return self.transpose( 

2388 Transpose.ROTATE_90 if angle == 90 else Transpose.ROTATE_270 

2389 ) 

2390 

2391 # Calculate the affine matrix. Note that this is the reverse 

2392 # transformation (from destination image to source) because we 

2393 # want to interpolate the (discrete) destination pixel from 

2394 # the local area around the (floating) source pixel. 

2395 

2396 # The matrix we actually want (note that it operates from the right): 

2397 # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx) 

2398 # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy) 

2399 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2400 

2401 # The reverse matrix is thus: 

2402 # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx) 

2403 # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty) 

2404 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2405 

2406 # In any case, the final translation may be updated at the end to 

2407 # compensate for the expand flag. 

2408 

2409 w, h = self.size 

2410 

2411 if translate is None: 

2412 post_trans = (0, 0) 

2413 else: 

2414 post_trans = translate 

2415 if center is None: 

2416 center = (w / 2, h / 2) 

2417 

2418 angle = -math.radians(angle) 

2419 matrix = [ 

2420 round(math.cos(angle), 15), 

2421 round(math.sin(angle), 15), 

2422 0.0, 

2423 round(-math.sin(angle), 15), 

2424 round(math.cos(angle), 15), 

2425 0.0, 

2426 ] 

2427 

2428 def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]: 

2429 (a, b, c, d, e, f) = matrix 

2430 return a * x + b * y + c, d * x + e * y + f 

2431 

2432 matrix[2], matrix[5] = transform( 

2433 -center[0] - post_trans[0], -center[1] - post_trans[1], matrix 

2434 ) 

2435 matrix[2] += center[0] 

2436 matrix[5] += center[1] 

2437 

2438 if expand: 

2439 # calculate output size 

2440 xx = [] 

2441 yy = [] 

2442 for x, y in ((0, 0), (w, 0), (w, h), (0, h)): 

2443 transformed_x, transformed_y = transform(x, y, matrix) 

2444 xx.append(transformed_x) 

2445 yy.append(transformed_y) 

2446 nw = math.ceil(max(xx)) - math.floor(min(xx)) 

2447 nh = math.ceil(max(yy)) - math.floor(min(yy)) 

2448 

2449 # We multiply a translation matrix from the right. Because of its 

2450 # special form, this is the same as taking the image of the 

2451 # translation vector as new translation vector. 

2452 matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix) 

2453 w, h = nw, nh 

2454 

2455 return self.transform( 

2456 (w, h), Transform.AFFINE, matrix, resample, fillcolor=fillcolor 

2457 ) 

2458 

2459 def save( 

2460 self, fp: StrOrBytesPath | IO[bytes], format: str | None = None, **params: Any 

2461 ) -> None: 

2462 """ 

2463 Saves this image under the given filename. If no format is 

2464 specified, the format to use is determined from the filename 

2465 extension, if possible. 

2466 

2467 Keyword options can be used to provide additional instructions 

2468 to the writer. If a writer doesn't recognise an option, it is 

2469 silently ignored. The available options are described in the 

2470 :doc:`image format documentation 

2471 <../handbook/image-file-formats>` for each writer. 

2472 

2473 You can use a file object instead of a filename. In this case, 

2474 you must always specify the format. The file object must 

2475 implement the ``seek``, ``tell``, and ``write`` 

2476 methods, and be opened in binary mode. 

2477 

2478 :param fp: A filename (string), os.PathLike object or file object. 

2479 :param format: Optional format override. If omitted, the 

2480 format to use is determined from the filename extension. 

2481 If a file object was used instead of a filename, this 

2482 parameter should always be used. 

2483 :param params: Extra parameters to the image writer. These can also be 

2484 set on the image itself through ``encoderinfo``. This is useful when 

2485 saving multiple images:: 

2486 

2487 # Saving XMP data to a single image 

2488 from PIL import Image 

2489 red = Image.new("RGB", (1, 1), "#f00") 

2490 red.save("out.mpo", xmp=b"test") 

2491 

2492 # Saving XMP data to the second frame of an image 

2493 from PIL import Image 

2494 black = Image.new("RGB", (1, 1)) 

2495 red = Image.new("RGB", (1, 1), "#f00") 

2496 red.encoderinfo = {"xmp": b"test"} 

2497 black.save("out.mpo", save_all=True, append_images=[red]) 

2498 :returns: None 

2499 :exception ValueError: If the output format could not be determined 

2500 from the file name. Use the format option to solve this. 

2501 :exception OSError: If the file could not be written. The file 

2502 may have been created, and may contain partial data. 

2503 """ 

2504 

2505 filename: str | bytes = "" 

2506 open_fp = False 

2507 if is_path(fp): 

2508 filename = os.fspath(fp) 

2509 open_fp = True 

2510 elif fp == sys.stdout: 

2511 try: 

2512 fp = sys.stdout.buffer 

2513 except AttributeError: 

2514 pass 

2515 if not filename and hasattr(fp, "name") and is_path(fp.name): 

2516 # only set the name for metadata purposes 

2517 filename = os.fspath(fp.name) 

2518 

2519 preinit() 

2520 

2521 filename_ext = os.path.splitext(filename)[1].lower() 

2522 ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext 

2523 

2524 if not format: 

2525 if ext not in EXTENSION: 

2526 init() 

2527 try: 

2528 format = EXTENSION[ext] 

2529 except KeyError as e: 

2530 msg = f"unknown file extension: {ext}" 

2531 raise ValueError(msg) from e 

2532 

2533 from . import ImageFile 

2534 

2535 # may mutate self! 

2536 if isinstance(self, ImageFile.ImageFile) and os.path.abspath( 

2537 filename 

2538 ) == os.path.abspath(self.filename): 

2539 self._ensure_mutable() 

2540 else: 

2541 self.load() 

2542 

2543 save_all = params.pop("save_all", None) 

2544 self._default_encoderinfo = params 

2545 encoderinfo = getattr(self, "encoderinfo", {}) 

2546 self._attach_default_encoderinfo(self) 

2547 self.encoderconfig: tuple[Any, ...] = () 

2548 

2549 if format.upper() not in SAVE: 

2550 init() 

2551 if save_all or ( 

2552 save_all is None 

2553 and params.get("append_images") 

2554 and format.upper() in SAVE_ALL 

2555 ): 

2556 save_handler = SAVE_ALL[format.upper()] 

2557 else: 

2558 save_handler = SAVE[format.upper()] 

2559 

2560 created = False 

2561 if open_fp: 

2562 created = not os.path.exists(filename) 

2563 if params.get("append", False): 

2564 # Open also for reading ("+"), because TIFF save_all 

2565 # writer needs to go back and edit the written data. 

2566 fp = builtins.open(filename, "r+b") 

2567 else: 

2568 fp = builtins.open(filename, "w+b") 

2569 else: 

2570 fp = cast(IO[bytes], fp) 

2571 

2572 try: 

2573 save_handler(self, fp, filename) 

2574 except Exception: 

2575 if open_fp: 

2576 fp.close() 

2577 if created: 

2578 try: 

2579 os.remove(filename) 

2580 except PermissionError: 

2581 pass 

2582 raise 

2583 finally: 

2584 self.encoderinfo = encoderinfo 

2585 if open_fp: 

2586 fp.close() 

2587 

2588 def _attach_default_encoderinfo(self, im: Image) -> dict[str, Any]: 

2589 encoderinfo = getattr(self, "encoderinfo", {}) 

2590 self.encoderinfo = {**im._default_encoderinfo, **encoderinfo} 

2591 return encoderinfo 

2592 

2593 def seek(self, frame: int) -> None: 

2594 """ 

2595 Seeks to the given frame in this sequence file. If you seek 

2596 beyond the end of the sequence, the method raises an 

2597 ``EOFError`` exception. When a sequence file is opened, the 

2598 library automatically seeks to frame 0. 

2599 

2600 See :py:meth:`~PIL.Image.Image.tell`. 

2601 

2602 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the 

2603 number of available frames. 

2604 

2605 :param frame: Frame number, starting at 0. 

2606 :exception EOFError: If the call attempts to seek beyond the end 

2607 of the sequence. 

2608 """ 

2609 

2610 # overridden by file handlers 

2611 if frame != 0: 

2612 msg = "no more images in file" 

2613 raise EOFError(msg) 

2614 

2615 def show(self, title: str | None = None) -> None: 

2616 """ 

2617 Displays this image. This method is mainly intended for debugging purposes. 

2618 

2619 This method calls :py:func:`PIL.ImageShow.show` internally. You can use 

2620 :py:func:`PIL.ImageShow.register` to override its default behaviour. 

2621 

2622 The image is first saved to a temporary file. By default, it will be in 

2623 PNG format. 

2624 

2625 On Unix, the image is then opened using the **xdg-open**, **display**, 

2626 **gm**, **eog** or **xv** utility, depending on which one can be found. 

2627 

2628 On macOS, the image is opened with the native Preview application. 

2629 

2630 On Windows, the image is opened with the standard PNG display utility. 

2631 

2632 :param title: Optional title to use for the image window, where possible. 

2633 """ 

2634 

2635 _show(self, title=title) 

2636 

2637 def split(self) -> tuple[Image, ...]: 

2638 """ 

2639 Split this image into individual bands. This method returns a 

2640 tuple of individual image bands from an image. For example, 

2641 splitting an "RGB" image creates three new images each 

2642 containing a copy of one of the original bands (red, green, 

2643 blue). 

2644 

2645 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel` 

2646 method can be more convenient and faster. 

2647 

2648 :returns: A tuple containing bands. 

2649 """ 

2650 

2651 self.load() 

2652 if self.im.bands == 1: 

2653 return (self.copy(),) 

2654 return tuple(map(self._new, self.im.split())) 

2655 

2656 def getchannel(self, channel: int | str) -> Image: 

2657 """ 

2658 Returns an image containing a single channel of the source image. 

2659 

2660 :param channel: What channel to return. Could be index 

2661 (0 for "R" channel of "RGB") or channel name 

2662 ("A" for alpha channel of "RGBA"). 

2663 :returns: An image in "L" mode. 

2664 

2665 .. versionadded:: 4.3.0 

2666 """ 

2667 self.load() 

2668 

2669 if isinstance(channel, str): 

2670 try: 

2671 channel = self.getbands().index(channel) 

2672 except ValueError as e: 

2673 msg = f'The image has no channel "{channel}"' 

2674 raise ValueError(msg) from e 

2675 

2676 return self._new(self.im.getband(channel)) 

2677 

2678 def tell(self) -> int: 

2679 """ 

2680 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. 

2681 

2682 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the 

2683 number of available frames. 

2684 

2685 :returns: Frame number, starting with 0. 

2686 """ 

2687 return 0 

2688 

2689 def thumbnail( 

2690 self, 

2691 size: tuple[float, float], 

2692 resample: Resampling = Resampling.BICUBIC, 

2693 reducing_gap: float | None = 2.0, 

2694 ) -> None: 

2695 """ 

2696 Make this image into a thumbnail. This method modifies the 

2697 image to contain a thumbnail version of itself, no larger than 

2698 the given size. This method calculates an appropriate thumbnail 

2699 size to preserve the aspect of the image, calls the 

2700 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader 

2701 (where applicable), and finally resizes the image. 

2702 

2703 Note that this function modifies the :py:class:`~PIL.Image.Image` 

2704 object in place. If you need to use the full resolution image as well, 

2705 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original 

2706 image. 

2707 

2708 :param size: The requested size in pixels, as a 2-tuple: 

2709 (width, height). 

2710 :param resample: Optional resampling filter. This can be one 

2711 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, 

2712 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, 

2713 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. 

2714 If omitted, it defaults to :py:data:`Resampling.BICUBIC`. 

2715 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0). 

2716 See: :ref:`concept-filters`. 

2717 :param reducing_gap: Apply optimization by resizing the image 

2718 in two steps. First, reducing the image by integer times 

2719 using :py:meth:`~PIL.Image.Image.reduce` or 

2720 :py:meth:`~PIL.Image.Image.draft` for JPEG images. 

2721 Second, resizing using regular resampling. The last step 

2722 changes size no less than by ``reducing_gap`` times. 

2723 ``reducing_gap`` may be None (no first step is performed) 

2724 or should be greater than 1.0. The bigger ``reducing_gap``, 

2725 the closer the result to the fair resampling. 

2726 The smaller ``reducing_gap``, the faster resizing. 

2727 With ``reducing_gap`` greater or equal to 3.0, the result is 

2728 indistinguishable from fair resampling in most cases. 

2729 The default value is 2.0 (very close to fair resampling 

2730 while still being faster in many cases). 

2731 :returns: None 

2732 """ 

2733 

2734 provided_size = tuple(map(math.floor, size)) 

2735 

2736 def preserve_aspect_ratio() -> tuple[int, int] | None: 

2737 def round_aspect(number: float, key: Callable[[int], float]) -> int: 

2738 return max(min(math.floor(number), math.ceil(number), key=key), 1) 

2739 

2740 x, y = provided_size 

2741 if x >= self.width and y >= self.height: 

2742 return None 

2743 

2744 aspect = self.width / self.height 

2745 if x / y >= aspect: 

2746 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) 

2747 else: 

2748 y = round_aspect( 

2749 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n) 

2750 ) 

2751 return x, y 

2752 

2753 preserved_size = preserve_aspect_ratio() 

2754 if preserved_size is None: 

2755 return 

2756 final_size = preserved_size 

2757 

2758 box = None 

2759 if reducing_gap is not None: 

2760 res = self.draft( 

2761 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) 

2762 ) 

2763 if res is not None: 

2764 box = res[1] 

2765 

2766 if self.size != final_size: 

2767 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) 

2768 

2769 self.im = im.im 

2770 self._size = final_size 

2771 self._mode = self.im.mode 

2772 

2773 self.readonly = 0 

2774 

2775 # FIXME: the different transform methods need further explanation 

2776 # instead of bloating the method docs, add a separate chapter. 

2777 def transform( 

2778 self, 

2779 size: tuple[int, int], 

2780 method: Transform | ImageTransformHandler | SupportsGetData, 

2781 data: Sequence[Any] | None = None, 

2782 resample: int = Resampling.NEAREST, 

2783 fill: int = 1, 

2784 fillcolor: float | tuple[float, ...] | str | None = None, 

2785 ) -> Image: 

2786 """ 

2787 Transforms this image. This method creates a new image with the 

2788 given size, and the same mode as the original, and copies data 

2789 to the new image using the given transform. 

2790 

2791 :param size: The output size in pixels, as a 2-tuple: 

2792 (width, height). 

2793 :param method: The transformation method. This is one of 

2794 :py:data:`Transform.EXTENT` (cut out a rectangular subregion), 

2795 :py:data:`Transform.AFFINE` (affine transform), 

2796 :py:data:`Transform.PERSPECTIVE` (perspective transform), 

2797 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or 

2798 :py:data:`Transform.MESH` (map a number of source quadrilaterals 

2799 in one operation). 

2800 

2801 It may also be an :py:class:`~PIL.Image.ImageTransformHandler` 

2802 object:: 

2803 

2804 class Example(Image.ImageTransformHandler): 

2805 def transform(self, size, data, resample, fill=1): 

2806 # Return result 

2807 

2808 Implementations of :py:class:`~PIL.Image.ImageTransformHandler` 

2809 for some of the :py:class:`Transform` methods are provided 

2810 in :py:mod:`~PIL.ImageTransform`. 

2811 

2812 It may also be an object with a ``method.getdata`` method 

2813 that returns a tuple supplying new ``method`` and ``data`` values:: 

2814 

2815 class Example: 

2816 def getdata(self): 

2817 method = Image.Transform.EXTENT 

2818 data = (0, 0, 100, 100) 

2819 return method, data 

2820 :param data: Extra data to the transformation method. 

2821 :param resample: Optional resampling filter. It can be one of 

2822 :py:data:`Resampling.NEAREST` (use nearest neighbour), 

2823 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 

2824 environment), or :py:data:`Resampling.BICUBIC` (cubic spline 

2825 interpolation in a 4x4 environment). If omitted, or if the image 

2826 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. 

2827 See: :ref:`concept-filters`. 

2828 :param fill: If ``method`` is an 

2829 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of 

2830 the arguments passed to it. Otherwise, it is unused. 

2831 :param fillcolor: Optional fill color for the area outside the 

2832 transform in the output image. 

2833 :returns: An :py:class:`~PIL.Image.Image` object. 

2834 """ 

2835 

2836 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: 

2837 return ( 

2838 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2839 .transform(size, method, data, resample, fill, fillcolor) 

2840 .convert(self.mode) 

2841 ) 

2842 

2843 if isinstance(method, ImageTransformHandler): 

2844 return method.transform(size, self, resample=resample, fill=fill) 

2845 

2846 if hasattr(method, "getdata"): 

2847 # compatibility w. old-style transform objects 

2848 method, data = method.getdata() 

2849 

2850 if data is None: 

2851 msg = "missing method data" 

2852 raise ValueError(msg) 

2853 

2854 im = new(self.mode, size, fillcolor) 

2855 if self.mode == "P" and self.palette: 

2856 im.palette = self.palette.copy() 

2857 im.info = self.info.copy() 

2858 if method == Transform.MESH: 

2859 # list of quads 

2860 for box, quad in data: 

2861 im.__transformer( 

2862 box, self, Transform.QUAD, quad, resample, fillcolor is None 

2863 ) 

2864 else: 

2865 im.__transformer( 

2866 (0, 0) + size, self, method, data, resample, fillcolor is None 

2867 ) 

2868 

2869 return im 

2870 

2871 def __transformer( 

2872 self, 

2873 box: tuple[int, int, int, int], 

2874 image: Image, 

2875 method: Transform, 

2876 data: Sequence[float], 

2877 resample: int = Resampling.NEAREST, 

2878 fill: bool = True, 

2879 ) -> None: 

2880 w = box[2] - box[0] 

2881 h = box[3] - box[1] 

2882 

2883 if method == Transform.AFFINE: 

2884 data = data[:6] 

2885 

2886 elif method == Transform.EXTENT: 

2887 # convert extent to an affine transform 

2888 x0, y0, x1, y1 = data 

2889 xs = (x1 - x0) / w 

2890 ys = (y1 - y0) / h 

2891 method = Transform.AFFINE 

2892 data = (xs, 0, x0, 0, ys, y0) 

2893 

2894 elif method == Transform.PERSPECTIVE: 

2895 data = data[:8] 

2896 

2897 elif method == Transform.QUAD: 

2898 # quadrilateral warp. data specifies the four corners 

2899 # given as NW, SW, SE, and NE. 

2900 nw = data[:2] 

2901 sw = data[2:4] 

2902 se = data[4:6] 

2903 ne = data[6:8] 

2904 x0, y0 = nw 

2905 As = 1.0 / w 

2906 At = 1.0 / h 

2907 data = ( 

2908 x0, 

2909 (ne[0] - x0) * As, 

2910 (sw[0] - x0) * At, 

2911 (se[0] - sw[0] - ne[0] + x0) * As * At, 

2912 y0, 

2913 (ne[1] - y0) * As, 

2914 (sw[1] - y0) * At, 

2915 (se[1] - sw[1] - ne[1] + y0) * As * At, 

2916 ) 

2917 

2918 else: 

2919 msg = "unknown transformation method" 

2920 raise ValueError(msg) 

2921 

2922 if resample not in ( 

2923 Resampling.NEAREST, 

2924 Resampling.BILINEAR, 

2925 Resampling.BICUBIC, 

2926 ): 

2927 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

2928 unusable: dict[int, str] = { 

2929 Resampling.BOX: "Image.Resampling.BOX", 

2930 Resampling.HAMMING: "Image.Resampling.HAMMING", 

2931 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

2932 } 

2933 msg = unusable[resample] + f" ({resample}) cannot be used." 

2934 else: 

2935 msg = f"Unknown resampling filter ({resample})." 

2936 

2937 filters = [ 

2938 f"{filter[1]} ({filter[0]})" 

2939 for filter in ( 

2940 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

2941 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

2942 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

2943 ) 

2944 ] 

2945 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

2946 raise ValueError(msg) 

2947 

2948 image.load() 

2949 

2950 self.load() 

2951 

2952 if image.mode in ("1", "P"): 

2953 resample = Resampling.NEAREST 

2954 

2955 self.im.transform(box, image.im, method, data, resample, fill) 

2956 

2957 def transpose(self, method: Transpose) -> Image: 

2958 """ 

2959 Transpose image (flip or rotate in 90 degree steps) 

2960 

2961 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

2962 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

2963 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

2964 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

2965 :returns: Returns a flipped or rotated copy of this image. 

2966 """ 

2967 

2968 self.load() 

2969 return self._new(self.im.transpose(method)) 

2970 

2971 def effect_spread(self, distance: int) -> Image: 

2972 """ 

2973 Randomly spread pixels in an image. 

2974 

2975 :param distance: Distance to spread pixels. 

2976 """ 

2977 self.load() 

2978 return self._new(self.im.effect_spread(distance)) 

2979 

2980 def toqimage(self) -> ImageQt.ImageQt: 

2981 """Returns a QImage copy of this image""" 

2982 from . import ImageQt 

2983 

2984 if not ImageQt.qt_is_installed: 

2985 msg = "Qt bindings are not installed" 

2986 raise ImportError(msg) 

2987 return ImageQt.toqimage(self) 

2988 

2989 def toqpixmap(self) -> ImageQt.QPixmap: 

2990 """Returns a QPixmap copy of this image""" 

2991 from . import ImageQt 

2992 

2993 if not ImageQt.qt_is_installed: 

2994 msg = "Qt bindings are not installed" 

2995 raise ImportError(msg) 

2996 return ImageQt.toqpixmap(self) 

2997 

2998 

2999# -------------------------------------------------------------------- 

3000# Abstract handlers. 

3001 

3002 

3003class ImagePointHandler(abc.ABC): 

3004 """ 

3005 Used as a mixin by point transforms 

3006 (for use with :py:meth:`~PIL.Image.Image.point`) 

3007 """ 

3008 

3009 @abc.abstractmethod 

3010 def point(self, im: Image) -> Image: 

3011 pass 

3012 

3013 

3014class ImageTransformHandler(abc.ABC): 

3015 """ 

3016 Used as a mixin by geometry transforms 

3017 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3018 """ 

3019 

3020 @abc.abstractmethod 

3021 def transform( 

3022 self, 

3023 size: tuple[int, int], 

3024 image: Image, 

3025 **options: Any, 

3026 ) -> Image: 

3027 pass 

3028 

3029 

3030# -------------------------------------------------------------------- 

3031# Factories 

3032 

3033 

3034def _check_size(size: Any) -> None: 

3035 """ 

3036 Common check to enforce type and sanity check on size tuples 

3037 

3038 :param size: Should be a 2 tuple of (width, height) 

3039 :returns: None, or raises a ValueError 

3040 """ 

3041 

3042 if not isinstance(size, (list, tuple)): 

3043 msg = "Size must be a list or tuple" 

3044 raise ValueError(msg) 

3045 if len(size) != 2: 

3046 msg = "Size must be a sequence of length 2" 

3047 raise ValueError(msg) 

3048 if size[0] < 0 or size[1] < 0: 

3049 msg = "Width and height must be >= 0" 

3050 raise ValueError(msg) 

3051 

3052 

3053def new( 

3054 mode: str, 

3055 size: tuple[int, int] | list[int], 

3056 color: float | tuple[float, ...] | str | None = 0, 

3057) -> Image: 

3058 """ 

3059 Creates a new image with the given mode and size. 

3060 

3061 :param mode: The mode to use for the new image. See: 

3062 :ref:`concept-modes`. 

3063 :param size: A 2-tuple, containing (width, height) in pixels. 

3064 :param color: What color to use for the image. Default is black. If given, 

3065 this should be a single integer or floating point value for single-band 

3066 modes, and a tuple for multi-band modes (one value per band). When 

3067 creating RGB or HSV images, you can also use color strings as supported 

3068 by the ImageColor module. See :ref:`colors` for more information. If the 

3069 color is None, the image is not initialised. 

3070 :returns: An :py:class:`~PIL.Image.Image` object. 

3071 """ 

3072 

3073 _check_size(size) 

3074 

3075 if color is None: 

3076 # don't initialize 

3077 return Image()._new(core.new(mode, size)) 

3078 

3079 if isinstance(color, str): 

3080 # css3-style specifier 

3081 

3082 from . import ImageColor 

3083 

3084 color = ImageColor.getcolor(color, mode) 

3085 

3086 im = Image() 

3087 if ( 

3088 mode == "P" 

3089 and isinstance(color, (list, tuple)) 

3090 and all(isinstance(i, int) for i in color) 

3091 ): 

3092 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3093 if len(color_ints) == 3 or len(color_ints) == 4: 

3094 # RGB or RGBA value for a P image 

3095 from . import ImagePalette 

3096 

3097 im.palette = ImagePalette.ImagePalette() 

3098 color = im.palette.getcolor(color_ints) 

3099 return im._new(core.fill(mode, size, color)) 

3100 

3101 

3102def frombytes( 

3103 mode: str, 

3104 size: tuple[int, int], 

3105 data: bytes | bytearray | SupportsArrayInterface, 

3106 decoder_name: str = "raw", 

3107 *args: Any, 

3108) -> Image: 

3109 """ 

3110 Creates a copy of an image memory from pixel data in a buffer. 

3111 

3112 In its simplest form, this function takes three arguments 

3113 (mode, size, and unpacked pixel data). 

3114 

3115 You can also use any pixel decoder supported by PIL. For more 

3116 information on available decoders, see the section 

3117 :ref:`Writing Your Own File Codec <file-codecs>`. 

3118 

3119 Note that this function decodes pixel data only, not entire images. 

3120 If you have an entire image in a string, wrap it in a 

3121 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3122 it. 

3123 

3124 :param mode: The image mode. See: :ref:`concept-modes`. 

3125 :param size: The image size. 

3126 :param data: A byte buffer containing raw data for the given mode. 

3127 :param decoder_name: What decoder to use. 

3128 :param args: Additional parameters for the given decoder. 

3129 :returns: An :py:class:`~PIL.Image.Image` object. 

3130 """ 

3131 

3132 _check_size(size) 

3133 

3134 im = new(mode, size) 

3135 if im.width != 0 and im.height != 0: 

3136 decoder_args: Any = args 

3137 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3138 # may pass tuple instead of argument list 

3139 decoder_args = decoder_args[0] 

3140 

3141 if decoder_name == "raw" and decoder_args == (): 

3142 decoder_args = mode 

3143 

3144 im.frombytes(data, decoder_name, decoder_args) 

3145 return im 

3146 

3147 

3148def frombuffer( 

3149 mode: str, 

3150 size: tuple[int, int], 

3151 data: bytes | SupportsArrayInterface, 

3152 decoder_name: str = "raw", 

3153 *args: Any, 

3154) -> Image: 

3155 """ 

3156 Creates an image memory referencing pixel data in a byte buffer. 

3157 

3158 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3159 in the byte buffer, where possible. This means that changes to the 

3160 original buffer object are reflected in this image). Not all modes can 

3161 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3162 

3163 Note that this function decodes pixel data only, not entire images. 

3164 If you have an entire image file in a string, wrap it in a 

3165 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3166 

3167 The default parameters used for the "raw" decoder differs from that used for 

3168 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3169 future release. The current release issues a warning if you do this; to disable 

3170 the warning, you should provide the full set of parameters. See below for details. 

3171 

3172 :param mode: The image mode. See: :ref:`concept-modes`. 

3173 :param size: The image size. 

3174 :param data: A bytes or other buffer object containing raw 

3175 data for the given mode. 

3176 :param decoder_name: What decoder to use. 

3177 :param args: Additional parameters for the given decoder. For the 

3178 default encoder ("raw"), it's recommended that you provide the 

3179 full set of parameters:: 

3180 

3181 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3182 

3183 :returns: An :py:class:`~PIL.Image.Image` object. 

3184 

3185 .. versionadded:: 1.1.4 

3186 """ 

3187 

3188 _check_size(size) 

3189 

3190 # may pass tuple instead of argument list 

3191 if len(args) == 1 and isinstance(args[0], tuple): 

3192 args = args[0] 

3193 

3194 if decoder_name == "raw": 

3195 if args == (): 

3196 args = mode, 0, 1 

3197 if args[0] in _MAPMODES: 

3198 im = new(mode, (0, 0)) 

3199 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3200 if mode == "P": 

3201 from . import ImagePalette 

3202 

3203 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3204 im.readonly = 1 

3205 return im 

3206 

3207 return frombytes(mode, size, data, decoder_name, args) 

3208 

3209 

3210class SupportsArrayInterface(Protocol): 

3211 """ 

3212 An object that has an ``__array_interface__`` dictionary. 

3213 """ 

3214 

3215 @property 

3216 def __array_interface__(self) -> dict[str, Any]: 

3217 raise NotImplementedError() 

3218 

3219 

3220class SupportsArrowArrayInterface(Protocol): 

3221 """ 

3222 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3223 data interface. 

3224 """ 

3225 

3226 def __arrow_c_array__( 

3227 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3228 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3229 raise NotImplementedError() 

3230 

3231 

3232def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3233 """ 

3234 Creates an image memory from an object exporting the array interface 

3235 (using the buffer protocol):: 

3236 

3237 from PIL import Image 

3238 import numpy as np 

3239 a = np.zeros((5, 5)) 

3240 im = Image.fromarray(a) 

3241 

3242 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3243 and :py:func:`~PIL.Image.frombuffer` is used. 

3244 

3245 In the case of NumPy, be aware that Pillow modes do not always correspond 

3246 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3247 32-bit signed integer pixels, and 32-bit floating point pixels. 

3248 

3249 Pillow images can also be converted to arrays:: 

3250 

3251 from PIL import Image 

3252 import numpy as np 

3253 im = Image.open("hopper.jpg") 

3254 a = np.asarray(im) 

3255 

3256 When converting Pillow images to arrays however, only pixel values are 

3257 transferred. This means that P and PA mode images will lose their palette. 

3258 

3259 :param obj: Object with array interface 

3260 :param mode: Optional mode to use when reading ``obj``. Will be determined from 

3261 type if ``None``. Deprecated. 

3262 

3263 This will not be used to convert the data after reading, but will be used to 

3264 change how the data is read:: 

3265 

3266 from PIL import Image 

3267 import numpy as np 

3268 a = np.full((1, 1), 300) 

3269 im = Image.fromarray(a, mode="L") 

3270 im.getpixel((0, 0)) # 44 

3271 im = Image.fromarray(a, mode="RGB") 

3272 im.getpixel((0, 0)) # (44, 1, 0) 

3273 

3274 See: :ref:`concept-modes` for general information about modes. 

3275 :returns: An image object. 

3276 

3277 .. versionadded:: 1.1.6 

3278 """ 

3279 arr = obj.__array_interface__ 

3280 shape = arr["shape"] 

3281 ndim = len(shape) 

3282 strides = arr.get("strides", None) 

3283 if mode is None: 

3284 try: 

3285 typekey = (1, 1) + shape[2:], arr["typestr"] 

3286 except KeyError as e: 

3287 msg = "Cannot handle this data type" 

3288 raise TypeError(msg) from e 

3289 try: 

3290 mode, rawmode = _fromarray_typemap[typekey] 

3291 except KeyError as e: 

3292 typekey_shape, typestr = typekey 

3293 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3294 raise TypeError(msg) from e 

3295 else: 

3296 deprecate("'mode' parameter", 13) 

3297 rawmode = mode 

3298 if mode in ["1", "L", "I", "P", "F"]: 

3299 ndmax = 2 

3300 elif mode == "RGB": 

3301 ndmax = 3 

3302 else: 

3303 ndmax = 4 

3304 if ndim > ndmax: 

3305 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3306 raise ValueError(msg) 

3307 

3308 size = 1 if ndim == 1 else shape[1], shape[0] 

3309 if strides is not None: 

3310 if hasattr(obj, "tobytes"): 

3311 obj = obj.tobytes() 

3312 elif hasattr(obj, "tostring"): 

3313 obj = obj.tostring() 

3314 else: 

3315 msg = "'strides' requires either tobytes() or tostring()" 

3316 raise ValueError(msg) 

3317 

3318 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3319 

3320 

3321def fromarrow( 

3322 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3323) -> Image: 

3324 """Creates an image with zero-copy shared memory from an object exporting 

3325 the arrow_c_array interface protocol:: 

3326 

3327 from PIL import Image 

3328 import pyarrow as pa 

3329 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3330 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3331 

3332 If the data representation of the ``obj`` is not compatible with 

3333 Pillow internal storage, a ValueError is raised. 

3334 

3335 Pillow images can also be converted to Arrow objects:: 

3336 

3337 from PIL import Image 

3338 import pyarrow as pa 

3339 im = Image.open('hopper.jpg') 

3340 arr = pa.array(im) 

3341 

3342 As with array support, when converting Pillow images to arrays, 

3343 only pixel values are transferred. This means that P and PA mode 

3344 images will lose their palette. 

3345 

3346 :param obj: Object with an arrow_c_array interface 

3347 :param mode: Image mode. 

3348 :param size: Image size. This must match the storage of the arrow object. 

3349 :returns: An Image object 

3350 

3351 Note that according to the Arrow spec, both the producer and the 

3352 consumer should consider the exported array to be immutable, as 

3353 unsynchronized updates will potentially cause inconsistent data. 

3354 

3355 See: :ref:`arrow-support` for more detailed information 

3356 

3357 .. versionadded:: 11.2.1 

3358 

3359 """ 

3360 if not hasattr(obj, "__arrow_c_array__"): 

3361 msg = "arrow_c_array interface not found" 

3362 raise ValueError(msg) 

3363 

3364 (schema_capsule, array_capsule) = obj.__arrow_c_array__() 

3365 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3366 if _im: 

3367 return Image()._new(_im) 

3368 

3369 msg = "new_arrow returned None without an exception" 

3370 raise ValueError(msg) 

3371 

3372 

3373def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3374 """Creates an image instance from a QImage image""" 

3375 from . import ImageQt 

3376 

3377 if not ImageQt.qt_is_installed: 

3378 msg = "Qt bindings are not installed" 

3379 raise ImportError(msg) 

3380 return ImageQt.fromqimage(im) 

3381 

3382 

3383def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3384 """Creates an image instance from a QPixmap image""" 

3385 from . import ImageQt 

3386 

3387 if not ImageQt.qt_is_installed: 

3388 msg = "Qt bindings are not installed" 

3389 raise ImportError(msg) 

3390 return ImageQt.fromqpixmap(im) 

3391 

3392 

3393_fromarray_typemap = { 

3394 # (shape, typestr) => mode, rawmode 

3395 # first two members of shape are set to one 

3396 ((1, 1), "|b1"): ("1", "1;8"), 

3397 ((1, 1), "|u1"): ("L", "L"), 

3398 ((1, 1), "|i1"): ("I", "I;8"), 

3399 ((1, 1), "<u2"): ("I", "I;16"), 

3400 ((1, 1), ">u2"): ("I", "I;16B"), 

3401 ((1, 1), "<i2"): ("I", "I;16S"), 

3402 ((1, 1), ">i2"): ("I", "I;16BS"), 

3403 ((1, 1), "<u4"): ("I", "I;32"), 

3404 ((1, 1), ">u4"): ("I", "I;32B"), 

3405 ((1, 1), "<i4"): ("I", "I;32S"), 

3406 ((1, 1), ">i4"): ("I", "I;32BS"), 

3407 ((1, 1), "<f4"): ("F", "F;32F"), 

3408 ((1, 1), ">f4"): ("F", "F;32BF"), 

3409 ((1, 1), "<f8"): ("F", "F;64F"), 

3410 ((1, 1), ">f8"): ("F", "F;64BF"), 

3411 ((1, 1, 2), "|u1"): ("LA", "LA"), 

3412 ((1, 1, 3), "|u1"): ("RGB", "RGB"), 

3413 ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), 

3414 # shortcuts: 

3415 ((1, 1), f"{_ENDIAN}i4"): ("I", "I"), 

3416 ((1, 1), f"{_ENDIAN}f4"): ("F", "F"), 

3417} 

3418 

3419 

3420def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3421 if MAX_IMAGE_PIXELS is None: 

3422 return 

3423 

3424 pixels = max(1, size[0]) * max(1, size[1]) 

3425 

3426 if pixels > 2 * MAX_IMAGE_PIXELS: 

3427 msg = ( 

3428 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3429 "pixels, could be decompression bomb DOS attack." 

3430 ) 

3431 raise DecompressionBombError(msg) 

3432 

3433 if pixels > MAX_IMAGE_PIXELS: 

3434 warnings.warn( 

3435 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3436 "could be decompression bomb DOS attack.", 

3437 DecompressionBombWarning, 

3438 ) 

3439 

3440 

3441def open( 

3442 fp: StrOrBytesPath | IO[bytes], 

3443 mode: Literal["r"] = "r", 

3444 formats: list[str] | tuple[str, ...] | None = None, 

3445) -> ImageFile.ImageFile: 

3446 """ 

3447 Opens and identifies the given image file. 

3448 

3449 This is a lazy operation; this function identifies the file, but 

3450 the file remains open and the actual image data is not read from 

3451 the file until you try to process the data (or call the 

3452 :py:meth:`~PIL.Image.Image.load` method). See 

3453 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3454 

3455 :param fp: A filename (string), os.PathLike object or a file object. 

3456 The file object must implement ``file.read``, 

3457 ``file.seek``, and ``file.tell`` methods, 

3458 and be opened in binary mode. The file object will also seek to zero 

3459 before reading. 

3460 :param mode: The mode. If given, this argument must be "r". 

3461 :param formats: A list or tuple of formats to attempt to load the file in. 

3462 This can be used to restrict the set of formats checked. 

3463 Pass ``None`` to try all supported formats. You can print the set of 

3464 available formats by running ``python3 -m PIL`` or using 

3465 the :py:func:`PIL.features.pilinfo` function. 

3466 :returns: An :py:class:`~PIL.Image.Image` object. 

3467 :exception FileNotFoundError: If the file cannot be found. 

3468 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3469 identified. 

3470 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3471 instance is used for ``fp``. 

3472 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3473 """ 

3474 

3475 if mode != "r": 

3476 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3477 raise ValueError(msg) 

3478 elif isinstance(fp, io.StringIO): 

3479 msg = ( # type: ignore[unreachable] 

3480 "StringIO cannot be used to open an image. " 

3481 "Binary data must be used instead." 

3482 ) 

3483 raise ValueError(msg) 

3484 

3485 if formats is None: 

3486 formats = ID 

3487 elif not isinstance(formats, (list, tuple)): 

3488 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3489 raise TypeError(msg) 

3490 

3491 exclusive_fp = False 

3492 filename: str | bytes = "" 

3493 if is_path(fp): 

3494 filename = os.fspath(fp) 

3495 fp = builtins.open(filename, "rb") 

3496 exclusive_fp = True 

3497 else: 

3498 fp = cast(IO[bytes], fp) 

3499 

3500 try: 

3501 fp.seek(0) 

3502 except (AttributeError, io.UnsupportedOperation): 

3503 fp = io.BytesIO(fp.read()) 

3504 exclusive_fp = True 

3505 

3506 prefix = fp.read(16) 

3507 

3508 preinit() 

3509 

3510 warning_messages: list[str] = [] 

3511 

3512 def _open_core( 

3513 fp: IO[bytes], 

3514 filename: str | bytes, 

3515 prefix: bytes, 

3516 formats: list[str] | tuple[str, ...], 

3517 ) -> ImageFile.ImageFile | None: 

3518 for i in formats: 

3519 i = i.upper() 

3520 if i not in OPEN: 

3521 init() 

3522 try: 

3523 factory, accept = OPEN[i] 

3524 result = not accept or accept(prefix) 

3525 if isinstance(result, str): 

3526 warning_messages.append(result) 

3527 elif result: 

3528 fp.seek(0) 

3529 im = factory(fp, filename) 

3530 _decompression_bomb_check(im.size) 

3531 return im 

3532 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3533 if WARN_POSSIBLE_FORMATS: 

3534 warning_messages.append(i + " opening failed. " + str(e)) 

3535 except BaseException: 

3536 if exclusive_fp: 

3537 fp.close() 

3538 raise 

3539 return None 

3540 

3541 im = _open_core(fp, filename, prefix, formats) 

3542 

3543 if im is None and formats is ID: 

3544 checked_formats = ID.copy() 

3545 if init(): 

3546 im = _open_core( 

3547 fp, 

3548 filename, 

3549 prefix, 

3550 tuple(format for format in formats if format not in checked_formats), 

3551 ) 

3552 

3553 if im: 

3554 im._exclusive_fp = exclusive_fp 

3555 return im 

3556 

3557 if exclusive_fp: 

3558 fp.close() 

3559 for message in warning_messages: 

3560 warnings.warn(message) 

3561 msg = "cannot identify image file %r" % (filename if filename else fp) 

3562 raise UnidentifiedImageError(msg) 

3563 

3564 

3565# 

3566# Image processing. 

3567 

3568 

3569def alpha_composite(im1: Image, im2: Image) -> Image: 

3570 """ 

3571 Alpha composite im2 over im1. 

3572 

3573 :param im1: The first image. Must have mode RGBA or LA. 

3574 :param im2: The second image. Must have the same mode and size as the first image. 

3575 :returns: An :py:class:`~PIL.Image.Image` object. 

3576 """ 

3577 

3578 im1.load() 

3579 im2.load() 

3580 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3581 

3582 

3583def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3584 """ 

3585 Creates a new image by interpolating between two input images, using 

3586 a constant alpha:: 

3587 

3588 out = image1 * (1.0 - alpha) + image2 * alpha 

3589 

3590 :param im1: The first image. 

3591 :param im2: The second image. Must have the same mode and size as 

3592 the first image. 

3593 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3594 copy of the first image is returned. If alpha is 1.0, a copy of 

3595 the second image is returned. There are no restrictions on the 

3596 alpha value. If necessary, the result is clipped to fit into 

3597 the allowed output range. 

3598 :returns: An :py:class:`~PIL.Image.Image` object. 

3599 """ 

3600 

3601 im1.load() 

3602 im2.load() 

3603 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3604 

3605 

3606def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3607 """ 

3608 Create composite image by blending images using a transparency mask. 

3609 

3610 :param image1: The first image. 

3611 :param image2: The second image. Must have the same mode and 

3612 size as the first image. 

3613 :param mask: A mask image. This image can have mode 

3614 "1", "L", or "RGBA", and must have the same size as the 

3615 other two images. 

3616 """ 

3617 

3618 image = image2.copy() 

3619 image.paste(image1, None, mask) 

3620 return image 

3621 

3622 

3623def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3624 """ 

3625 Applies the function (which should take one argument) to each pixel 

3626 in the given image. If the image has more than one band, the same 

3627 function is applied to each band. Note that the function is 

3628 evaluated once for each possible pixel value, so you cannot use 

3629 random components or other generators. 

3630 

3631 :param image: The input image. 

3632 :param function: A function object, taking one integer argument. 

3633 :returns: An :py:class:`~PIL.Image.Image` object. 

3634 """ 

3635 

3636 return image.point(args[0]) 

3637 

3638 

3639def merge(mode: str, bands: Sequence[Image]) -> Image: 

3640 """ 

3641 Merge a set of single band images into a new multiband image. 

3642 

3643 :param mode: The mode to use for the output image. See: 

3644 :ref:`concept-modes`. 

3645 :param bands: A sequence containing one single-band image for 

3646 each band in the output image. All bands must have the 

3647 same size. 

3648 :returns: An :py:class:`~PIL.Image.Image` object. 

3649 """ 

3650 

3651 if getmodebands(mode) != len(bands) or "*" in mode: 

3652 msg = "wrong number of bands" 

3653 raise ValueError(msg) 

3654 for band in bands[1:]: 

3655 if band.mode != getmodetype(mode): 

3656 msg = "mode mismatch" 

3657 raise ValueError(msg) 

3658 if band.size != bands[0].size: 

3659 msg = "size mismatch" 

3660 raise ValueError(msg) 

3661 for band in bands: 

3662 band.load() 

3663 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3664 

3665 

3666# -------------------------------------------------------------------- 

3667# Plugin registry 

3668 

3669 

3670def register_open( 

3671 id: str, 

3672 factory: ( 

3673 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3674 | type[ImageFile.ImageFile] 

3675 ), 

3676 accept: Callable[[bytes], bool | str] | None = None, 

3677) -> None: 

3678 """ 

3679 Register an image file plugin. This function should not be used 

3680 in application code. 

3681 

3682 :param id: An image format identifier. 

3683 :param factory: An image file factory method. 

3684 :param accept: An optional function that can be used to quickly 

3685 reject images having another format. 

3686 """ 

3687 id = id.upper() 

3688 if id not in ID: 

3689 ID.append(id) 

3690 OPEN[id] = factory, accept 

3691 

3692 

3693def register_mime(id: str, mimetype: str) -> None: 

3694 """ 

3695 Registers an image MIME type by populating ``Image.MIME``. This function 

3696 should not be used in application code. 

3697 

3698 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3699 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3700 provide a different result for specific images. 

3701 

3702 :param id: An image format identifier. 

3703 :param mimetype: The image MIME type for this format. 

3704 """ 

3705 MIME[id.upper()] = mimetype 

3706 

3707 

3708def register_save( 

3709 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3710) -> None: 

3711 """ 

3712 Registers an image save function. This function should not be 

3713 used in application code. 

3714 

3715 :param id: An image format identifier. 

3716 :param driver: A function to save images in this format. 

3717 """ 

3718 SAVE[id.upper()] = driver 

3719 

3720 

3721def register_save_all( 

3722 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3723) -> None: 

3724 """ 

3725 Registers an image function to save all the frames 

3726 of a multiframe format. This function should not be 

3727 used in application code. 

3728 

3729 :param id: An image format identifier. 

3730 :param driver: A function to save images in this format. 

3731 """ 

3732 SAVE_ALL[id.upper()] = driver 

3733 

3734 

3735def register_extension(id: str, extension: str) -> None: 

3736 """ 

3737 Registers an image extension. This function should not be 

3738 used in application code. 

3739 

3740 :param id: An image format identifier. 

3741 :param extension: An extension used for this format. 

3742 """ 

3743 EXTENSION[extension.lower()] = id.upper() 

3744 

3745 

3746def register_extensions(id: str, extensions: list[str]) -> None: 

3747 """ 

3748 Registers image extensions. This function should not be 

3749 used in application code. 

3750 

3751 :param id: An image format identifier. 

3752 :param extensions: A list of extensions used for this format. 

3753 """ 

3754 for extension in extensions: 

3755 register_extension(id, extension) 

3756 

3757 

3758def registered_extensions() -> dict[str, str]: 

3759 """ 

3760 Returns a dictionary containing all file extensions belonging 

3761 to registered plugins 

3762 """ 

3763 init() 

3764 return EXTENSION 

3765 

3766 

3767def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3768 """ 

3769 Registers an image decoder. This function should not be 

3770 used in application code. 

3771 

3772 :param name: The name of the decoder 

3773 :param decoder: An ImageFile.PyDecoder object 

3774 

3775 .. versionadded:: 4.1.0 

3776 """ 

3777 DECODERS[name] = decoder 

3778 

3779 

3780def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3781 """ 

3782 Registers an image encoder. This function should not be 

3783 used in application code. 

3784 

3785 :param name: The name of the encoder 

3786 :param encoder: An ImageFile.PyEncoder object 

3787 

3788 .. versionadded:: 4.1.0 

3789 """ 

3790 ENCODERS[name] = encoder 

3791 

3792 

3793# -------------------------------------------------------------------- 

3794# Simple display support. 

3795 

3796 

3797def _show(image: Image, **options: Any) -> None: 

3798 from . import ImageShow 

3799 

3800 ImageShow.show(image, **options) 

3801 

3802 

3803# -------------------------------------------------------------------- 

3804# Effects 

3805 

3806 

3807def effect_mandelbrot( 

3808 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3809) -> Image: 

3810 """ 

3811 Generate a Mandelbrot set covering the given extent. 

3812 

3813 :param size: The requested size in pixels, as a 2-tuple: 

3814 (width, height). 

3815 :param extent: The extent to cover, as a 4-tuple: 

3816 (x0, y0, x1, y1). 

3817 :param quality: Quality. 

3818 """ 

3819 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3820 

3821 

3822def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3823 """ 

3824 Generate Gaussian noise centered around 128. 

3825 

3826 :param size: The requested size in pixels, as a 2-tuple: 

3827 (width, height). 

3828 :param sigma: Standard deviation of noise. 

3829 """ 

3830 return Image()._new(core.effect_noise(size, sigma)) 

3831 

3832 

3833def linear_gradient(mode: str) -> Image: 

3834 """ 

3835 Generate 256x256 linear gradient from black to white, top to bottom. 

3836 

3837 :param mode: Input mode. 

3838 """ 

3839 return Image()._new(core.linear_gradient(mode)) 

3840 

3841 

3842def radial_gradient(mode: str) -> Image: 

3843 """ 

3844 Generate 256x256 radial gradient from black to white, centre to edge. 

3845 

3846 :param mode: Input mode. 

3847 """ 

3848 return Image()._new(core.radial_gradient(mode)) 

3849 

3850 

3851# -------------------------------------------------------------------- 

3852# Resources 

3853 

3854 

3855def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

3856 env_dict = env if env is not None else os.environ 

3857 

3858 for var_name, setter in [ 

3859 ("PILLOW_ALIGNMENT", core.set_alignment), 

3860 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

3861 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

3862 ]: 

3863 if var_name not in env_dict: 

3864 continue 

3865 

3866 var = env_dict[var_name].lower() 

3867 

3868 units = 1 

3869 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

3870 if var.endswith(postfix): 

3871 units = mul 

3872 var = var[: -len(postfix)] 

3873 

3874 try: 

3875 var_int = int(var) * units 

3876 except ValueError: 

3877 warnings.warn(f"{var_name} is not int") 

3878 continue 

3879 

3880 try: 

3881 setter(var_int) 

3882 except ValueError as e: 

3883 warnings.warn(f"{var_name}: {e}") 

3884 

3885 

3886_apply_env_variables() 

3887atexit.register(core.clear_cache) 

3888 

3889 

3890if TYPE_CHECKING: 

3891 _ExifBase = MutableMapping[int, Any] 

3892else: 

3893 _ExifBase = MutableMapping 

3894 

3895 

3896class Exif(_ExifBase): 

3897 """ 

3898 This class provides read and write access to EXIF image data:: 

3899 

3900 from PIL import Image 

3901 im = Image.open("exif.png") 

3902 exif = im.getexif() # Returns an instance of this class 

3903 

3904 Information can be read and written, iterated over or deleted:: 

3905 

3906 print(exif[274]) # 1 

3907 exif[274] = 2 

3908 for k, v in exif.items(): 

3909 print("Tag", k, "Value", v) # Tag 274 Value 2 

3910 del exif[274] 

3911 

3912 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

3913 returns a dictionary:: 

3914 

3915 from PIL import ExifTags 

3916 im = Image.open("exif_gps.jpg") 

3917 exif = im.getexif() 

3918 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

3919 print(gps_ifd) 

3920 

3921 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

3922 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

3923 

3924 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

3925 

3926 print(exif[ExifTags.Base.Software]) # PIL 

3927 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

3928 """ 

3929 

3930 endian: str | None = None 

3931 bigtiff = False 

3932 _loaded = False 

3933 

3934 def __init__(self) -> None: 

3935 self._data: dict[int, Any] = {} 

3936 self._hidden_data: dict[int, Any] = {} 

3937 self._ifds: dict[int, dict[int, Any]] = {} 

3938 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

3939 self._loaded_exif: bytes | None = None 

3940 

3941 def _fixup(self, value: Any) -> Any: 

3942 try: 

3943 if len(value) == 1 and isinstance(value, tuple): 

3944 return value[0] 

3945 except Exception: 

3946 pass 

3947 return value 

3948 

3949 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

3950 # Helper function 

3951 # returns a dict with any single item tuples/lists as individual values 

3952 return {k: self._fixup(v) for k, v in src_dict.items()} 

3953 

3954 def _get_ifd_dict( 

3955 self, offset: int, group: int | None = None 

3956 ) -> dict[int, Any] | None: 

3957 try: 

3958 # an offset pointer to the location of the nested embedded IFD. 

3959 # It should be a long, but may be corrupted. 

3960 self.fp.seek(offset) 

3961 except (KeyError, TypeError): 

3962 return None 

3963 else: 

3964 from . import TiffImagePlugin 

3965 

3966 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

3967 info.load(self.fp) 

3968 return self._fixup_dict(dict(info)) 

3969 

3970 def _get_head(self) -> bytes: 

3971 version = b"\x2b" if self.bigtiff else b"\x2a" 

3972 if self.endian == "<": 

3973 head = b"II" + version + b"\x00" + o32le(8) 

3974 else: 

3975 head = b"MM\x00" + version + o32be(8) 

3976 if self.bigtiff: 

3977 head += o32le(8) if self.endian == "<" else o32be(8) 

3978 head += b"\x00\x00\x00\x00" 

3979 return head 

3980 

3981 def load(self, data: bytes) -> None: 

3982 # Extract EXIF information. This is highly experimental, 

3983 # and is likely to be replaced with something better in a future 

3984 # version. 

3985 

3986 # The EXIF record consists of a TIFF file embedded in a JPEG 

3987 # application marker (!). 

3988 if data == self._loaded_exif: 

3989 return 

3990 self._loaded_exif = data 

3991 self._data.clear() 

3992 self._hidden_data.clear() 

3993 self._ifds.clear() 

3994 while data and data.startswith(b"Exif\x00\x00"): 

3995 data = data[6:] 

3996 if not data: 

3997 self._info = None 

3998 return 

3999 

4000 self.fp: IO[bytes] = io.BytesIO(data) 

4001 self.head = self.fp.read(8) 

4002 # process dictionary 

4003 from . import TiffImagePlugin 

4004 

4005 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4006 self.endian = self._info._endian 

4007 self.fp.seek(self._info.next) 

4008 self._info.load(self.fp) 

4009 

4010 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4011 self._loaded_exif = None 

4012 self._data.clear() 

4013 self._hidden_data.clear() 

4014 self._ifds.clear() 

4015 

4016 # process dictionary 

4017 from . import TiffImagePlugin 

4018 

4019 self.fp = fp 

4020 if offset is not None: 

4021 self.head = self._get_head() 

4022 else: 

4023 self.head = self.fp.read(8) 

4024 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4025 if self.endian is None: 

4026 self.endian = self._info._endian 

4027 if offset is None: 

4028 offset = self._info.next 

4029 self.fp.tell() 

4030 self.fp.seek(offset) 

4031 self._info.load(self.fp) 

4032 

4033 def _get_merged_dict(self) -> dict[int, Any]: 

4034 merged_dict = dict(self) 

4035 

4036 # get EXIF extension 

4037 if ExifTags.IFD.Exif in self: 

4038 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4039 if ifd: 

4040 merged_dict.update(ifd) 

4041 

4042 # GPS 

4043 if ExifTags.IFD.GPSInfo in self: 

4044 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4045 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4046 ) 

4047 

4048 return merged_dict 

4049 

4050 def tobytes(self, offset: int = 8) -> bytes: 

4051 from . import TiffImagePlugin 

4052 

4053 head = self._get_head() 

4054 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4055 for tag, ifd_dict in self._ifds.items(): 

4056 if tag not in self: 

4057 ifd[tag] = ifd_dict 

4058 for tag, value in self.items(): 

4059 if tag in [ 

4060 ExifTags.IFD.Exif, 

4061 ExifTags.IFD.GPSInfo, 

4062 ] and not isinstance(value, dict): 

4063 value = self.get_ifd(tag) 

4064 if ( 

4065 tag == ExifTags.IFD.Exif 

4066 and ExifTags.IFD.Interop in value 

4067 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4068 ): 

4069 value = value.copy() 

4070 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4071 ifd[tag] = value 

4072 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4073 

4074 def get_ifd(self, tag: int) -> dict[int, Any]: 

4075 if tag not in self._ifds: 

4076 if tag == ExifTags.IFD.IFD1: 

4077 if self._info is not None and self._info.next != 0: 

4078 ifd = self._get_ifd_dict(self._info.next) 

4079 if ifd is not None: 

4080 self._ifds[tag] = ifd 

4081 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4082 offset = self._hidden_data.get(tag, self.get(tag)) 

4083 if offset is not None: 

4084 ifd = self._get_ifd_dict(offset, tag) 

4085 if ifd is not None: 

4086 self._ifds[tag] = ifd 

4087 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4088 if ExifTags.IFD.Exif not in self._ifds: 

4089 self.get_ifd(ExifTags.IFD.Exif) 

4090 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4091 if tag == ExifTags.IFD.MakerNote: 

4092 from .TiffImagePlugin import ImageFileDirectory_v2 

4093 

4094 if tag_data.startswith(b"FUJIFILM"): 

4095 ifd_offset = i32le(tag_data, 8) 

4096 ifd_data = tag_data[ifd_offset:] 

4097 

4098 makernote = {} 

4099 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4100 ifd_tag, typ, count, data = struct.unpack( 

4101 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4102 ) 

4103 try: 

4104 ( 

4105 unit_size, 

4106 handler, 

4107 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4108 except KeyError: 

4109 continue 

4110 size = count * unit_size 

4111 if size > 4: 

4112 (offset,) = struct.unpack("<L", data) 

4113 data = ifd_data[offset - 12 : offset + size - 12] 

4114 else: 

4115 data = data[:size] 

4116 

4117 if len(data) != size: 

4118 warnings.warn( 

4119 "Possibly corrupt EXIF MakerNote data. " 

4120 f"Expecting to read {size} bytes but only got " 

4121 f"{len(data)}. Skipping tag {ifd_tag}" 

4122 ) 

4123 continue 

4124 

4125 if not data: 

4126 continue 

4127 

4128 makernote[ifd_tag] = handler( 

4129 ImageFileDirectory_v2(), data, False 

4130 ) 

4131 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4132 elif self.get(0x010F) == "Nintendo": 

4133 makernote = {} 

4134 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4135 ifd_tag, typ, count, data = struct.unpack( 

4136 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4137 ) 

4138 if ifd_tag == 0x1101: 

4139 # CameraInfo 

4140 (offset,) = struct.unpack(">L", data) 

4141 self.fp.seek(offset) 

4142 

4143 camerainfo: dict[str, int | bytes] = { 

4144 "ModelID": self.fp.read(4) 

4145 } 

4146 

4147 self.fp.read(4) 

4148 # Seconds since 2000 

4149 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4150 

4151 self.fp.read(4) 

4152 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4153 

4154 self.fp.read(12) 

4155 parallax = self.fp.read(4) 

4156 handler = ImageFileDirectory_v2._load_dispatch[ 

4157 TiffTags.FLOAT 

4158 ][1] 

4159 camerainfo["Parallax"] = handler( 

4160 ImageFileDirectory_v2(), parallax, False 

4161 )[0] 

4162 

4163 self.fp.read(4) 

4164 camerainfo["Category"] = self.fp.read(2) 

4165 

4166 makernote = {0x1101: camerainfo} 

4167 self._ifds[tag] = makernote 

4168 else: 

4169 # Interop 

4170 ifd = self._get_ifd_dict(tag_data, tag) 

4171 if ifd is not None: 

4172 self._ifds[tag] = ifd 

4173 ifd = self._ifds.setdefault(tag, {}) 

4174 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4175 ifd = { 

4176 k: v 

4177 for (k, v) in ifd.items() 

4178 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4179 } 

4180 return ifd 

4181 

4182 def hide_offsets(self) -> None: 

4183 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4184 if tag in self: 

4185 self._hidden_data[tag] = self[tag] 

4186 del self[tag] 

4187 

4188 def __str__(self) -> str: 

4189 if self._info is not None: 

4190 # Load all keys into self._data 

4191 for tag in self._info: 

4192 self[tag] 

4193 

4194 return str(self._data) 

4195 

4196 def __len__(self) -> int: 

4197 keys = set(self._data) 

4198 if self._info is not None: 

4199 keys.update(self._info) 

4200 return len(keys) 

4201 

4202 def __getitem__(self, tag: int) -> Any: 

4203 if self._info is not None and tag not in self._data and tag in self._info: 

4204 self._data[tag] = self._fixup(self._info[tag]) 

4205 del self._info[tag] 

4206 return self._data[tag] 

4207 

4208 def __contains__(self, tag: object) -> bool: 

4209 return tag in self._data or (self._info is not None and tag in self._info) 

4210 

4211 def __setitem__(self, tag: int, value: Any) -> None: 

4212 if self._info is not None and tag in self._info: 

4213 del self._info[tag] 

4214 self._data[tag] = value 

4215 

4216 def __delitem__(self, tag: int) -> None: 

4217 if self._info is not None and tag in self._info: 

4218 del self._info[tag] 

4219 else: 

4220 del self._data[tag] 

4221 if tag in self._ifds: 

4222 del self._ifds[tag] 

4223 

4224 def __iter__(self) -> Iterator[int]: 

4225 keys = set(self._data) 

4226 if self._info is not None: 

4227 keys.update(self._info) 

4228 return iter(keys)