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

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

1728 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) -> Image: 

594 return self 

595 

596 def __exit__(self, *args: object) -> None: 

597 pass 

598 

599 def close(self) -> None: 

600 """ 

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

602 The image data will be unusable afterward. 

603 

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

605 have not had their file read and closed by the 

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

607 more information. 

608 """ 

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

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

611 self.map.close() 

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

613 

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

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

616 # object is gone. 

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

618 

619 def _copy(self) -> None: 

620 self.load() 

621 self.im = self.im.copy() 

622 self.readonly = 0 

623 

624 def _ensure_mutable(self) -> None: 

625 if self.readonly: 

626 self._copy() 

627 else: 

628 self.load() 

629 

630 def _dump( 

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

632 ) -> str: 

633 suffix = "" 

634 if format: 

635 suffix = f".{format}" 

636 

637 if not file: 

638 f, filename = tempfile.mkstemp(suffix) 

639 os.close(f) 

640 else: 

641 filename = file 

642 if not filename.endswith(suffix): 

643 filename = filename + suffix 

644 

645 self.load() 

646 

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

648 self.im.save_ppm(filename) 

649 else: 

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

651 

652 return filename 

653 

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

655 if self.__class__ is not other.__class__: 

656 return False 

657 assert isinstance(other, Image) 

658 return ( 

659 self.mode == other.mode 

660 and self.size == other.size 

661 and self.info == other.info 

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

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

664 ) 

665 

666 def __repr__(self) -> str: 

667 return ( 

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

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

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

671 ) 

672 

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

674 """IPython plain text display support""" 

675 

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

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

678 p.text( 

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

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

681 ) 

682 

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

684 """Helper function for iPython display hook. 

685 

686 :param image_format: Image format. 

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

688 """ 

689 b = io.BytesIO() 

690 try: 

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

692 except Exception: 

693 return None 

694 return b.getvalue() 

695 

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

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

698 

699 :returns: PNG version of the image as bytes 

700 """ 

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

702 

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

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

705 

706 :returns: JPEG version of the image as bytes 

707 """ 

708 return self._repr_image("JPEG") 

709 

710 @property 

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

712 # numpy array interface support 

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

714 if self.mode == "1": 

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

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

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

718 else: 

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

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

721 return new 

722 

723 def __arrow_c_schema__(self) -> object: 

724 self.load() 

725 return self.im.__arrow_c_schema__() 

726 

727 def __arrow_c_array__( 

728 self, requested_schema: object | None = None 

729 ) -> tuple[object, object]: 

730 self.load() 

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

732 

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

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

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

736 

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

738 Image.__init__(self) 

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

740 self.info = info 

741 self._mode = mode 

742 self._size = size 

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

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

745 self.putpalette(palette) 

746 self.frombytes(data) 

747 

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

749 """ 

750 Return image as a bytes object. 

751 

752 .. warning:: 

753 

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

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

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

757 

758 :param encoder_name: What encoder to use. 

759 

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

761 To see how this packs pixel data into the returned 

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

763 

764 A list of C encoders can be seen under codecs 

765 section of the function array in 

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

767 within the relevant plugins. 

768 :param args: Extra arguments to the encoder. 

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

770 """ 

771 

772 encoder_args: Any = args 

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

774 # may pass tuple instead of argument list 

775 encoder_args = encoder_args[0] 

776 

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

778 encoder_args = self.mode 

779 

780 self.load() 

781 

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

783 return b"" 

784 

785 # unpack data 

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

787 e.setimage(self.im) 

788 

789 from . import ImageFile 

790 

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

792 

793 output = [] 

794 while True: 

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

796 output.append(data) 

797 if errcode: 

798 break 

799 if errcode < 0: 

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

801 raise RuntimeError(msg) 

802 

803 return b"".join(output) 

804 

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

806 """ 

807 Returns the image converted to an X11 bitmap. 

808 

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

810 

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

812 :returns: A string containing an X11 bitmap. 

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

814 """ 

815 

816 self.load() 

817 if self.mode != "1": 

818 msg = "not a bitmap" 

819 raise ValueError(msg) 

820 data = self.tobytes("xbm") 

821 return b"".join( 

822 [ 

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

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

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

826 data, 

827 b"};", 

828 ] 

829 ) 

830 

831 def frombytes( 

832 self, 

833 data: bytes | bytearray | SupportsArrayInterface, 

834 decoder_name: str = "raw", 

835 *args: Any, 

836 ) -> None: 

837 """ 

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

839 

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

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

842 """ 

843 

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

845 return 

846 

847 decoder_args: Any = args 

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

849 # may pass tuple instead of argument list 

850 decoder_args = decoder_args[0] 

851 

852 # default format 

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

854 decoder_args = self.mode 

855 

856 # unpack data 

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

858 d.setimage(self.im) 

859 s = d.decode(data) 

860 

861 if s[0] >= 0: 

862 msg = "not enough image data" 

863 raise ValueError(msg) 

864 if s[1] != 0: 

865 msg = "cannot decode image data" 

866 raise ValueError(msg) 

867 

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

869 """ 

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

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

872 Image class automatically loads an opened image when it is 

873 accessed for the first time. 

874 

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

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

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

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

879 

880 :returns: An image access object. 

881 :rtype: :py:class:`.PixelAccess` 

882 """ 

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

884 # realize palette 

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

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

887 self.palette.dirty = 0 

888 self.palette.rawmode = None 

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

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

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

892 else: 

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

894 self.palette.mode = "RGBA" 

895 else: 

896 self.palette.palette = self.im.getpalette( 

897 self.palette.mode, self.palette.mode 

898 ) 

899 

900 if self._im is not None: 

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

902 return None 

903 

904 def verify(self) -> None: 

905 """ 

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

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

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

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

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

911 file. 

912 """ 

913 pass 

914 

915 def convert( 

916 self, 

917 mode: str | None = None, 

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

919 dither: Dither | None = None, 

920 palette: Palette = Palette.WEB, 

921 colors: int = 256, 

922 ) -> Image: 

923 """ 

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

925 method translates pixels through the palette. If mode is 

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

927 and the palette can be represented without a palette. 

928 

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

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

931 

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

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

934 

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

936 

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

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

939 dither to approximate the original image luminosity levels. If 

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

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

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

943 

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

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

946 and ``dither`` and ``palette`` are ignored. 

947 

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

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

950 

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

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

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

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

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

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

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

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

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

960 :data:`Palette.ADAPTIVE`. 

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

962 palette. Defaults to 256. 

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

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

965 """ 

966 

967 self.load() 

968 

969 has_transparency = "transparency" in self.info 

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

971 # determine default mode 

972 if self.palette: 

973 mode = self.palette.mode 

974 else: 

975 mode = "RGB" 

976 if mode == "RGB" and has_transparency: 

977 mode = "RGBA" 

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

979 return self.copy() 

980 

981 if matrix: 

982 # matrix conversion 

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

984 msg = "illegal conversion" 

985 raise ValueError(msg) 

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

987 new_im = self._new(im) 

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

989 transparency = new_im.info["transparency"] 

990 

991 def convert_transparency( 

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

993 ) -> int: 

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

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

996 

997 if mode == "L": 

998 transparency = convert_transparency(matrix, transparency) 

999 elif len(mode) == 3: 

1000 transparency = tuple( 

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

1002 for i in range(len(transparency)) 

1003 ) 

1004 new_im.info["transparency"] = transparency 

1005 return new_im 

1006 

1007 if self.mode == "RGBA": 

1008 if mode == "P": 

1009 return self.quantize(colors) 

1010 elif mode == "PA": 

1011 r, g, b, a = self.split() 

1012 rgb = merge("RGB", (r, g, b)) 

1013 p = rgb.quantize(colors) 

1014 return merge("PA", (p, a)) 

1015 

1016 trns = None 

1017 delete_trns = False 

1018 # transparency handling 

1019 if has_transparency: 

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

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

1022 ): 

1023 # Use transparent conversion to promote from transparent 

1024 # color to an alpha channel. 

1025 new_im = self._new( 

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

1027 ) 

1028 del new_im.info["transparency"] 

1029 return new_im 

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

1031 t = self.info["transparency"] 

1032 if isinstance(t, bytes): 

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

1034 warnings.warn( 

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

1036 "converted to RGBA images" 

1037 ) 

1038 delete_trns = True 

1039 else: 

1040 # get the new transparency color. 

1041 # use existing conversions 

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

1043 if self.mode == "P": 

1044 assert self.palette is not None 

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

1046 if isinstance(t, tuple): 

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

1048 assert trns_im.palette is not None 

1049 try: 

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

1051 except ValueError as e: 

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

1053 # If all 256 colors are in use, 

1054 # then there is no need for transparency 

1055 t = None 

1056 else: 

1057 raise ValueError(err) from e 

1058 if t is None: 

1059 trns = None 

1060 else: 

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

1062 

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

1064 trns_im = trns_im.convert(mode) 

1065 else: 

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

1067 # after quantization. 

1068 trns_im = trns_im.convert("RGB") 

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

1070 

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

1072 t = self.info["transparency"] 

1073 delete_trns = True 

1074 

1075 if isinstance(t, bytes): 

1076 self.im.putpalettealphas(t) 

1077 elif isinstance(t, int): 

1078 self.im.putpalettealpha(t, 0) 

1079 else: 

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

1081 raise ValueError(msg) 

1082 

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

1084 im = self.im.quantize(colors) 

1085 new_im = self._new(im) 

1086 from . import ImagePalette 

1087 

1088 new_im.palette = ImagePalette.ImagePalette( 

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

1090 ) 

1091 if delete_trns: 

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

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

1094 del new_im.info["transparency"] 

1095 if trns is not None: 

1096 try: 

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

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

1099 new_im, 

1100 ) 

1101 except Exception: 

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

1103 # transparency hanging around to mess us up. 

1104 del new_im.info["transparency"] 

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

1106 return new_im 

1107 

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

1109 im = self 

1110 if mode == "LAB": 

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

1112 im = im.convert("RGBA") 

1113 other_mode = im.mode 

1114 else: 

1115 other_mode = mode 

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

1117 from . import ImageCms 

1118 

1119 srgb = ImageCms.createProfile("sRGB") 

1120 lab = ImageCms.createProfile("LAB") 

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

1122 transform = ImageCms.buildTransform( 

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

1124 ) 

1125 return transform.apply(im) 

1126 

1127 # colorspace conversion 

1128 if dither is None: 

1129 dither = Dither.FLOYDSTEINBERG 

1130 

1131 try: 

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

1133 except ValueError: 

1134 try: 

1135 # normalize source image and try again 

1136 modebase = getmodebase(self.mode) 

1137 if modebase == self.mode: 

1138 raise 

1139 im = self.im.convert(modebase) 

1140 im = im.convert(mode, dither) 

1141 except KeyError as e: 

1142 msg = "illegal conversion" 

1143 raise ValueError(msg) from e 

1144 

1145 new_im = self._new(im) 

1146 if mode in ("P", "PA") and palette != Palette.ADAPTIVE: 

1147 from . import ImagePalette 

1148 

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

1150 if delete_trns: 

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

1152 del new_im.info["transparency"] 

1153 if trns is not None: 

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

1155 try: 

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

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

1158 ) 

1159 except ValueError as e: 

1160 del new_im.info["transparency"] 

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

1162 # If all 256 colors are in use, 

1163 # then there is no need for transparency 

1164 warnings.warn( 

1165 "Couldn't allocate palette entry for transparency" 

1166 ) 

1167 else: 

1168 new_im.info["transparency"] = trns 

1169 return new_im 

1170 

1171 def quantize( 

1172 self, 

1173 colors: int = 256, 

1174 method: int | None = None, 

1175 kmeans: int = 0, 

1176 palette: Image | None = None, 

1177 dither: Dither = Dither.FLOYDSTEINBERG, 

1178 ) -> Image: 

1179 """ 

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

1181 of colors. 

1182 

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

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

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

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

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

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

1189 ``feature="libimagequant"``). 

1190 

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

1192 

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

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

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

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

1197 :param palette: Quantize to the palette of given 

1198 :py:class:`PIL.Image.Image`. 

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

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

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

1202 (default). 

1203 :returns: A new image 

1204 """ 

1205 

1206 self.load() 

1207 

1208 if method is None: 

1209 # defaults: 

1210 method = Quantize.MEDIANCUT 

1211 if self.mode == "RGBA": 

1212 method = Quantize.FASTOCTREE 

1213 

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

1215 Quantize.FASTOCTREE, 

1216 Quantize.LIBIMAGEQUANT, 

1217 ): 

1218 # Caller specified an invalid mode. 

1219 msg = ( 

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

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

1222 ) 

1223 raise ValueError(msg) 

1224 

1225 if palette: 

1226 # use palette from reference image 

1227 palette.load() 

1228 if palette.mode != "P": 

1229 msg = "bad mode for palette image" 

1230 raise ValueError(msg) 

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

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

1233 raise ValueError(msg) 

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

1235 new_im = self._new(im) 

1236 assert palette.palette is not None 

1237 new_im.palette = palette.palette.copy() 

1238 return new_im 

1239 

1240 if kmeans < 0: 

1241 msg = "kmeans must not be negative" 

1242 raise ValueError(msg) 

1243 

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

1245 

1246 from . import ImagePalette 

1247 

1248 mode = im.im.getpalettemode() 

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

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

1251 

1252 return im 

1253 

1254 def copy(self) -> Image: 

1255 """ 

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

1257 into an image, but still retain the original. 

1258 

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

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

1261 """ 

1262 self.load() 

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

1264 

1265 __copy__ = copy 

1266 

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

1268 """ 

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

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

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

1272 

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

1274 

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

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

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

1278 """ 

1279 

1280 if box is None: 

1281 return self.copy() 

1282 

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

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

1285 raise ValueError(msg) 

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

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

1288 raise ValueError(msg) 

1289 

1290 self.load() 

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

1292 

1293 def _crop( 

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

1295 ) -> core.ImagingCore: 

1296 """ 

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

1298 

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

1300 includes additional sanity checks. 

1301 

1302 :param im: a core image object 

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

1304 :returns: A core image object. 

1305 """ 

1306 

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

1308 

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

1310 

1311 _decompression_bomb_check(absolute_values) 

1312 

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

1314 

1315 def draft( 

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

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

1318 """ 

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

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

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

1322 JPEG to grayscale while loading it. 

1323 

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

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

1326 

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

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

1329 effect. 

1330 

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

1332 currently implemented only for JPEG and MPO images. 

1333 

1334 :param mode: The requested mode. 

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

1336 (width, height). 

1337 """ 

1338 pass 

1339 

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

1341 """ 

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

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

1344 

1345 :param filter: Filter kernel. 

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

1347 

1348 from . import ImageFilter 

1349 

1350 self.load() 

1351 

1352 if callable(filter): 

1353 filter = filter() 

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

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

1356 raise TypeError(msg) 

1357 

1358 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1361 

1362 ims = [ 

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

1364 ] 

1365 return merge(self.mode, ims) 

1366 

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

1368 """ 

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

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

1371 

1372 :returns: A tuple containing band names. 

1373 :rtype: tuple 

1374 """ 

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

1376 

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

1378 """ 

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

1380 image. 

1381 

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

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

1384 Otherwise, trim pixels when all channels are zero. 

1385 Keyword-only argument. 

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

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

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

1389 method returns None. 

1390 

1391 """ 

1392 

1393 self.load() 

1394 return self.im.getbbox(alpha_only) 

1395 

1396 def getcolors( 

1397 self, maxcolors: int = 256 

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

1399 """ 

1400 Returns a list of colors used in this image. 

1401 

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

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

1404 return the index of the color in the palette. 

1405 

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

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

1408 256 colors. 

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

1410 """ 

1411 

1412 self.load() 

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

1414 h = self.im.histogram() 

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

1416 if len(out) > maxcolors: 

1417 return None 

1418 return out 

1419 return self.im.getcolors(maxcolors) 

1420 

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

1422 """ 

1423 Returns the contents of this image as a sequence object 

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

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

1426 line zero, and so on. 

1427 

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

1429 internal PIL data type, which only supports certain sequence 

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

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

1432 

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

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

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

1436 :returns: A sequence-like object. 

1437 """ 

1438 deprecate("Image.Image.getdata", 14, "get_flattened_data") 

1439 

1440 self.load() 

1441 if band is not None: 

1442 return self.im.getband(band) 

1443 return self.im # could be abused 

1444 

1445 def get_flattened_data( 

1446 self, band: int | None = None 

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

1448 """ 

1449 Returns the contents of this image as a tuple containing pixel values. 

1450 The sequence object is flattened, so that values for line one follow 

1451 directly after the values of line zero, and so on. 

1452 

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

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

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

1456 :returns: A tuple containing pixel values. 

1457 """ 

1458 self.load() 

1459 if band is not None: 

1460 return tuple(self.im.getband(band)) 

1461 return tuple(self.im) 

1462 

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

1464 """ 

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

1466 the image. 

1467 

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

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

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

1471 """ 

1472 

1473 self.load() 

1474 if self.im.bands > 1: 

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

1476 return self.im.getextrema() 

1477 

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

1479 """ 

1480 Returns a dictionary containing the XMP tags. 

1481 Requires defusedxml to be installed. 

1482 

1483 :returns: XMP tags in a dictionary. 

1484 """ 

1485 

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

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

1488 

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

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

1491 children = list(element) 

1492 if children: 

1493 for child in children: 

1494 name = get_name(child.tag) 

1495 child_value = get_value(child) 

1496 if name in value: 

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

1498 value[name] = [value[name]] 

1499 value[name].append(child_value) 

1500 else: 

1501 value[name] = child_value 

1502 elif value: 

1503 if element.text: 

1504 value["text"] = element.text 

1505 else: 

1506 return element.text 

1507 return value 

1508 

1509 if ElementTree is None: 

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

1511 return {} 

1512 if "xmp" not in self.info: 

1513 return {} 

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

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

1516 

1517 def getexif(self) -> Exif: 

1518 """ 

1519 Gets EXIF data from the image. 

1520 

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

1522 """ 

1523 if self._exif is None: 

1524 self._exif = Exif() 

1525 elif self._exif._loaded: 

1526 return self._exif 

1527 self._exif._loaded = True 

1528 

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

1530 if exif_info is None: 

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

1532 exif_info = bytes.fromhex( 

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

1534 ) 

1535 elif hasattr(self, "tag_v2"): 

1536 from . import TiffImagePlugin 

1537 

1538 assert isinstance(self, TiffImagePlugin.TiffImageFile) 

1539 self._exif.bigtiff = self.tag_v2._bigtiff 

1540 self._exif.endian = self.tag_v2._endian 

1541 

1542 assert self.fp is not None 

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

1544 if exif_info is not None: 

1545 self._exif.load(exif_info) 

1546 

1547 # XMP tags 

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

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

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

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

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

1553 if xmp_tags: 

1554 match = re.search(pattern, xmp_tags) 

1555 if match: 

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

1557 

1558 return self._exif 

1559 

1560 def _reload_exif(self) -> None: 

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

1562 return 

1563 self._exif._loaded = False 

1564 self.getexif() 

1565 

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

1567 from . import ImageFile 

1568 

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

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

1571 

1572 def getim(self) -> CapsuleType: 

1573 """ 

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

1575 

1576 :returns: A capsule object. 

1577 """ 

1578 

1579 self.load() 

1580 return self.im.ptr 

1581 

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

1583 """ 

1584 Returns the image palette as a list. 

1585 

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

1587 return the palette in its current mode. 

1588 

1589 .. versionadded:: 9.1.0 

1590 

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

1592 image has no palette. 

1593 """ 

1594 

1595 self.load() 

1596 try: 

1597 mode = self.im.getpalettemode() 

1598 except ValueError: 

1599 return None # no palette 

1600 if rawmode is None: 

1601 rawmode = mode 

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

1603 

1604 @property 

1605 def has_transparency_data(self) -> bool: 

1606 """ 

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

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

1609 in the info dictionary. 

1610 

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

1612 within are opaque. 

1613 

1614 :returns: A boolean. 

1615 """ 

1616 if ( 

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

1618 or "transparency" in self.info 

1619 ): 

1620 return True 

1621 if self.mode == "P": 

1622 assert self.palette is not None 

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

1624 return False 

1625 

1626 def apply_transparency(self) -> None: 

1627 """ 

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

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

1630 Otherwise, the image is unchanged. 

1631 """ 

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

1633 return 

1634 

1635 from . import ImagePalette 

1636 

1637 palette = self.getpalette("RGBA") 

1638 assert palette is not None 

1639 transparency = self.info["transparency"] 

1640 if isinstance(transparency, bytes): 

1641 for i, alpha in enumerate(transparency): 

1642 palette[i * 4 + 3] = alpha 

1643 else: 

1644 palette[transparency * 4 + 3] = 0 

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

1646 self.palette.dirty = 1 

1647 

1648 del self.info["transparency"] 

1649 

1650 def getpixel( 

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

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

1653 """ 

1654 Returns the pixel value at a given position. 

1655 

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

1657 :ref:`coordinate-system`. 

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

1659 this method returns a tuple. 

1660 """ 

1661 

1662 self.load() 

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

1664 

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

1666 """ 

1667 Get projection to x and y axes 

1668 

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

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

1671 """ 

1672 

1673 self.load() 

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

1675 return list(x), list(y) 

1676 

1677 def histogram( 

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

1679 ) -> list[int]: 

1680 """ 

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

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

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

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

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

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

1687 

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

1689 by this method. 

1690 

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

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

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

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

1695 

1696 :param mask: An optional mask. 

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

1698 :returns: A list containing pixel counts. 

1699 """ 

1700 self.load() 

1701 if mask: 

1702 mask.load() 

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

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

1705 return self.im.histogram( 

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

1707 ) 

1708 return self.im.histogram() 

1709 

1710 def entropy( 

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

1712 ) -> float: 

1713 """ 

1714 Calculates and returns the entropy for the image. 

1715 

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

1717 image by this method. 

1718 

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

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

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

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

1723 

1724 :param mask: An optional mask. 

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

1726 :returns: A float value representing the image entropy 

1727 """ 

1728 self.load() 

1729 if mask: 

1730 mask.load() 

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

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

1733 return self.im.entropy( 

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

1735 ) 

1736 return self.im.entropy() 

1737 

1738 def paste( 

1739 self, 

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

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

1742 mask: Image | None = None, 

1743 ) -> None: 

1744 """ 

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

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

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

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

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

1750 

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

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

1753 details). 

1754 

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

1756 containing pixel values. The method then fills the region 

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

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

1759 :ref:`colors` for more information. 

1760 

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

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

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

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

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

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

1767 channels if they have them. 

1768 

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

1770 combine images with respect to their alpha channels. 

1771 

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

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

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

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

1776 upper left corner. 

1777 

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

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

1780 is interpreted as a mask image. 

1781 :param mask: An optional mask image. 

1782 """ 

1783 

1784 if isinstance(box, Image): 

1785 if mask is not None: 

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

1787 raise ValueError(msg) 

1788 # abbreviated paste(im, mask) syntax 

1789 mask = box 

1790 box = None 

1791 

1792 if box is None: 

1793 box = (0, 0) 

1794 

1795 if len(box) == 2: 

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

1797 if isinstance(im, Image): 

1798 size = im.size 

1799 elif isinstance(mask, Image): 

1800 size = mask.size 

1801 else: 

1802 # FIXME: use self.size here? 

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

1804 raise ValueError(msg) 

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

1806 

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

1808 if isinstance(im, str): 

1809 from . import ImageColor 

1810 

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

1812 elif isinstance(im, Image): 

1813 im.load() 

1814 if self.mode != im.mode: 

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

1816 # should use an adapter for this! 

1817 im = im.convert(self.mode) 

1818 source = im.im 

1819 else: 

1820 source = im 

1821 

1822 self._ensure_mutable() 

1823 

1824 if mask: 

1825 mask.load() 

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

1827 else: 

1828 self.im.paste(source, box) 

1829 

1830 def alpha_composite( 

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

1832 ) -> None: 

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

1834 onto this image. 

1835 

1836 :param im: image to composite over this one 

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

1838 left corner in this (destination) image. 

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

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

1841 bottom) for the bounds of the source rectangle 

1842 

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

1844 """ 

1845 

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

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

1848 raise ValueError(msg) 

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

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

1851 raise ValueError(msg) 

1852 

1853 if len(source) == 4: 

1854 overlay_crop_box = tuple(source) 

1855 elif len(source) == 2: 

1856 overlay_crop_box = tuple(source) + im.size 

1857 else: 

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

1859 raise ValueError(msg) 

1860 

1861 if not len(dest) == 2: 

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

1863 raise ValueError(msg) 

1864 if min(source) < 0: 

1865 msg = "Source must be non-negative" 

1866 raise ValueError(msg) 

1867 

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

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

1870 overlay = im 

1871 else: 

1872 overlay = im.crop(overlay_crop_box) 

1873 

1874 # target for the paste 

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

1876 

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

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

1879 background = self 

1880 else: 

1881 background = self.crop(box) 

1882 

1883 result = alpha_composite(background, overlay) 

1884 self.paste(result, box) 

1885 

1886 def point( 

1887 self, 

1888 lut: ( 

1889 Sequence[float] 

1890 | NumpyArray 

1891 | Callable[[int], float] 

1892 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1893 | ImagePointHandler 

1894 ), 

1895 mode: str | None = None, 

1896 ) -> Image: 

1897 """ 

1898 Maps this image through a lookup table or function. 

1899 

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

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

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

1903 single argument. The function is called once for each 

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

1905 all bands of the image. 

1906 

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

1908 object:: 

1909 

1910 class Example(Image.ImagePointHandler): 

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

1912 # Return result 

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

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

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

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

1917 """ 

1918 

1919 self.load() 

1920 

1921 if isinstance(lut, ImagePointHandler): 

1922 return lut.point(self) 

1923 

1924 if callable(lut): 

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

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

1927 # check if the function can be used with point_transform 

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

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

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

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

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

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

1934 else: 

1935 flatLut = lut 

1936 

1937 if self.mode == "F": 

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

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

1940 raise ValueError(msg) 

1941 

1942 if mode != "F": 

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

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

1945 

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

1947 """ 

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

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

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

1951 

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

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

1954 """ 

1955 

1956 self._ensure_mutable() 

1957 

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

1959 # attempt to promote self to a matching alpha mode 

1960 try: 

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

1962 try: 

1963 self.im.setmode(mode) 

1964 except (AttributeError, ValueError) as e: 

1965 # do things the hard way 

1966 im = self.im.convert(mode) 

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

1968 msg = "alpha channel could not be added" 

1969 raise ValueError(msg) from e # sanity check 

1970 self.im = im 

1971 self._mode = self.im.mode 

1972 except KeyError as e: 

1973 msg = "illegal image mode" 

1974 raise ValueError(msg) from e 

1975 

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

1977 band = 1 

1978 else: 

1979 band = 3 

1980 

1981 if isinstance(alpha, Image): 

1982 # alpha layer 

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

1984 msg = "illegal image mode" 

1985 raise ValueError(msg) 

1986 alpha.load() 

1987 if alpha.mode == "1": 

1988 alpha = alpha.convert("L") 

1989 else: 

1990 # constant alpha 

1991 try: 

1992 self.im.fillband(band, alpha) 

1993 except (AttributeError, ValueError): 

1994 # do things the hard way 

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

1996 else: 

1997 return 

1998 

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

2000 

2001 def putdata( 

2002 self, 

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

2004 scale: float = 1.0, 

2005 offset: float = 0.0, 

2006 ) -> None: 

2007 """ 

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

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

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

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

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

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

2014 

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

2016 information about values. 

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

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

2019 """ 

2020 

2021 self._ensure_mutable() 

2022 

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

2024 

2025 def putpalette( 

2026 self, 

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

2028 rawmode: str = "RGB", 

2029 ) -> None: 

2030 """ 

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

2032 or "LA" image. 

2033 

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

2035 integer value for each channel in the raw mode. 

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

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

2038 index in the 256 colors. 

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

2040 containing red, green, blue and alpha values. 

2041 

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

2043 

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

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

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

2047 """ 

2048 from . import ImagePalette 

2049 

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

2051 msg = "illegal image mode" 

2052 raise ValueError(msg) 

2053 if isinstance(data, ImagePalette.ImagePalette): 

2054 if data.rawmode is not None: 

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

2056 else: 

2057 palette = ImagePalette.ImagePalette(palette=data.palette) 

2058 palette.dirty = 1 

2059 else: 

2060 if not isinstance(data, bytes): 

2061 data = bytes(data) 

2062 palette = ImagePalette.raw(rawmode, data) 

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

2064 self.palette = palette 

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

2066 self.load() # install new palette 

2067 

2068 def putpixel( 

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

2070 ) -> None: 

2071 """ 

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

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

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

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

2076 

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

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

2079 module instead. 

2080 

2081 See: 

2082 

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

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

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

2086 

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

2088 :ref:`coordinate-system`. 

2089 :param value: The pixel value. 

2090 """ 

2091 

2092 self._ensure_mutable() 

2093 

2094 if ( 

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

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

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

2098 ): 

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

2100 if self.mode == "PA": 

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

2102 value = value[:3] 

2103 assert self.palette is not None 

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

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

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

2107 

2108 def remap_palette( 

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

2110 ) -> Image: 

2111 """ 

2112 Rewrites the image to reorder the palette. 

2113 

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

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

2116 is the identity transform. 

2117 :param source_palette: Bytes or None. 

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

2119 

2120 """ 

2121 from . import ImagePalette 

2122 

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

2124 msg = "illegal image mode" 

2125 raise ValueError(msg) 

2126 

2127 bands = 3 

2128 palette_mode = "RGB" 

2129 if source_palette is None: 

2130 if self.mode == "P": 

2131 self.load() 

2132 palette_mode = self.im.getpalettemode() 

2133 if palette_mode == "RGBA": 

2134 bands = 4 

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

2136 else: # L-mode 

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

2138 elif len(source_palette) > 768: 

2139 bands = 4 

2140 palette_mode = "RGBA" 

2141 

2142 palette_bytes = b"" 

2143 new_positions = [0] * 256 

2144 

2145 # pick only the used colors from the palette 

2146 for i, oldPosition in enumerate(dest_map): 

2147 palette_bytes += source_palette[ 

2148 oldPosition * bands : oldPosition * bands + bands 

2149 ] 

2150 new_positions[oldPosition] = i 

2151 

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

2153 

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

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

2156 # from palette 1 to palette 2. New_positions is 

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

2158 # palette 1 with any holes removed. 

2159 

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

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

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

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

2164 # sans palette thus converting the image bytes, then 

2165 # assigning the optimized RGB palette. 

2166 

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

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

2169 

2170 mapping_palette = bytearray(new_positions) 

2171 

2172 m_im = self.copy() 

2173 m_im._mode = "P" 

2174 

2175 m_im.palette = ImagePalette.ImagePalette( 

2176 palette_mode, palette=mapping_palette * bands 

2177 ) 

2178 # possibly set palette dirty, then 

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

2180 # or just force it. 

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

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

2183 

2184 m_im = m_im.convert("L") 

2185 

2186 m_im.putpalette(palette_bytes, palette_mode) 

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

2188 

2189 if "transparency" in self.info: 

2190 try: 

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

2192 except ValueError: 

2193 if "transparency" in m_im.info: 

2194 del m_im.info["transparency"] 

2195 

2196 return m_im 

2197 

2198 def _get_safe_box( 

2199 self, 

2200 size: tuple[int, int], 

2201 resample: Resampling, 

2202 box: tuple[float, float, float, float], 

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

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

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

2206 """ 

2207 filter_support = _filters_support[resample] - 0.5 

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

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

2210 support_x = filter_support * scale_x 

2211 support_y = filter_support * scale_y 

2212 

2213 return ( 

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

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

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

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

2218 ) 

2219 

2220 def resize( 

2221 self, 

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

2223 resample: int | None = None, 

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

2225 reducing_gap: float | None = None, 

2226 ) -> Image: 

2227 """ 

2228 Returns a resized copy of this image. 

2229 

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

2231 (width, height). 

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

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

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

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

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

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

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

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

2240 the source image region to be scaled. 

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

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

2243 :param reducing_gap: Apply optimization by resizing the image 

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

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

2246 Second, resizing using regular resampling. The last step 

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

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

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

2250 the closer the result to the fair resampling. 

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

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

2253 indistinguishable from fair resampling in most cases. 

2254 The default value is None (no optimization). 

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

2256 """ 

2257 

2258 if resample is None: 

2259 resample = Resampling.BICUBIC 

2260 elif resample not in ( 

2261 Resampling.NEAREST, 

2262 Resampling.BILINEAR, 

2263 Resampling.BICUBIC, 

2264 Resampling.LANCZOS, 

2265 Resampling.BOX, 

2266 Resampling.HAMMING, 

2267 ): 

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

2269 

2270 filters = [ 

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

2272 for filter in ( 

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

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

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

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

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

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

2279 ) 

2280 ] 

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

2282 raise ValueError(msg) 

2283 

2284 if reducing_gap is not None and reducing_gap < 1.0: 

2285 msg = "reducing_gap must be 1.0 or greater" 

2286 raise ValueError(msg) 

2287 

2288 if box is None: 

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

2290 

2291 size = tuple(size) 

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

2293 return self.copy() 

2294 

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

2296 resample = Resampling.NEAREST 

2297 

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

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

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

2301 return im.convert(self.mode) 

2302 

2303 self.load() 

2304 

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

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

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

2308 if factor_x > 1 or factor_y > 1: 

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

2310 factor = (factor_x, factor_y) 

2311 self = ( 

2312 self.reduce(factor, box=reduce_box) 

2313 if callable(self.reduce) 

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

2315 ) 

2316 box = ( 

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

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

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

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

2321 ) 

2322 

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

2324 

2325 def reduce( 

2326 self, 

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

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

2329 ) -> Image: 

2330 """ 

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

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

2333 the resulting size will be rounded up. 

2334 

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

2336 for width and height separately. 

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

2338 the source image region to be reduced. 

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

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

2341 """ 

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

2343 factor = (factor, factor) 

2344 

2345 if box is None: 

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

2347 

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

2349 return self.copy() 

2350 

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

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

2353 im = im.reduce(factor, box) 

2354 return im.convert(self.mode) 

2355 

2356 self.load() 

2357 

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

2359 

2360 def rotate( 

2361 self, 

2362 angle: float, 

2363 resample: Resampling = Resampling.NEAREST, 

2364 expand: int | bool = False, 

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

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

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

2368 ) -> Image: 

2369 """ 

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

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

2372 clockwise around its centre. 

2373 

2374 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2381 See :ref:`concept-filters`. 

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

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

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

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

2386 the center and no translation. 

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

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

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

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

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

2392 """ 

2393 

2394 angle = angle % 360.0 

2395 

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

2397 # translating or changing the center. 

2398 if not (center or translate): 

2399 if angle == 0: 

2400 return self.copy() 

2401 if angle == 180: 

2402 return self.transpose(Transpose.ROTATE_180) 

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

2404 return self.transpose( 

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

2406 ) 

2407 

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

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

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

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

2412 

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

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

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

2416 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2417 

2418 # The reverse matrix is thus: 

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

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

2421 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2422 

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

2424 # compensate for the expand flag. 

2425 

2426 w, h = self.size 

2427 

2428 if translate is None: 

2429 post_trans = (0, 0) 

2430 else: 

2431 post_trans = translate 

2432 if center is None: 

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

2434 

2435 angle = -math.radians(angle) 

2436 matrix = [ 

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

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

2439 0.0, 

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

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

2442 0.0, 

2443 ] 

2444 

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

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

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

2448 

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

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

2451 ) 

2452 matrix[2] += center[0] 

2453 matrix[5] += center[1] 

2454 

2455 if expand: 

2456 # calculate output size 

2457 xx = [] 

2458 yy = [] 

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

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

2461 xx.append(transformed_x) 

2462 yy.append(transformed_y) 

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

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

2465 

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

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

2468 # translation vector as new translation vector. 

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

2470 w, h = nw, nh 

2471 

2472 return self.transform( 

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

2474 ) 

2475 

2476 def save( 

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

2478 ) -> None: 

2479 """ 

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

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

2482 extension, if possible. 

2483 

2484 Keyword options can be used to provide additional instructions 

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

2486 silently ignored. The available options are described in the 

2487 :doc:`image format documentation 

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

2489 

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

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

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

2493 methods, and be opened in binary mode. 

2494 

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

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

2497 format to use is determined from the filename extension. 

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

2499 parameter should always be used. 

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

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

2502 saving multiple images:: 

2503 

2504 # Saving XMP data to a single image 

2505 from PIL import Image 

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

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

2508 

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

2510 from PIL import Image 

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

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

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

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

2515 :returns: None 

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

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

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

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

2520 """ 

2521 

2522 filename: str | bytes = "" 

2523 open_fp = False 

2524 if is_path(fp): 

2525 filename = os.fspath(fp) 

2526 open_fp = True 

2527 elif fp == sys.stdout: 

2528 try: 

2529 fp = sys.stdout.buffer 

2530 except AttributeError: 

2531 pass 

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

2533 # only set the name for metadata purposes 

2534 filename = os.fspath(fp.name) 

2535 

2536 preinit() 

2537 

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

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

2540 

2541 if not format: 

2542 if ext not in EXTENSION: 

2543 init() 

2544 try: 

2545 format = EXTENSION[ext] 

2546 except KeyError as e: 

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

2548 raise ValueError(msg) from e 

2549 

2550 from . import ImageFile 

2551 

2552 # may mutate self! 

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

2554 filename 

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

2556 self._ensure_mutable() 

2557 else: 

2558 self.load() 

2559 

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

2561 self._default_encoderinfo = params 

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

2563 self._attach_default_encoderinfo(self) 

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

2565 

2566 if format.upper() not in SAVE: 

2567 init() 

2568 if save_all or ( 

2569 save_all is None 

2570 and params.get("append_images") 

2571 and format.upper() in SAVE_ALL 

2572 ): 

2573 save_handler = SAVE_ALL[format.upper()] 

2574 else: 

2575 save_handler = SAVE[format.upper()] 

2576 

2577 created = False 

2578 if open_fp: 

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

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

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

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

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

2584 else: 

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

2586 else: 

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

2588 

2589 try: 

2590 save_handler(self, fp, filename) 

2591 except Exception: 

2592 if open_fp: 

2593 fp.close() 

2594 if created: 

2595 try: 

2596 os.remove(filename) 

2597 except PermissionError: 

2598 pass 

2599 raise 

2600 finally: 

2601 self.encoderinfo = encoderinfo 

2602 if open_fp: 

2603 fp.close() 

2604 

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

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

2607 self.encoderinfo = {**im._default_encoderinfo, **encoderinfo} 

2608 return encoderinfo 

2609 

2610 def seek(self, frame: int) -> None: 

2611 """ 

2612 Seeks to the given frame in this sequence file. If you seek 

2613 beyond the end of the sequence, the method raises an 

2614 ``EOFError`` exception. When a sequence file is opened, the 

2615 library automatically seeks to frame 0. 

2616 

2617 See :py:meth:`~PIL.Image.Image.tell`. 

2618 

2619 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the 

2620 number of available frames. 

2621 

2622 :param frame: Frame number, starting at 0. 

2623 :exception EOFError: If the call attempts to seek beyond the end 

2624 of the sequence. 

2625 """ 

2626 

2627 # overridden by file handlers 

2628 if frame != 0: 

2629 msg = "no more images in file" 

2630 raise EOFError(msg) 

2631 

2632 def show(self, title: str | None = None) -> None: 

2633 """ 

2634 Displays this image. This method is mainly intended for debugging purposes. 

2635 

2636 This method calls :py:func:`PIL.ImageShow.show` internally. You can use 

2637 :py:func:`PIL.ImageShow.register` to override its default behaviour. 

2638 

2639 The image is first saved to a temporary file. By default, it will be in 

2640 PNG format. 

2641 

2642 On Unix, the image is then opened using the **xdg-open**, **display**, 

2643 **gm**, **eog** or **xv** utility, depending on which one can be found. 

2644 

2645 On macOS, the image is opened with the native Preview application. 

2646 

2647 On Windows, the image is opened with the standard PNG display utility. 

2648 

2649 :param title: Optional title to use for the image window, where possible. 

2650 """ 

2651 

2652 from . import ImageShow 

2653 

2654 ImageShow.show(self, title) 

2655 

2656 def split(self) -> tuple[Image, ...]: 

2657 """ 

2658 Split this image into individual bands. This method returns a 

2659 tuple of individual image bands from an image. For example, 

2660 splitting an "RGB" image creates three new images each 

2661 containing a copy of one of the original bands (red, green, 

2662 blue). 

2663 

2664 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel` 

2665 method can be more convenient and faster. 

2666 

2667 :returns: A tuple containing bands. 

2668 """ 

2669 

2670 self.load() 

2671 if self.im.bands == 1: 

2672 return (self.copy(),) 

2673 return tuple(map(self._new, self.im.split())) 

2674 

2675 def getchannel(self, channel: int | str) -> Image: 

2676 """ 

2677 Returns an image containing a single channel of the source image. 

2678 

2679 :param channel: What channel to return. Could be index 

2680 (0 for "R" channel of "RGB") or channel name 

2681 ("A" for alpha channel of "RGBA"). 

2682 :returns: An image in "L" mode. 

2683 

2684 .. versionadded:: 4.3.0 

2685 """ 

2686 self.load() 

2687 

2688 if isinstance(channel, str): 

2689 try: 

2690 channel = self.getbands().index(channel) 

2691 except ValueError as e: 

2692 msg = f'The image has no channel "{channel}"' 

2693 raise ValueError(msg) from e 

2694 

2695 return self._new(self.im.getband(channel)) 

2696 

2697 def tell(self) -> int: 

2698 """ 

2699 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. 

2700 

2701 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the 

2702 number of available frames. 

2703 

2704 :returns: Frame number, starting with 0. 

2705 """ 

2706 return 0 

2707 

2708 def thumbnail( 

2709 self, 

2710 size: tuple[float, float], 

2711 resample: Resampling = Resampling.BICUBIC, 

2712 reducing_gap: float | None = 2.0, 

2713 ) -> None: 

2714 """ 

2715 Make this image into a thumbnail. This method modifies the 

2716 image to contain a thumbnail version of itself, no larger than 

2717 the given size. This method calculates an appropriate thumbnail 

2718 size to preserve the aspect of the image, calls the 

2719 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader 

2720 (where applicable), and finally resizes the image. 

2721 

2722 Note that this function modifies the :py:class:`~PIL.Image.Image` 

2723 object in place. If you need to use the full resolution image as well, 

2724 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original 

2725 image. 

2726 

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

2728 (width, height). 

2729 :param resample: Optional resampling filter. This can be one 

2730 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, 

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

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

2733 If omitted, it defaults to :py:data:`Resampling.BICUBIC`. 

2734 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0). 

2735 See: :ref:`concept-filters`. 

2736 :param reducing_gap: Apply optimization by resizing the image 

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

2738 using :py:meth:`~PIL.Image.Image.reduce` or 

2739 :py:meth:`~PIL.Image.Image.draft` for JPEG images. 

2740 Second, resizing using regular resampling. The last step 

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

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

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

2744 the closer the result to the fair resampling. 

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

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

2747 indistinguishable from fair resampling in most cases. 

2748 The default value is 2.0 (very close to fair resampling 

2749 while still being faster in many cases). 

2750 :returns: None 

2751 """ 

2752 

2753 provided_size = tuple(map(math.floor, size)) 

2754 

2755 def preserve_aspect_ratio() -> tuple[int, int] | None: 

2756 def round_aspect(number: float, key: Callable[[int], float]) -> int: 

2757 return max(min(math.floor(number), math.ceil(number), key=key), 1) 

2758 

2759 x, y = provided_size 

2760 if x >= self.width and y >= self.height: 

2761 return None 

2762 

2763 aspect = self.width / self.height 

2764 if x / y >= aspect: 

2765 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) 

2766 else: 

2767 y = round_aspect( 

2768 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n) 

2769 ) 

2770 return x, y 

2771 

2772 preserved_size = preserve_aspect_ratio() 

2773 if preserved_size is None: 

2774 return 

2775 final_size = preserved_size 

2776 

2777 box = None 

2778 if reducing_gap is not None: 

2779 res = self.draft( 

2780 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) 

2781 ) 

2782 if res is not None: 

2783 box = res[1] 

2784 

2785 if self.size != final_size: 

2786 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) 

2787 

2788 self.im = im.im 

2789 self._size = final_size 

2790 self._mode = self.im.mode 

2791 

2792 self.readonly = 0 

2793 

2794 # FIXME: the different transform methods need further explanation 

2795 # instead of bloating the method docs, add a separate chapter. 

2796 def transform( 

2797 self, 

2798 size: tuple[int, int], 

2799 method: Transform | ImageTransformHandler | SupportsGetData, 

2800 data: Sequence[Any] | None = None, 

2801 resample: int = Resampling.NEAREST, 

2802 fill: int = 1, 

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

2804 ) -> Image: 

2805 """ 

2806 Transforms this image. This method creates a new image with the 

2807 given size, and the same mode as the original, and copies data 

2808 to the new image using the given transform. 

2809 

2810 :param size: The output size in pixels, as a 2-tuple: 

2811 (width, height). 

2812 :param method: The transformation method. This is one of 

2813 :py:data:`Transform.EXTENT` (cut out a rectangular subregion), 

2814 :py:data:`Transform.AFFINE` (affine transform), 

2815 :py:data:`Transform.PERSPECTIVE` (perspective transform), 

2816 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or 

2817 :py:data:`Transform.MESH` (map a number of source quadrilaterals 

2818 in one operation). 

2819 

2820 It may also be an :py:class:`~PIL.Image.ImageTransformHandler` 

2821 object:: 

2822 

2823 class Example(Image.ImageTransformHandler): 

2824 def transform(self, size, data, resample, fill=1): 

2825 # Return result 

2826 

2827 Implementations of :py:class:`~PIL.Image.ImageTransformHandler` 

2828 for some of the :py:class:`Transform` methods are provided 

2829 in :py:mod:`~PIL.ImageTransform`. 

2830 

2831 It may also be an object with a ``method.getdata`` method 

2832 that returns a tuple supplying new ``method`` and ``data`` values:: 

2833 

2834 class Example: 

2835 def getdata(self): 

2836 method = Image.Transform.EXTENT 

2837 data = (0, 0, 100, 100) 

2838 return method, data 

2839 :param data: Extra data to the transformation method. 

2840 :param resample: Optional resampling filter. It can be one of 

2841 :py:data:`Resampling.NEAREST` (use nearest neighbour), 

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

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

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

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

2846 See: :ref:`concept-filters`. 

2847 :param fill: If ``method`` is an 

2848 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of 

2849 the arguments passed to it. Otherwise, it is unused. 

2850 :param fillcolor: Optional fill color for the area outside the 

2851 transform in the output image. 

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

2853 """ 

2854 

2855 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: 

2856 return ( 

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

2858 .transform(size, method, data, resample, fill, fillcolor) 

2859 .convert(self.mode) 

2860 ) 

2861 

2862 if isinstance(method, ImageTransformHandler): 

2863 return method.transform(size, self, resample=resample, fill=fill) 

2864 

2865 if hasattr(method, "getdata"): 

2866 # compatibility w. old-style transform objects 

2867 method, data = method.getdata() 

2868 

2869 if data is None: 

2870 msg = "missing method data" 

2871 raise ValueError(msg) 

2872 

2873 im = new(self.mode, size, fillcolor) 

2874 if self.mode == "P" and self.palette: 

2875 im.palette = self.palette.copy() 

2876 im.info = self.info.copy() 

2877 if method == Transform.MESH: 

2878 # list of quads 

2879 for box, quad in data: 

2880 im.__transformer( 

2881 box, self, Transform.QUAD, quad, resample, fillcolor is None 

2882 ) 

2883 else: 

2884 im.__transformer( 

2885 (0, 0) + size, self, method, data, resample, fillcolor is None 

2886 ) 

2887 

2888 return im 

2889 

2890 def __transformer( 

2891 self, 

2892 box: tuple[int, int, int, int], 

2893 image: Image, 

2894 method: Transform, 

2895 data: Sequence[float], 

2896 resample: int = Resampling.NEAREST, 

2897 fill: bool = True, 

2898 ) -> None: 

2899 w = box[2] - box[0] 

2900 h = box[3] - box[1] 

2901 

2902 if method == Transform.AFFINE: 

2903 data = data[:6] 

2904 

2905 elif method == Transform.EXTENT: 

2906 # convert extent to an affine transform 

2907 x0, y0, x1, y1 = data 

2908 xs = (x1 - x0) / w 

2909 ys = (y1 - y0) / h 

2910 method = Transform.AFFINE 

2911 data = (xs, 0, x0, 0, ys, y0) 

2912 

2913 elif method == Transform.PERSPECTIVE: 

2914 data = data[:8] 

2915 

2916 elif method == Transform.QUAD: 

2917 # quadrilateral warp. data specifies the four corners 

2918 # given as NW, SW, SE, and NE. 

2919 nw = data[:2] 

2920 sw = data[2:4] 

2921 se = data[4:6] 

2922 ne = data[6:8] 

2923 x0, y0 = nw 

2924 As = 1.0 / w 

2925 At = 1.0 / h 

2926 data = ( 

2927 x0, 

2928 (ne[0] - x0) * As, 

2929 (sw[0] - x0) * At, 

2930 (se[0] - sw[0] - ne[0] + x0) * As * At, 

2931 y0, 

2932 (ne[1] - y0) * As, 

2933 (sw[1] - y0) * At, 

2934 (se[1] - sw[1] - ne[1] + y0) * As * At, 

2935 ) 

2936 

2937 else: 

2938 msg = "unknown transformation method" 

2939 raise ValueError(msg) 

2940 

2941 if resample not in ( 

2942 Resampling.NEAREST, 

2943 Resampling.BILINEAR, 

2944 Resampling.BICUBIC, 

2945 ): 

2946 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

2947 unusable: dict[int, str] = { 

2948 Resampling.BOX: "Image.Resampling.BOX", 

2949 Resampling.HAMMING: "Image.Resampling.HAMMING", 

2950 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

2951 } 

2952 msg = unusable[resample] + f" ({resample}) cannot be used." 

2953 else: 

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

2955 

2956 filters = [ 

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

2958 for filter in ( 

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

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

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

2962 ) 

2963 ] 

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

2965 raise ValueError(msg) 

2966 

2967 image.load() 

2968 

2969 self.load() 

2970 

2971 if image.mode in ("1", "P"): 

2972 resample = Resampling.NEAREST 

2973 

2974 self.im.transform(box, image.im, method, data, resample, fill) 

2975 

2976 def transpose(self, method: Transpose) -> Image: 

2977 """ 

2978 Transpose image (flip or rotate in 90 degree steps) 

2979 

2980 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

2981 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

2982 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

2983 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

2984 :returns: Returns a flipped or rotated copy of this image. 

2985 """ 

2986 

2987 self.load() 

2988 return self._new(self.im.transpose(method)) 

2989 

2990 def effect_spread(self, distance: int) -> Image: 

2991 """ 

2992 Randomly spread pixels in an image. 

2993 

2994 :param distance: Distance to spread pixels. 

2995 """ 

2996 self.load() 

2997 return self._new(self.im.effect_spread(distance)) 

2998 

2999 def toqimage(self) -> ImageQt.ImageQt: 

3000 """Returns a QImage copy of this image""" 

3001 from . import ImageQt 

3002 

3003 if not ImageQt.qt_is_installed: 

3004 msg = "Qt bindings are not installed" 

3005 raise ImportError(msg) 

3006 return ImageQt.toqimage(self) 

3007 

3008 def toqpixmap(self) -> ImageQt.QPixmap: 

3009 """Returns a QPixmap copy of this image""" 

3010 from . import ImageQt 

3011 

3012 if not ImageQt.qt_is_installed: 

3013 msg = "Qt bindings are not installed" 

3014 raise ImportError(msg) 

3015 return ImageQt.toqpixmap(self) 

3016 

3017 

3018# -------------------------------------------------------------------- 

3019# Abstract handlers. 

3020 

3021 

3022class ImagePointHandler(abc.ABC): 

3023 """ 

3024 Used as a mixin by point transforms 

3025 (for use with :py:meth:`~PIL.Image.Image.point`) 

3026 """ 

3027 

3028 @abc.abstractmethod 

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

3030 pass 

3031 

3032 

3033class ImageTransformHandler(abc.ABC): 

3034 """ 

3035 Used as a mixin by geometry transforms 

3036 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3037 """ 

3038 

3039 @abc.abstractmethod 

3040 def transform( 

3041 self, 

3042 size: tuple[int, int], 

3043 image: Image, 

3044 **options: Any, 

3045 ) -> Image: 

3046 pass 

3047 

3048 

3049# -------------------------------------------------------------------- 

3050# Factories 

3051 

3052 

3053def _check_size(size: Any) -> None: 

3054 """ 

3055 Common check to enforce type and sanity check on size tuples 

3056 

3057 :param size: Should be a 2 tuple of (width, height) 

3058 :returns: None, or raises a ValueError 

3059 """ 

3060 

3061 if not isinstance(size, (list, tuple)): 

3062 msg = "Size must be a list or tuple" 

3063 raise ValueError(msg) 

3064 if len(size) != 2: 

3065 msg = "Size must be a sequence of length 2" 

3066 raise ValueError(msg) 

3067 if size[0] < 0 or size[1] < 0: 

3068 msg = "Width and height must be >= 0" 

3069 raise ValueError(msg) 

3070 

3071 

3072def new( 

3073 mode: str, 

3074 size: tuple[int, int] | list[int], 

3075 color: float | tuple[float, ...] | str | None = 0, 

3076) -> Image: 

3077 """ 

3078 Creates a new image with the given mode and size. 

3079 

3080 :param mode: The mode to use for the new image. See: 

3081 :ref:`concept-modes`. 

3082 :param size: A 2-tuple, containing (width, height) in pixels. 

3083 :param color: What color to use for the image. Default is black. If given, 

3084 this should be a single integer or floating point value for single-band 

3085 modes, and a tuple for multi-band modes (one value per band). When 

3086 creating RGB or HSV images, you can also use color strings as supported 

3087 by the ImageColor module. See :ref:`colors` for more information. If the 

3088 color is None, the image is not initialised. 

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

3090 """ 

3091 

3092 _check_size(size) 

3093 

3094 if color is None: 

3095 # don't initialize 

3096 return Image()._new(core.new(mode, size)) 

3097 

3098 if isinstance(color, str): 

3099 # css3-style specifier 

3100 

3101 from . import ImageColor 

3102 

3103 color = ImageColor.getcolor(color, mode) 

3104 

3105 im = Image() 

3106 if ( 

3107 mode == "P" 

3108 and isinstance(color, (list, tuple)) 

3109 and all(isinstance(i, int) for i in color) 

3110 ): 

3111 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3112 if len(color_ints) == 3 or len(color_ints) == 4: 

3113 # RGB or RGBA value for a P image 

3114 from . import ImagePalette 

3115 

3116 im.palette = ImagePalette.ImagePalette() 

3117 color = im.palette.getcolor(color_ints) 

3118 return im._new(core.fill(mode, size, color)) 

3119 

3120 

3121def frombytes( 

3122 mode: str, 

3123 size: tuple[int, int], 

3124 data: bytes | bytearray | SupportsArrayInterface, 

3125 decoder_name: str = "raw", 

3126 *args: Any, 

3127) -> Image: 

3128 """ 

3129 Creates a copy of an image memory from pixel data in a buffer. 

3130 

3131 In its simplest form, this function takes three arguments 

3132 (mode, size, and unpacked pixel data). 

3133 

3134 You can also use any pixel decoder supported by PIL. For more 

3135 information on available decoders, see the section 

3136 :ref:`Writing Your Own File Codec <file-codecs>`. 

3137 

3138 Note that this function decodes pixel data only, not entire images. 

3139 If you have an entire image in a string, wrap it in a 

3140 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3141 it. 

3142 

3143 :param mode: The image mode. See: :ref:`concept-modes`. 

3144 :param size: The image size. 

3145 :param data: A byte buffer containing raw data for the given mode. 

3146 :param decoder_name: What decoder to use. 

3147 :param args: Additional parameters for the given decoder. 

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

3149 """ 

3150 

3151 _check_size(size) 

3152 

3153 im = new(mode, size) 

3154 if im.width != 0 and im.height != 0: 

3155 decoder_args: Any = args 

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

3157 # may pass tuple instead of argument list 

3158 decoder_args = decoder_args[0] 

3159 

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

3161 decoder_args = mode 

3162 

3163 im.frombytes(data, decoder_name, decoder_args) 

3164 return im 

3165 

3166 

3167def frombuffer( 

3168 mode: str, 

3169 size: tuple[int, int], 

3170 data: bytes | SupportsArrayInterface, 

3171 decoder_name: str = "raw", 

3172 *args: Any, 

3173) -> Image: 

3174 """ 

3175 Creates an image memory referencing pixel data in a byte buffer. 

3176 

3177 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3178 in the byte buffer, where possible. This means that changes to the 

3179 original buffer object are reflected in this image). Not all modes can 

3180 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3181 

3182 Note that this function decodes pixel data only, not entire images. 

3183 If you have an entire image file in a string, wrap it in a 

3184 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3185 

3186 The default parameters used for the "raw" decoder differs from that used for 

3187 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3188 future release. The current release issues a warning if you do this; to disable 

3189 the warning, you should provide the full set of parameters. See below for details. 

3190 

3191 :param mode: The image mode. See: :ref:`concept-modes`. 

3192 :param size: The image size. 

3193 :param data: A bytes or other buffer object containing raw 

3194 data for the given mode. 

3195 :param decoder_name: What decoder to use. 

3196 :param args: Additional parameters for the given decoder. For the 

3197 default encoder ("raw"), it's recommended that you provide the 

3198 full set of parameters:: 

3199 

3200 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3201 

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

3203 

3204 .. versionadded:: 1.1.4 

3205 """ 

3206 

3207 _check_size(size) 

3208 

3209 # may pass tuple instead of argument list 

3210 if len(args) == 1 and isinstance(args[0], tuple): 

3211 args = args[0] 

3212 

3213 if decoder_name == "raw": 

3214 if args == (): 

3215 args = mode, 0, 1 

3216 if args[0] in _MAPMODES: 

3217 im = new(mode, (0, 0)) 

3218 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3219 if mode == "P": 

3220 from . import ImagePalette 

3221 

3222 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3223 im.readonly = 1 

3224 return im 

3225 

3226 return frombytes(mode, size, data, decoder_name, args) 

3227 

3228 

3229class SupportsArrayInterface(Protocol): 

3230 """ 

3231 An object that has an ``__array_interface__`` dictionary. 

3232 """ 

3233 

3234 @property 

3235 def __array_interface__(self) -> dict[str, Any]: 

3236 raise NotImplementedError() 

3237 

3238 

3239class SupportsArrowArrayInterface(Protocol): 

3240 """ 

3241 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3242 data interface. 

3243 """ 

3244 

3245 def __arrow_c_array__( 

3246 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3247 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3248 raise NotImplementedError() 

3249 

3250 

3251def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3252 """ 

3253 Creates an image memory from an object exporting the array interface 

3254 (using the buffer protocol):: 

3255 

3256 from PIL import Image 

3257 import numpy as np 

3258 a = np.zeros((5, 5)) 

3259 im = Image.fromarray(a) 

3260 

3261 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3262 and :py:func:`~PIL.Image.frombuffer` is used. 

3263 

3264 In the case of NumPy, be aware that Pillow modes do not always correspond 

3265 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3266 32-bit signed integer pixels, and 32-bit floating point pixels. 

3267 

3268 Pillow images can also be converted to arrays:: 

3269 

3270 from PIL import Image 

3271 import numpy as np 

3272 im = Image.open("hopper.jpg") 

3273 a = np.asarray(im) 

3274 

3275 When converting Pillow images to arrays however, only pixel values are 

3276 transferred. This means that P and PA mode images will lose their palette. 

3277 

3278 :param obj: Object with array interface 

3279 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not 

3280 contain information about palettes or color spaces, this can be used to place 

3281 grayscale L mode data within a P mode image, or read RGB data as YCbCr for 

3282 example. 

3283 

3284 See: :ref:`concept-modes` for general information about modes. 

3285 :returns: An image object. 

3286 

3287 .. versionadded:: 1.1.6 

3288 """ 

3289 arr = obj.__array_interface__ 

3290 shape = arr["shape"] 

3291 ndim = len(shape) 

3292 strides = arr.get("strides", None) 

3293 try: 

3294 typekey = (1, 1) + shape[2:], arr["typestr"] 

3295 except KeyError as e: 

3296 if mode is not None: 

3297 typekey = None 

3298 color_modes: list[str] = [] 

3299 else: 

3300 msg = "Cannot handle this data type" 

3301 raise TypeError(msg) from e 

3302 if typekey is not None: 

3303 try: 

3304 typemode, rawmode, color_modes = _fromarray_typemap[typekey] 

3305 except KeyError as e: 

3306 typekey_shape, typestr = typekey 

3307 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3308 raise TypeError(msg) from e 

3309 if mode is not None: 

3310 if mode != typemode and mode not in color_modes: 

3311 deprecate("'mode' parameter for changing data types", 13) 

3312 rawmode = mode 

3313 else: 

3314 mode = typemode 

3315 if mode in ["1", "L", "I", "P", "F"]: 

3316 ndmax = 2 

3317 elif mode == "RGB": 

3318 ndmax = 3 

3319 else: 

3320 ndmax = 4 

3321 if ndim > ndmax: 

3322 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3323 raise ValueError(msg) 

3324 

3325 size = 1 if ndim == 1 else shape[1], shape[0] 

3326 if strides is not None: 

3327 if hasattr(obj, "tobytes"): 

3328 obj = obj.tobytes() 

3329 elif hasattr(obj, "tostring"): 

3330 obj = obj.tostring() 

3331 else: 

3332 msg = "'strides' requires either tobytes() or tostring()" 

3333 raise ValueError(msg) 

3334 

3335 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3336 

3337 

3338def fromarrow( 

3339 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3340) -> Image: 

3341 """Creates an image with zero-copy shared memory from an object exporting 

3342 the arrow_c_array interface protocol:: 

3343 

3344 from PIL import Image 

3345 import pyarrow as pa 

3346 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3347 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3348 

3349 If the data representation of the ``obj`` is not compatible with 

3350 Pillow internal storage, a ValueError is raised. 

3351 

3352 Pillow images can also be converted to Arrow objects:: 

3353 

3354 from PIL import Image 

3355 import pyarrow as pa 

3356 im = Image.open('hopper.jpg') 

3357 arr = pa.array(im) 

3358 

3359 As with array support, when converting Pillow images to arrays, 

3360 only pixel values are transferred. This means that P and PA mode 

3361 images will lose their palette. 

3362 

3363 :param obj: Object with an arrow_c_array interface 

3364 :param mode: Image mode. 

3365 :param size: Image size. This must match the storage of the arrow object. 

3366 :returns: An Image object 

3367 

3368 Note that according to the Arrow spec, both the producer and the 

3369 consumer should consider the exported array to be immutable, as 

3370 unsynchronized updates will potentially cause inconsistent data. 

3371 

3372 See: :ref:`arrow-support` for more detailed information 

3373 

3374 .. versionadded:: 11.2.1 

3375 

3376 """ 

3377 if not hasattr(obj, "__arrow_c_array__"): 

3378 msg = "arrow_c_array interface not found" 

3379 raise ValueError(msg) 

3380 

3381 (schema_capsule, array_capsule) = obj.__arrow_c_array__() 

3382 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3383 if _im: 

3384 return Image()._new(_im) 

3385 

3386 msg = "new_arrow returned None without an exception" 

3387 raise ValueError(msg) 

3388 

3389 

3390def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3391 """Creates an image instance from a QImage image""" 

3392 from . import ImageQt 

3393 

3394 if not ImageQt.qt_is_installed: 

3395 msg = "Qt bindings are not installed" 

3396 raise ImportError(msg) 

3397 return ImageQt.fromqimage(im) 

3398 

3399 

3400def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3401 """Creates an image instance from a QPixmap image""" 

3402 from . import ImageQt 

3403 

3404 if not ImageQt.qt_is_installed: 

3405 msg = "Qt bindings are not installed" 

3406 raise ImportError(msg) 

3407 return ImageQt.fromqpixmap(im) 

3408 

3409 

3410_fromarray_typemap = { 

3411 # (shape, typestr) => mode, rawmode, color modes 

3412 # first two members of shape are set to one 

3413 ((1, 1), "|b1"): ("1", "1;8", []), 

3414 ((1, 1), "|u1"): ("L", "L", ["P"]), 

3415 ((1, 1), "|i1"): ("I", "I;8", []), 

3416 ((1, 1), "<u2"): ("I", "I;16", []), 

3417 ((1, 1), ">u2"): ("I", "I;16B", []), 

3418 ((1, 1), "<i2"): ("I", "I;16S", []), 

3419 ((1, 1), ">i2"): ("I", "I;16BS", []), 

3420 ((1, 1), "<u4"): ("I", "I;32", []), 

3421 ((1, 1), ">u4"): ("I", "I;32B", []), 

3422 ((1, 1), "<i4"): ("I", "I;32S", []), 

3423 ((1, 1), ">i4"): ("I", "I;32BS", []), 

3424 ((1, 1), "<f4"): ("F", "F;32F", []), 

3425 ((1, 1), ">f4"): ("F", "F;32BF", []), 

3426 ((1, 1), "<f8"): ("F", "F;64F", []), 

3427 ((1, 1), ">f8"): ("F", "F;64BF", []), 

3428 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]), 

3429 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), 

3430 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), 

3431 # shortcuts: 

3432 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []), 

3433 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []), 

3434} 

3435 

3436 

3437def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3438 if MAX_IMAGE_PIXELS is None: 

3439 return 

3440 

3441 pixels = max(1, size[0]) * max(1, size[1]) 

3442 

3443 if pixels > 2 * MAX_IMAGE_PIXELS: 

3444 msg = ( 

3445 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3446 "pixels, could be decompression bomb DOS attack." 

3447 ) 

3448 raise DecompressionBombError(msg) 

3449 

3450 if pixels > MAX_IMAGE_PIXELS: 

3451 warnings.warn( 

3452 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3453 "could be decompression bomb DOS attack.", 

3454 DecompressionBombWarning, 

3455 ) 

3456 

3457 

3458def open( 

3459 fp: StrOrBytesPath | IO[bytes], 

3460 mode: Literal["r"] = "r", 

3461 formats: list[str] | tuple[str, ...] | None = None, 

3462) -> ImageFile.ImageFile: 

3463 """ 

3464 Opens and identifies the given image file. 

3465 

3466 This is a lazy operation; this function identifies the file, but 

3467 the file remains open and the actual image data is not read from 

3468 the file until you try to process the data (or call the 

3469 :py:meth:`~PIL.Image.Image.load` method). See 

3470 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3471 

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

3473 The file object must implement ``file.read``, 

3474 ``file.seek``, and ``file.tell`` methods, 

3475 and be opened in binary mode. The file object will also seek to zero 

3476 before reading. 

3477 :param mode: The mode. If given, this argument must be "r". 

3478 :param formats: A list or tuple of formats to attempt to load the file in. 

3479 This can be used to restrict the set of formats checked. 

3480 Pass ``None`` to try all supported formats. You can print the set of 

3481 available formats by running ``python3 -m PIL`` or using 

3482 the :py:func:`PIL.features.pilinfo` function. 

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

3484 :exception FileNotFoundError: If the file cannot be found. 

3485 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3486 identified. 

3487 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3488 instance is used for ``fp``. 

3489 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3490 """ 

3491 

3492 if mode != "r": 

3493 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3494 raise ValueError(msg) 

3495 elif isinstance(fp, io.StringIO): 

3496 msg = ( # type: ignore[unreachable] 

3497 "StringIO cannot be used to open an image. " 

3498 "Binary data must be used instead." 

3499 ) 

3500 raise ValueError(msg) 

3501 

3502 if formats is None: 

3503 formats = ID 

3504 elif not isinstance(formats, (list, tuple)): 

3505 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3506 raise TypeError(msg) 

3507 

3508 exclusive_fp = False 

3509 filename: str | bytes = "" 

3510 if is_path(fp): 

3511 filename = os.fspath(fp) 

3512 fp = builtins.open(filename, "rb") 

3513 exclusive_fp = True 

3514 else: 

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

3516 

3517 try: 

3518 fp.seek(0) 

3519 except (AttributeError, io.UnsupportedOperation): 

3520 fp = io.BytesIO(fp.read()) 

3521 exclusive_fp = True 

3522 

3523 prefix = fp.read(16) 

3524 

3525 preinit() 

3526 

3527 warning_messages: list[str] = [] 

3528 

3529 def _open_core( 

3530 fp: IO[bytes], 

3531 filename: str | bytes, 

3532 prefix: bytes, 

3533 formats: list[str] | tuple[str, ...], 

3534 ) -> ImageFile.ImageFile | None: 

3535 for i in formats: 

3536 i = i.upper() 

3537 if i not in OPEN: 

3538 init() 

3539 try: 

3540 factory, accept = OPEN[i] 

3541 result = not accept or accept(prefix) 

3542 if isinstance(result, str): 

3543 warning_messages.append(result) 

3544 elif result: 

3545 fp.seek(0) 

3546 im = factory(fp, filename) 

3547 _decompression_bomb_check(im.size) 

3548 return im 

3549 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3550 if WARN_POSSIBLE_FORMATS: 

3551 warning_messages.append(i + " opening failed. " + str(e)) 

3552 except BaseException: 

3553 if exclusive_fp: 

3554 fp.close() 

3555 raise 

3556 return None 

3557 

3558 im = _open_core(fp, filename, prefix, formats) 

3559 

3560 if im is None and formats is ID: 

3561 checked_formats = ID.copy() 

3562 if init(): 

3563 im = _open_core( 

3564 fp, 

3565 filename, 

3566 prefix, 

3567 tuple(format for format in formats if format not in checked_formats), 

3568 ) 

3569 

3570 if im: 

3571 im._exclusive_fp = exclusive_fp 

3572 return im 

3573 

3574 if exclusive_fp: 

3575 fp.close() 

3576 for message in warning_messages: 

3577 warnings.warn(message) 

3578 msg = "cannot identify image file %r" % (filename if filename else fp) 

3579 raise UnidentifiedImageError(msg) 

3580 

3581 

3582# 

3583# Image processing. 

3584 

3585 

3586def alpha_composite(im1: Image, im2: Image) -> Image: 

3587 """ 

3588 Alpha composite im2 over im1. 

3589 

3590 :param im1: The first image. Must have mode RGBA or LA. 

3591 :param im2: The second image. Must have the same mode and size as the first image. 

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

3593 """ 

3594 

3595 im1.load() 

3596 im2.load() 

3597 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3598 

3599 

3600def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3601 """ 

3602 Creates a new image by interpolating between two input images, using 

3603 a constant alpha:: 

3604 

3605 out = image1 * (1.0 - alpha) + image2 * alpha 

3606 

3607 :param im1: The first image. 

3608 :param im2: The second image. Must have the same mode and size as 

3609 the first image. 

3610 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3611 copy of the first image is returned. If alpha is 1.0, a copy of 

3612 the second image is returned. There are no restrictions on the 

3613 alpha value. If necessary, the result is clipped to fit into 

3614 the allowed output range. 

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

3616 """ 

3617 

3618 im1.load() 

3619 im2.load() 

3620 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3621 

3622 

3623def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3624 """ 

3625 Create composite image by blending images using a transparency mask. 

3626 

3627 :param image1: The first image. 

3628 :param image2: The second image. Must have the same mode and 

3629 size as the first image. 

3630 :param mask: A mask image. This image can have mode 

3631 "1", "L", or "RGBA", and must have the same size as the 

3632 other two images. 

3633 """ 

3634 

3635 image = image2.copy() 

3636 image.paste(image1, None, mask) 

3637 return image 

3638 

3639 

3640def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3641 """ 

3642 Applies the function (which should take one argument) to each pixel 

3643 in the given image. If the image has more than one band, the same 

3644 function is applied to each band. Note that the function is 

3645 evaluated once for each possible pixel value, so you cannot use 

3646 random components or other generators. 

3647 

3648 :param image: The input image. 

3649 :param function: A function object, taking one integer argument. 

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

3651 """ 

3652 

3653 return image.point(args[0]) 

3654 

3655 

3656def merge(mode: str, bands: Sequence[Image]) -> Image: 

3657 """ 

3658 Merge a set of single band images into a new multiband image. 

3659 

3660 :param mode: The mode to use for the output image. See: 

3661 :ref:`concept-modes`. 

3662 :param bands: A sequence containing one single-band image for 

3663 each band in the output image. All bands must have the 

3664 same size. 

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

3666 """ 

3667 

3668 if getmodebands(mode) != len(bands) or "*" in mode: 

3669 msg = "wrong number of bands" 

3670 raise ValueError(msg) 

3671 for band in bands[1:]: 

3672 if band.mode != getmodetype(mode): 

3673 msg = "mode mismatch" 

3674 raise ValueError(msg) 

3675 if band.size != bands[0].size: 

3676 msg = "size mismatch" 

3677 raise ValueError(msg) 

3678 for band in bands: 

3679 band.load() 

3680 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3681 

3682 

3683# -------------------------------------------------------------------- 

3684# Plugin registry 

3685 

3686 

3687def register_open( 

3688 id: str, 

3689 factory: ( 

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

3691 | type[ImageFile.ImageFile] 

3692 ), 

3693 accept: Callable[[bytes], bool | str] | None = None, 

3694) -> None: 

3695 """ 

3696 Register an image file plugin. This function should not be used 

3697 in application code. 

3698 

3699 :param id: An image format identifier. 

3700 :param factory: An image file factory method. 

3701 :param accept: An optional function that can be used to quickly 

3702 reject images having another format. 

3703 """ 

3704 id = id.upper() 

3705 if id not in ID: 

3706 ID.append(id) 

3707 OPEN[id] = factory, accept 

3708 

3709 

3710def register_mime(id: str, mimetype: str) -> None: 

3711 """ 

3712 Registers an image MIME type by populating ``Image.MIME``. This function 

3713 should not be used in application code. 

3714 

3715 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3716 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3717 provide a different result for specific images. 

3718 

3719 :param id: An image format identifier. 

3720 :param mimetype: The image MIME type for this format. 

3721 """ 

3722 MIME[id.upper()] = mimetype 

3723 

3724 

3725def register_save( 

3726 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3727) -> None: 

3728 """ 

3729 Registers an image save function. This function should not be 

3730 used in application code. 

3731 

3732 :param id: An image format identifier. 

3733 :param driver: A function to save images in this format. 

3734 """ 

3735 SAVE[id.upper()] = driver 

3736 

3737 

3738def register_save_all( 

3739 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3740) -> None: 

3741 """ 

3742 Registers an image function to save all the frames 

3743 of a multiframe format. This function should not be 

3744 used in application code. 

3745 

3746 :param id: An image format identifier. 

3747 :param driver: A function to save images in this format. 

3748 """ 

3749 SAVE_ALL[id.upper()] = driver 

3750 

3751 

3752def register_extension(id: str, extension: str) -> None: 

3753 """ 

3754 Registers an image extension. This function should not be 

3755 used in application code. 

3756 

3757 :param id: An image format identifier. 

3758 :param extension: An extension used for this format. 

3759 """ 

3760 EXTENSION[extension.lower()] = id.upper() 

3761 

3762 

3763def register_extensions(id: str, extensions: list[str]) -> None: 

3764 """ 

3765 Registers image extensions. This function should not be 

3766 used in application code. 

3767 

3768 :param id: An image format identifier. 

3769 :param extensions: A list of extensions used for this format. 

3770 """ 

3771 for extension in extensions: 

3772 register_extension(id, extension) 

3773 

3774 

3775def registered_extensions() -> dict[str, str]: 

3776 """ 

3777 Returns a dictionary containing all file extensions belonging 

3778 to registered plugins 

3779 """ 

3780 init() 

3781 return EXTENSION 

3782 

3783 

3784def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3785 """ 

3786 Registers an image decoder. This function should not be 

3787 used in application code. 

3788 

3789 :param name: The name of the decoder 

3790 :param decoder: An ImageFile.PyDecoder object 

3791 

3792 .. versionadded:: 4.1.0 

3793 """ 

3794 DECODERS[name] = decoder 

3795 

3796 

3797def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3798 """ 

3799 Registers an image encoder. This function should not be 

3800 used in application code. 

3801 

3802 :param name: The name of the encoder 

3803 :param encoder: An ImageFile.PyEncoder object 

3804 

3805 .. versionadded:: 4.1.0 

3806 """ 

3807 ENCODERS[name] = encoder 

3808 

3809 

3810# -------------------------------------------------------------------- 

3811# Simple display support. 

3812 

3813 

3814def _show(image: Image, **options: Any) -> None: 

3815 from . import ImageShow 

3816 

3817 deprecate("Image._show", 13, "ImageShow.show") 

3818 ImageShow.show(image, **options) 

3819 

3820 

3821# -------------------------------------------------------------------- 

3822# Effects 

3823 

3824 

3825def effect_mandelbrot( 

3826 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3827) -> Image: 

3828 """ 

3829 Generate a Mandelbrot set covering the given extent. 

3830 

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

3832 (width, height). 

3833 :param extent: The extent to cover, as a 4-tuple: 

3834 (x0, y0, x1, y1). 

3835 :param quality: Quality. 

3836 """ 

3837 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3838 

3839 

3840def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3841 """ 

3842 Generate Gaussian noise centered around 128. 

3843 

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

3845 (width, height). 

3846 :param sigma: Standard deviation of noise. 

3847 """ 

3848 return Image()._new(core.effect_noise(size, sigma)) 

3849 

3850 

3851def linear_gradient(mode: str) -> Image: 

3852 """ 

3853 Generate 256x256 linear gradient from black to white, top to bottom. 

3854 

3855 :param mode: Input mode. 

3856 """ 

3857 return Image()._new(core.linear_gradient(mode)) 

3858 

3859 

3860def radial_gradient(mode: str) -> Image: 

3861 """ 

3862 Generate 256x256 radial gradient from black to white, centre to edge. 

3863 

3864 :param mode: Input mode. 

3865 """ 

3866 return Image()._new(core.radial_gradient(mode)) 

3867 

3868 

3869# -------------------------------------------------------------------- 

3870# Resources 

3871 

3872 

3873def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

3874 env_dict = env if env is not None else os.environ 

3875 

3876 for var_name, setter in [ 

3877 ("PILLOW_ALIGNMENT", core.set_alignment), 

3878 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

3879 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

3880 ]: 

3881 if var_name not in env_dict: 

3882 continue 

3883 

3884 var = env_dict[var_name].lower() 

3885 

3886 units = 1 

3887 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

3888 if var.endswith(postfix): 

3889 units = mul 

3890 var = var[: -len(postfix)] 

3891 

3892 try: 

3893 var_int = int(var) * units 

3894 except ValueError: 

3895 warnings.warn(f"{var_name} is not int") 

3896 continue 

3897 

3898 try: 

3899 setter(var_int) 

3900 except ValueError as e: 

3901 warnings.warn(f"{var_name}: {e}") 

3902 

3903 

3904_apply_env_variables() 

3905atexit.register(core.clear_cache) 

3906 

3907 

3908if TYPE_CHECKING: 

3909 _ExifBase = MutableMapping[int, Any] 

3910else: 

3911 _ExifBase = MutableMapping 

3912 

3913 

3914class Exif(_ExifBase): 

3915 """ 

3916 This class provides read and write access to EXIF image data:: 

3917 

3918 from PIL import Image 

3919 im = Image.open("exif.png") 

3920 exif = im.getexif() # Returns an instance of this class 

3921 

3922 Information can be read and written, iterated over or deleted:: 

3923 

3924 print(exif[274]) # 1 

3925 exif[274] = 2 

3926 for k, v in exif.items(): 

3927 print("Tag", k, "Value", v) # Tag 274 Value 2 

3928 del exif[274] 

3929 

3930 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

3931 returns a dictionary:: 

3932 

3933 from PIL import ExifTags 

3934 im = Image.open("exif_gps.jpg") 

3935 exif = im.getexif() 

3936 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

3937 print(gps_ifd) 

3938 

3939 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

3940 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

3941 

3942 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

3943 

3944 print(exif[ExifTags.Base.Software]) # PIL 

3945 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

3946 """ 

3947 

3948 endian: str | None = None 

3949 bigtiff = False 

3950 _loaded = False 

3951 

3952 def __init__(self) -> None: 

3953 self._data: dict[int, Any] = {} 

3954 self._hidden_data: dict[int, Any] = {} 

3955 self._ifds: dict[int, dict[int, Any]] = {} 

3956 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

3957 self._loaded_exif: bytes | None = None 

3958 

3959 def _fixup(self, value: Any) -> Any: 

3960 try: 

3961 if len(value) == 1 and isinstance(value, tuple): 

3962 return value[0] 

3963 except Exception: 

3964 pass 

3965 return value 

3966 

3967 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

3968 # Helper function 

3969 # returns a dict with any single item tuples/lists as individual values 

3970 return {k: self._fixup(v) for k, v in src_dict.items()} 

3971 

3972 def _get_ifd_dict( 

3973 self, offset: int, group: int | None = None 

3974 ) -> dict[int, Any] | None: 

3975 try: 

3976 # an offset pointer to the location of the nested embedded IFD. 

3977 # It should be a long, but may be corrupted. 

3978 self.fp.seek(offset) 

3979 except (KeyError, TypeError): 

3980 return None 

3981 else: 

3982 from . import TiffImagePlugin 

3983 

3984 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

3985 info.load(self.fp) 

3986 return self._fixup_dict(dict(info)) 

3987 

3988 def _get_head(self) -> bytes: 

3989 version = b"\x2b" if self.bigtiff else b"\x2a" 

3990 if self.endian == "<": 

3991 head = b"II" + version + b"\x00" + o32le(8) 

3992 else: 

3993 head = b"MM\x00" + version + o32be(8) 

3994 if self.bigtiff: 

3995 head += o32le(8) if self.endian == "<" else o32be(8) 

3996 head += b"\x00\x00\x00\x00" 

3997 return head 

3998 

3999 def load(self, data: bytes) -> None: 

4000 # Extract EXIF information. This is highly experimental, 

4001 # and is likely to be replaced with something better in a future 

4002 # version. 

4003 

4004 # The EXIF record consists of a TIFF file embedded in a JPEG 

4005 # application marker (!). 

4006 if data == self._loaded_exif: 

4007 return 

4008 self._loaded_exif = data 

4009 self._data.clear() 

4010 self._hidden_data.clear() 

4011 self._ifds.clear() 

4012 while data and data.startswith(b"Exif\x00\x00"): 

4013 data = data[6:] 

4014 if not data: 

4015 self._info = None 

4016 return 

4017 

4018 self.fp: IO[bytes] = io.BytesIO(data) 

4019 self.head = self.fp.read(8) 

4020 # process dictionary 

4021 from . import TiffImagePlugin 

4022 

4023 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4024 self.endian = self._info._endian 

4025 self.fp.seek(self._info.next) 

4026 self._info.load(self.fp) 

4027 

4028 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4029 self._loaded_exif = None 

4030 self._data.clear() 

4031 self._hidden_data.clear() 

4032 self._ifds.clear() 

4033 

4034 # process dictionary 

4035 from . import TiffImagePlugin 

4036 

4037 self.fp = fp 

4038 if offset is not None: 

4039 self.head = self._get_head() 

4040 else: 

4041 self.head = self.fp.read(8) 

4042 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4043 if self.endian is None: 

4044 self.endian = self._info._endian 

4045 if offset is None: 

4046 offset = self._info.next 

4047 self.fp.tell() 

4048 self.fp.seek(offset) 

4049 self._info.load(self.fp) 

4050 

4051 def _get_merged_dict(self) -> dict[int, Any]: 

4052 merged_dict = dict(self) 

4053 

4054 # get EXIF extension 

4055 if ExifTags.IFD.Exif in self: 

4056 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4057 if ifd: 

4058 merged_dict.update(ifd) 

4059 

4060 # GPS 

4061 if ExifTags.IFD.GPSInfo in self: 

4062 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4063 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4064 ) 

4065 

4066 return merged_dict 

4067 

4068 def tobytes(self, offset: int = 8) -> bytes: 

4069 from . import TiffImagePlugin 

4070 

4071 head = self._get_head() 

4072 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4073 for tag, ifd_dict in self._ifds.items(): 

4074 if tag not in self: 

4075 ifd[tag] = ifd_dict 

4076 for tag, value in self.items(): 

4077 if tag in [ 

4078 ExifTags.IFD.Exif, 

4079 ExifTags.IFD.GPSInfo, 

4080 ] and not isinstance(value, dict): 

4081 value = self.get_ifd(tag) 

4082 if ( 

4083 tag == ExifTags.IFD.Exif 

4084 and ExifTags.IFD.Interop in value 

4085 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4086 ): 

4087 value = value.copy() 

4088 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4089 ifd[tag] = value 

4090 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4091 

4092 def get_ifd(self, tag: int) -> dict[int, Any]: 

4093 if tag not in self._ifds: 

4094 if tag == ExifTags.IFD.IFD1: 

4095 if self._info is not None and self._info.next != 0: 

4096 ifd = self._get_ifd_dict(self._info.next) 

4097 if ifd is not None: 

4098 self._ifds[tag] = ifd 

4099 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4100 offset = self._hidden_data.get(tag, self.get(tag)) 

4101 if offset is not None: 

4102 ifd = self._get_ifd_dict(offset, tag) 

4103 if ifd is not None: 

4104 self._ifds[tag] = ifd 

4105 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4106 if ExifTags.IFD.Exif not in self._ifds: 

4107 self.get_ifd(ExifTags.IFD.Exif) 

4108 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4109 if tag == ExifTags.IFD.MakerNote: 

4110 from .TiffImagePlugin import ImageFileDirectory_v2 

4111 

4112 if tag_data.startswith(b"FUJIFILM"): 

4113 ifd_offset = i32le(tag_data, 8) 

4114 ifd_data = tag_data[ifd_offset:] 

4115 

4116 makernote = {} 

4117 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4118 ifd_tag, typ, count, data = struct.unpack( 

4119 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4120 ) 

4121 try: 

4122 ( 

4123 unit_size, 

4124 handler, 

4125 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4126 except KeyError: 

4127 continue 

4128 size = count * unit_size 

4129 if size > 4: 

4130 (offset,) = struct.unpack("<L", data) 

4131 data = ifd_data[offset - 12 : offset + size - 12] 

4132 else: 

4133 data = data[:size] 

4134 

4135 if len(data) != size: 

4136 warnings.warn( 

4137 "Possibly corrupt EXIF MakerNote data. " 

4138 f"Expecting to read {size} bytes but only got " 

4139 f"{len(data)}. Skipping tag {ifd_tag}" 

4140 ) 

4141 continue 

4142 

4143 if not data: 

4144 continue 

4145 

4146 makernote[ifd_tag] = handler( 

4147 ImageFileDirectory_v2(), data, False 

4148 ) 

4149 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4150 elif self.get(0x010F) == "Nintendo": 

4151 makernote = {} 

4152 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4153 ifd_tag, typ, count, data = struct.unpack( 

4154 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4155 ) 

4156 if ifd_tag == 0x1101: 

4157 # CameraInfo 

4158 (offset,) = struct.unpack(">L", data) 

4159 self.fp.seek(offset) 

4160 

4161 camerainfo: dict[str, int | bytes] = { 

4162 "ModelID": self.fp.read(4) 

4163 } 

4164 

4165 self.fp.read(4) 

4166 # Seconds since 2000 

4167 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4168 

4169 self.fp.read(4) 

4170 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4171 

4172 self.fp.read(12) 

4173 parallax = self.fp.read(4) 

4174 handler = ImageFileDirectory_v2._load_dispatch[ 

4175 TiffTags.FLOAT 

4176 ][1] 

4177 camerainfo["Parallax"] = handler( 

4178 ImageFileDirectory_v2(), parallax, False 

4179 )[0] 

4180 

4181 self.fp.read(4) 

4182 camerainfo["Category"] = self.fp.read(2) 

4183 

4184 makernote = {0x1101: camerainfo} 

4185 self._ifds[tag] = makernote 

4186 else: 

4187 # Interop 

4188 ifd = self._get_ifd_dict(tag_data, tag) 

4189 if ifd is not None: 

4190 self._ifds[tag] = ifd 

4191 ifd = self._ifds.setdefault(tag, {}) 

4192 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4193 ifd = { 

4194 k: v 

4195 for (k, v) in ifd.items() 

4196 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4197 } 

4198 return ifd 

4199 

4200 def hide_offsets(self) -> None: 

4201 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4202 if tag in self: 

4203 self._hidden_data[tag] = self[tag] 

4204 del self[tag] 

4205 

4206 def __str__(self) -> str: 

4207 if self._info is not None: 

4208 # Load all keys into self._data 

4209 for tag in self._info: 

4210 self[tag] 

4211 

4212 return str(self._data) 

4213 

4214 def __len__(self) -> int: 

4215 keys = set(self._data) 

4216 if self._info is not None: 

4217 keys.update(self._info) 

4218 return len(keys) 

4219 

4220 def __getitem__(self, tag: int) -> Any: 

4221 if self._info is not None and tag not in self._data and tag in self._info: 

4222 self._data[tag] = self._fixup(self._info[tag]) 

4223 del self._info[tag] 

4224 return self._data[tag] 

4225 

4226 def __contains__(self, tag: object) -> bool: 

4227 return tag in self._data or (self._info is not None and tag in self._info) 

4228 

4229 def __setitem__(self, tag: int, value: Any) -> None: 

4230 if self._info is not None and tag in self._info: 

4231 del self._info[tag] 

4232 self._data[tag] = value 

4233 

4234 def __delitem__(self, tag: int) -> None: 

4235 if self._info is not None and tag in self._info: 

4236 del self._info[tag] 

4237 else: 

4238 del self._data[tag] 

4239 if tag in self._ifds: 

4240 del self._ifds[tag] 

4241 

4242 def __iter__(self) -> Iterator[int]: 

4243 keys = set(self._data) 

4244 if self._info is not None: 

4245 keys.update(self._info) 

4246 return iter(keys)