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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1715 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 core = DeferredError.new(ImportError("The _imaging C module is not installed.")) 

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

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

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

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

111 # possible. 

112 warnings.warn( 

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

114 RuntimeWarning, 

115 ) 

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

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

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

119 # see docs/porting.rst 

120 raise 

121 

122 

123# 

124# Constants 

125 

126 

127# transpose 

128class Transpose(IntEnum): 

129 FLIP_LEFT_RIGHT = 0 

130 FLIP_TOP_BOTTOM = 1 

131 ROTATE_90 = 2 

132 ROTATE_180 = 3 

133 ROTATE_270 = 4 

134 TRANSPOSE = 5 

135 TRANSVERSE = 6 

136 

137 

138# transforms (also defined in Imaging.h) 

139class Transform(IntEnum): 

140 AFFINE = 0 

141 EXTENT = 1 

142 PERSPECTIVE = 2 

143 QUAD = 3 

144 MESH = 4 

145 

146 

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

148class Resampling(IntEnum): 

149 NEAREST = 0 

150 BOX = 4 

151 BILINEAR = 2 

152 HAMMING = 5 

153 BICUBIC = 3 

154 LANCZOS = 1 

155 

156 

157_filters_support = { 

158 Resampling.BOX: 0.5, 

159 Resampling.BILINEAR: 1.0, 

160 Resampling.HAMMING: 1.0, 

161 Resampling.BICUBIC: 2.0, 

162 Resampling.LANCZOS: 3.0, 

163} 

164 

165 

166# dithers 

167class Dither(IntEnum): 

168 NONE = 0 

169 ORDERED = 1 # Not yet implemented 

170 RASTERIZE = 2 # Not yet implemented 

171 FLOYDSTEINBERG = 3 # default 

172 

173 

174# palettes/quantizers 

175class Palette(IntEnum): 

176 WEB = 0 

177 ADAPTIVE = 1 

178 

179 

180class Quantize(IntEnum): 

181 MEDIANCUT = 0 

182 MAXCOVERAGE = 1 

183 FASTOCTREE = 2 

184 LIBIMAGEQUANT = 3 

185 

186 

187module = sys.modules[__name__] 

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

189 for item in enum: 

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

191 

192 

193if hasattr(core, "DEFAULT_STRATEGY"): 

194 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

195 FILTERED = core.FILTERED 

196 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

197 RLE = core.RLE 

198 FIXED = core.FIXED 

199 

200 

201# -------------------------------------------------------------------- 

202# Registries 

203 

204TYPE_CHECKING = False 

205if TYPE_CHECKING: 

206 import mmap 

207 from xml.etree.ElementTree import Element 

208 

209 from IPython.lib.pretty import PrettyPrinter 

210 

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

212 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath 

213ID: list[str] = [] 

214OPEN: dict[ 

215 str, 

216 tuple[ 

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

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

219 ], 

220] = {} 

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

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

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

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

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

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

227 

228# -------------------------------------------------------------------- 

229# Modes 

230 

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

232 

233 

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

235 m = ImageMode.getmode(im.mode) 

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

237 extra = len(m.bands) 

238 if extra != 1: 

239 shape += (extra,) 

240 return shape, m.typestr 

241 

242 

243MODES = [ 

244 "1", 

245 "CMYK", 

246 "F", 

247 "HSV", 

248 "I", 

249 "I;16", 

250 "I;16B", 

251 "I;16L", 

252 "I;16N", 

253 "L", 

254 "LA", 

255 "La", 

256 "LAB", 

257 "P", 

258 "PA", 

259 "RGB", 

260 "RGBA", 

261 "RGBa", 

262 "RGBX", 

263 "YCbCr", 

264] 

265 

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

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

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

269 

270 

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

272 """ 

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

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

275 contain color data. 

276 

277 :param mode: Input mode. 

278 :returns: "L" or "RGB". 

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

280 """ 

281 return ImageMode.getmode(mode).basemode 

282 

283 

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

285 """ 

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

287 single-layer mode suitable for storing individual bands. 

288 

289 :param mode: Input mode. 

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

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

292 """ 

293 return ImageMode.getmode(mode).basetype 

294 

295 

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

297 """ 

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

299 a tuple containing the names of individual bands (use 

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

301 individual band. 

302 

303 :param mode: Input mode. 

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

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

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

307 """ 

308 return ImageMode.getmode(mode).bands 

309 

310 

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

312 """ 

313 Gets the number of individual bands for this mode. 

314 

315 :param mode: Input mode. 

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

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

318 """ 

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

320 

321 

322# -------------------------------------------------------------------- 

323# Helpers 

324 

325_initialized = 0 

326 

327 

328def preinit() -> None: 

329 """ 

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

331 

332 It is called when opening or saving images. 

333 """ 

334 

335 global _initialized 

336 if _initialized >= 1: 

337 return 

338 

339 try: 

340 from . import BmpImagePlugin 

341 

342 assert BmpImagePlugin 

343 except ImportError: 

344 pass 

345 try: 

346 from . import GifImagePlugin 

347 

348 assert GifImagePlugin 

349 except ImportError: 

350 pass 

351 try: 

352 from . import JpegImagePlugin 

353 

354 assert JpegImagePlugin 

355 except ImportError: 

356 pass 

357 try: 

358 from . import PpmImagePlugin 

359 

360 assert PpmImagePlugin 

361 except ImportError: 

362 pass 

363 try: 

364 from . import PngImagePlugin 

365 

366 assert PngImagePlugin 

367 except ImportError: 

368 pass 

369 

370 _initialized = 1 

371 

372 

373def init() -> bool: 

374 """ 

375 Explicitly initializes the Python Imaging Library. This function 

376 loads all available file format drivers. 

377 

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

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

380 """ 

381 

382 global _initialized 

383 if _initialized >= 2: 

384 return False 

385 

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

387 for plugin in _plugins: 

388 try: 

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

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

391 except ImportError as e: 

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

393 

394 if OPEN or SAVE: 

395 _initialized = 2 

396 return True 

397 return False 

398 

399 

400# -------------------------------------------------------------------- 

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

402 

403 

404def _getdecoder( 

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

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

407 # tweak arguments 

408 if args is None: 

409 args = () 

410 elif not isinstance(args, tuple): 

411 args = (args,) 

412 

413 try: 

414 decoder = DECODERS[decoder_name] 

415 except KeyError: 

416 pass 

417 else: 

418 return decoder(mode, *args + extra) 

419 

420 try: 

421 # get decoder 

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

423 except AttributeError as e: 

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

425 raise OSError(msg) from e 

426 return decoder(mode, *args + extra) 

427 

428 

429def _getencoder( 

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

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

432 # tweak arguments 

433 if args is None: 

434 args = () 

435 elif not isinstance(args, tuple): 

436 args = (args,) 

437 

438 try: 

439 encoder = ENCODERS[encoder_name] 

440 except KeyError: 

441 pass 

442 else: 

443 return encoder(mode, *args + extra) 

444 

445 try: 

446 # get encoder 

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

448 except AttributeError as e: 

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

450 raise OSError(msg) from e 

451 return encoder(mode, *args + extra) 

452 

453 

454# -------------------------------------------------------------------- 

455# Simple expression analyzer 

456 

457 

458class ImagePointTransform: 

459 """ 

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

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

462 ``scale`` and ``offset`` is added. 

463 """ 

464 

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

466 self.scale = scale 

467 self.offset = offset 

468 

469 def __neg__(self) -> ImagePointTransform: 

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

471 

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

473 if isinstance(other, ImagePointTransform): 

474 return ImagePointTransform( 

475 self.scale + other.scale, self.offset + other.offset 

476 ) 

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

478 

479 __radd__ = __add__ 

480 

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

482 return self + -other 

483 

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

485 return other + -self 

486 

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

488 if isinstance(other, ImagePointTransform): 

489 return NotImplemented 

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

491 

492 __rmul__ = __mul__ 

493 

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

495 if isinstance(other, ImagePointTransform): 

496 return NotImplemented 

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

498 

499 

500def _getscaleoffset( 

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

502) -> tuple[float, float]: 

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

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

505 

506 

507# -------------------------------------------------------------------- 

508# Implementation wrapper 

509 

510 

511class SupportsGetData(Protocol): 

512 def getdata( 

513 self, 

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

515 

516 

517class Image: 

518 """ 

519 This class represents an image object. To create 

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

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

522 directly. 

523 

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

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

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

527 """ 

528 

529 format: str | None = None 

530 format_description: str | None = None 

531 _close_exclusive_fp_after_loading = True 

532 

533 def __init__(self) -> None: 

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

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

536 self._mode = "" 

537 self._size = (0, 0) 

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

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

540 self.readonly = 0 

541 self._exif: Exif | None = None 

542 

543 @property 

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

545 if isinstance(self._im, DeferredError): 

546 raise self._im.ex 

547 assert self._im is not None 

548 return self._im 

549 

550 @im.setter 

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

552 self._im = im 

553 

554 @property 

555 def width(self) -> int: 

556 return self.size[0] 

557 

558 @property 

559 def height(self) -> int: 

560 return self.size[1] 

561 

562 @property 

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

564 return self._size 

565 

566 @property 

567 def mode(self) -> str: 

568 return self._mode 

569 

570 @property 

571 def readonly(self) -> int: 

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

573 

574 @readonly.setter 

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

576 self._readonly = readonly 

577 

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

579 new = Image() 

580 new.im = im 

581 new._mode = im.mode 

582 new._size = im.size 

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

584 if self.palette: 

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

586 else: 

587 from . import ImagePalette 

588 

589 new.palette = ImagePalette.ImagePalette() 

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

591 return new 

592 

593 # Context manager support 

594 def __enter__(self): 

595 return self 

596 

597 def __exit__(self, *args): 

598 from . import ImageFile 

599 

600 if isinstance(self, ImageFile.ImageFile): 

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

602 self._close_fp() 

603 self.fp = None 

604 

605 def close(self) -> None: 

606 """ 

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

608 The image data will be unusable afterward. 

609 

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

611 have not had their file read and closed by the 

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

613 more information. 

614 """ 

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

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

617 self.map.close() 

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

619 

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

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

622 # object is gone. 

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

624 

625 def _copy(self) -> None: 

626 self.load() 

627 self.im = self.im.copy() 

628 self.readonly = 0 

629 

630 def _ensure_mutable(self) -> None: 

631 if self.readonly: 

632 self._copy() 

633 else: 

634 self.load() 

635 

636 def _dump( 

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

638 ) -> str: 

639 suffix = "" 

640 if format: 

641 suffix = f".{format}" 

642 

643 if not file: 

644 f, filename = tempfile.mkstemp(suffix) 

645 os.close(f) 

646 else: 

647 filename = file 

648 if not filename.endswith(suffix): 

649 filename = filename + suffix 

650 

651 self.load() 

652 

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

654 self.im.save_ppm(filename) 

655 else: 

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

657 

658 return filename 

659 

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

661 if self.__class__ is not other.__class__: 

662 return False 

663 assert isinstance(other, Image) 

664 return ( 

665 self.mode == other.mode 

666 and self.size == other.size 

667 and self.info == other.info 

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

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

670 ) 

671 

672 def __repr__(self) -> str: 

673 return ( 

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

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

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

677 ) 

678 

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

680 """IPython plain text display support""" 

681 

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

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

684 p.text( 

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

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

687 ) 

688 

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

690 """Helper function for iPython display hook. 

691 

692 :param image_format: Image format. 

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

694 """ 

695 b = io.BytesIO() 

696 try: 

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

698 except Exception: 

699 return None 

700 return b.getvalue() 

701 

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

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

704 

705 :returns: PNG version of the image as bytes 

706 """ 

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

708 

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

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

711 

712 :returns: JPEG version of the image as bytes 

713 """ 

714 return self._repr_image("JPEG") 

715 

716 @property 

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

718 # numpy array interface support 

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

720 if self.mode == "1": 

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

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

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

724 else: 

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

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

727 return new 

728 

729 def __arrow_c_schema__(self) -> object: 

730 self.load() 

731 return self.im.__arrow_c_schema__() 

732 

733 def __arrow_c_array__( 

734 self, requested_schema: object | None = None 

735 ) -> tuple[object, object]: 

736 self.load() 

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

738 

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

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

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

742 

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

744 Image.__init__(self) 

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

746 self.info = info 

747 self._mode = mode 

748 self._size = size 

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

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

751 self.putpalette(palette) 

752 self.frombytes(data) 

753 

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

755 """ 

756 Return image as a bytes object. 

757 

758 .. warning:: 

759 

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

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

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

763 

764 :param encoder_name: What encoder to use. 

765 

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

767 To see how this packs pixel data into the returned 

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

769 

770 A list of C encoders can be seen under codecs 

771 section of the function array in 

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

773 within the relevant plugins. 

774 :param args: Extra arguments to the encoder. 

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

776 """ 

777 

778 encoder_args: Any = args 

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

780 # may pass tuple instead of argument list 

781 encoder_args = encoder_args[0] 

782 

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

784 encoder_args = self.mode 

785 

786 self.load() 

787 

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

789 return b"" 

790 

791 # unpack data 

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

793 e.setimage(self.im) 

794 

795 from . import ImageFile 

796 

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

798 

799 output = [] 

800 while True: 

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

802 output.append(data) 

803 if errcode: 

804 break 

805 if errcode < 0: 

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

807 raise RuntimeError(msg) 

808 

809 return b"".join(output) 

810 

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

812 """ 

813 Returns the image converted to an X11 bitmap. 

814 

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

816 

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

818 :returns: A string containing an X11 bitmap. 

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

820 """ 

821 

822 self.load() 

823 if self.mode != "1": 

824 msg = "not a bitmap" 

825 raise ValueError(msg) 

826 data = self.tobytes("xbm") 

827 return b"".join( 

828 [ 

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

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

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

832 data, 

833 b"};", 

834 ] 

835 ) 

836 

837 def frombytes( 

838 self, 

839 data: bytes | bytearray | SupportsArrayInterface, 

840 decoder_name: str = "raw", 

841 *args: Any, 

842 ) -> None: 

843 """ 

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

845 

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

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

848 """ 

849 

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

851 return 

852 

853 decoder_args: Any = args 

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

855 # may pass tuple instead of argument list 

856 decoder_args = decoder_args[0] 

857 

858 # default format 

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

860 decoder_args = self.mode 

861 

862 # unpack data 

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

864 d.setimage(self.im) 

865 s = d.decode(data) 

866 

867 if s[0] >= 0: 

868 msg = "not enough image data" 

869 raise ValueError(msg) 

870 if s[1] != 0: 

871 msg = "cannot decode image data" 

872 raise ValueError(msg) 

873 

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

875 """ 

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

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

878 Image class automatically loads an opened image when it is 

879 accessed for the first time. 

880 

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

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

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

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

885 

886 :returns: An image access object. 

887 :rtype: :py:class:`.PixelAccess` 

888 """ 

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

890 # realize palette 

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

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

893 self.palette.dirty = 0 

894 self.palette.rawmode = None 

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

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

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

898 else: 

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

900 self.palette.mode = "RGBA" 

901 else: 

902 self.palette.palette = self.im.getpalette( 

903 self.palette.mode, self.palette.mode 

904 ) 

905 

906 if self._im is not None: 

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

908 return None 

909 

910 def verify(self) -> None: 

911 """ 

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

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

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

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

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

917 file. 

918 """ 

919 pass 

920 

921 def convert( 

922 self, 

923 mode: str | None = None, 

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

925 dither: Dither | None = None, 

926 palette: Palette = Palette.WEB, 

927 colors: int = 256, 

928 ) -> Image: 

929 """ 

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

931 method translates pixels through the palette. If mode is 

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

933 and the palette can be represented without a palette. 

934 

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

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

937 

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

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

940 

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

942 

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

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

945 dither to approximate the original image luminosity levels. If 

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

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

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

949 

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

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

952 and ``dither`` and ``palette`` are ignored. 

953 

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

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

956 

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

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

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

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

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

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

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

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

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

966 :data:`Palette.ADAPTIVE`. 

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

968 palette. Defaults to 256. 

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

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

971 """ 

972 

973 self.load() 

974 

975 has_transparency = "transparency" in self.info 

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

977 # determine default mode 

978 if self.palette: 

979 mode = self.palette.mode 

980 else: 

981 mode = "RGB" 

982 if mode == "RGB" and has_transparency: 

983 mode = "RGBA" 

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

985 return self.copy() 

986 

987 if matrix: 

988 # matrix conversion 

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

990 msg = "illegal conversion" 

991 raise ValueError(msg) 

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

993 new_im = self._new(im) 

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

995 transparency = new_im.info["transparency"] 

996 

997 def convert_transparency( 

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

999 ) -> int: 

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

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

1002 

1003 if mode == "L": 

1004 transparency = convert_transparency(matrix, transparency) 

1005 elif len(mode) == 3: 

1006 transparency = tuple( 

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

1008 for i in range(len(transparency)) 

1009 ) 

1010 new_im.info["transparency"] = transparency 

1011 return new_im 

1012 

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

1014 return self.quantize(colors) 

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 == "P" 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 _expand(self, xmargin: int, ymargin: int | None = None) -> Image: 

1341 if ymargin is None: 

1342 ymargin = xmargin 

1343 self.load() 

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

1345 

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

1347 """ 

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

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

1350 

1351 :param filter: Filter kernel. 

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

1353 

1354 from . import ImageFilter 

1355 

1356 self.load() 

1357 

1358 if callable(filter): 

1359 filter = filter() 

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

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

1362 raise TypeError(msg) 

1363 

1364 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1367 

1368 ims = [ 

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

1370 ] 

1371 return merge(self.mode, ims) 

1372 

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

1374 """ 

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

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

1377 

1378 :returns: A tuple containing band names. 

1379 :rtype: tuple 

1380 """ 

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

1382 

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

1384 """ 

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

1386 image. 

1387 

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

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

1390 Otherwise, trim pixels when all channels are zero. 

1391 Keyword-only argument. 

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

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

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

1395 method returns None. 

1396 

1397 """ 

1398 

1399 self.load() 

1400 return self.im.getbbox(alpha_only) 

1401 

1402 def getcolors( 

1403 self, maxcolors: int = 256 

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

1405 """ 

1406 Returns a list of colors used in this image. 

1407 

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

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

1410 return the index of the color in the palette. 

1411 

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

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

1414 256 colors. 

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

1416 """ 

1417 

1418 self.load() 

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

1420 h = self.im.histogram() 

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

1422 if len(out) > maxcolors: 

1423 return None 

1424 return out 

1425 return self.im.getcolors(maxcolors) 

1426 

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

1428 """ 

1429 Returns the contents of this image as a sequence object 

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

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

1432 line zero, and so on. 

1433 

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

1435 internal PIL data type, which only supports certain sequence 

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

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

1438 

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

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

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

1442 :returns: A sequence-like object. 

1443 """ 

1444 

1445 self.load() 

1446 if band is not None: 

1447 return self.im.getband(band) 

1448 return self.im # could be abused 

1449 

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

1451 """ 

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

1453 the image. 

1454 

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

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

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

1458 """ 

1459 

1460 self.load() 

1461 if self.im.bands > 1: 

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

1463 return self.im.getextrema() 

1464 

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

1466 """ 

1467 Returns a dictionary containing the XMP tags. 

1468 Requires defusedxml to be installed. 

1469 

1470 :returns: XMP tags in a dictionary. 

1471 """ 

1472 

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

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

1475 

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

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

1478 children = list(element) 

1479 if children: 

1480 for child in children: 

1481 name = get_name(child.tag) 

1482 child_value = get_value(child) 

1483 if name in value: 

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

1485 value[name] = [value[name]] 

1486 value[name].append(child_value) 

1487 else: 

1488 value[name] = child_value 

1489 elif value: 

1490 if element.text: 

1491 value["text"] = element.text 

1492 else: 

1493 return element.text 

1494 return value 

1495 

1496 if ElementTree is None: 

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

1498 return {} 

1499 if "xmp" not in self.info: 

1500 return {} 

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

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

1503 

1504 def getexif(self) -> Exif: 

1505 """ 

1506 Gets EXIF data from the image. 

1507 

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

1509 """ 

1510 if self._exif is None: 

1511 self._exif = Exif() 

1512 elif self._exif._loaded: 

1513 return self._exif 

1514 self._exif._loaded = True 

1515 

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

1517 if exif_info is None: 

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

1519 exif_info = bytes.fromhex( 

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

1521 ) 

1522 elif hasattr(self, "tag_v2"): 

1523 self._exif.bigtiff = self.tag_v2._bigtiff 

1524 self._exif.endian = self.tag_v2._endian 

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

1526 if exif_info is not None: 

1527 self._exif.load(exif_info) 

1528 

1529 # XMP tags 

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

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

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

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

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

1535 if xmp_tags: 

1536 match = re.search(pattern, xmp_tags) 

1537 if match: 

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

1539 

1540 return self._exif 

1541 

1542 def _reload_exif(self) -> None: 

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

1544 return 

1545 self._exif._loaded = False 

1546 self.getexif() 

1547 

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

1549 from . import ImageFile 

1550 

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

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

1553 

1554 def getim(self) -> CapsuleType: 

1555 """ 

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

1557 

1558 :returns: A capsule object. 

1559 """ 

1560 

1561 self.load() 

1562 return self.im.ptr 

1563 

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

1565 """ 

1566 Returns the image palette as a list. 

1567 

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

1569 return the palette in its current mode. 

1570 

1571 .. versionadded:: 9.1.0 

1572 

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

1574 image has no palette. 

1575 """ 

1576 

1577 self.load() 

1578 try: 

1579 mode = self.im.getpalettemode() 

1580 except ValueError: 

1581 return None # no palette 

1582 if rawmode is None: 

1583 rawmode = mode 

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

1585 

1586 @property 

1587 def has_transparency_data(self) -> bool: 

1588 """ 

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

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

1591 in the info dictionary. 

1592 

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

1594 within are opaque. 

1595 

1596 :returns: A boolean. 

1597 """ 

1598 if ( 

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

1600 or "transparency" in self.info 

1601 ): 

1602 return True 

1603 if self.mode == "P": 

1604 assert self.palette is not None 

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

1606 return False 

1607 

1608 def apply_transparency(self) -> None: 

1609 """ 

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

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

1612 Otherwise, the image is unchanged. 

1613 """ 

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

1615 return 

1616 

1617 from . import ImagePalette 

1618 

1619 palette = self.getpalette("RGBA") 

1620 assert palette is not None 

1621 transparency = self.info["transparency"] 

1622 if isinstance(transparency, bytes): 

1623 for i, alpha in enumerate(transparency): 

1624 palette[i * 4 + 3] = alpha 

1625 else: 

1626 palette[transparency * 4 + 3] = 0 

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

1628 self.palette.dirty = 1 

1629 

1630 del self.info["transparency"] 

1631 

1632 def getpixel( 

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

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

1635 """ 

1636 Returns the pixel value at a given position. 

1637 

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

1639 :ref:`coordinate-system`. 

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

1641 this method returns a tuple. 

1642 """ 

1643 

1644 self.load() 

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

1646 

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

1648 """ 

1649 Get projection to x and y axes 

1650 

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

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

1653 """ 

1654 

1655 self.load() 

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

1657 return list(x), list(y) 

1658 

1659 def histogram( 

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

1661 ) -> list[int]: 

1662 """ 

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

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

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

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

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

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

1669 

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

1671 by this method. 

1672 

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

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

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

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

1677 

1678 :param mask: An optional mask. 

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

1680 :returns: A list containing pixel counts. 

1681 """ 

1682 self.load() 

1683 if mask: 

1684 mask.load() 

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

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

1687 return self.im.histogram( 

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

1689 ) 

1690 return self.im.histogram() 

1691 

1692 def entropy( 

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

1694 ) -> float: 

1695 """ 

1696 Calculates and returns the entropy for the image. 

1697 

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

1699 image by this method. 

1700 

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

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

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

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

1705 

1706 :param mask: An optional mask. 

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

1708 :returns: A float value representing the image entropy 

1709 """ 

1710 self.load() 

1711 if mask: 

1712 mask.load() 

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

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

1715 return self.im.entropy( 

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

1717 ) 

1718 return self.im.entropy() 

1719 

1720 def paste( 

1721 self, 

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

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

1724 mask: Image | None = None, 

1725 ) -> None: 

1726 """ 

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

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

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

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

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

1732 

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

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

1735 details). 

1736 

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

1738 containing pixel values. The method then fills the region 

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

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

1741 :ref:`colors` for more information. 

1742 

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

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

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

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

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

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

1749 channels if they have them. 

1750 

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

1752 combine images with respect to their alpha channels. 

1753 

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

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

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

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

1758 upper left corner. 

1759 

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

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

1762 is interpreted as a mask image. 

1763 :param mask: An optional mask image. 

1764 """ 

1765 

1766 if isinstance(box, Image): 

1767 if mask is not None: 

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

1769 raise ValueError(msg) 

1770 # abbreviated paste(im, mask) syntax 

1771 mask = box 

1772 box = None 

1773 

1774 if box is None: 

1775 box = (0, 0) 

1776 

1777 if len(box) == 2: 

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

1779 if isinstance(im, Image): 

1780 size = im.size 

1781 elif isinstance(mask, Image): 

1782 size = mask.size 

1783 else: 

1784 # FIXME: use self.size here? 

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

1786 raise ValueError(msg) 

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

1788 

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

1790 if isinstance(im, str): 

1791 from . import ImageColor 

1792 

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

1794 elif isinstance(im, Image): 

1795 im.load() 

1796 if self.mode != im.mode: 

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

1798 # should use an adapter for this! 

1799 im = im.convert(self.mode) 

1800 source = im.im 

1801 else: 

1802 source = im 

1803 

1804 self._ensure_mutable() 

1805 

1806 if mask: 

1807 mask.load() 

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

1809 else: 

1810 self.im.paste(source, box) 

1811 

1812 def alpha_composite( 

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

1814 ) -> None: 

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

1816 onto this image. 

1817 

1818 :param im: image to composite over this one 

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

1820 left corner in this (destination) image. 

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

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

1823 bottom) for the bounds of the source rectangle 

1824 

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

1826 """ 

1827 

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

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

1830 raise ValueError(msg) 

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

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

1833 raise ValueError(msg) 

1834 

1835 if len(source) == 4: 

1836 overlay_crop_box = tuple(source) 

1837 elif len(source) == 2: 

1838 overlay_crop_box = tuple(source) + im.size 

1839 else: 

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

1841 raise ValueError(msg) 

1842 

1843 if not len(dest) == 2: 

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

1845 raise ValueError(msg) 

1846 if min(source) < 0: 

1847 msg = "Source must be non-negative" 

1848 raise ValueError(msg) 

1849 

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

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

1852 overlay = im 

1853 else: 

1854 overlay = im.crop(overlay_crop_box) 

1855 

1856 # target for the paste 

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

1858 

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

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

1861 background = self 

1862 else: 

1863 background = self.crop(box) 

1864 

1865 result = alpha_composite(background, overlay) 

1866 self.paste(result, box) 

1867 

1868 def point( 

1869 self, 

1870 lut: ( 

1871 Sequence[float] 

1872 | NumpyArray 

1873 | Callable[[int], float] 

1874 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1875 | ImagePointHandler 

1876 ), 

1877 mode: str | None = None, 

1878 ) -> Image: 

1879 """ 

1880 Maps this image through a lookup table or function. 

1881 

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

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

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

1885 single argument. The function is called once for each 

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

1887 all bands of the image. 

1888 

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

1890 object:: 

1891 

1892 class Example(Image.ImagePointHandler): 

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

1894 # Return result 

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

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

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

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

1899 """ 

1900 

1901 self.load() 

1902 

1903 if isinstance(lut, ImagePointHandler): 

1904 return lut.point(self) 

1905 

1906 if callable(lut): 

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

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

1909 # check if the function can be used with point_transform 

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

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

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

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

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

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

1916 else: 

1917 flatLut = lut 

1918 

1919 if self.mode == "F": 

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

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

1922 raise ValueError(msg) 

1923 

1924 if mode != "F": 

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

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

1927 

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

1929 """ 

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

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

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

1933 

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

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

1936 """ 

1937 

1938 self._ensure_mutable() 

1939 

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

1941 # attempt to promote self to a matching alpha mode 

1942 try: 

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

1944 try: 

1945 self.im.setmode(mode) 

1946 except (AttributeError, ValueError) as e: 

1947 # do things the hard way 

1948 im = self.im.convert(mode) 

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

1950 msg = "alpha channel could not be added" 

1951 raise ValueError(msg) from e # sanity check 

1952 self.im = im 

1953 self._mode = self.im.mode 

1954 except KeyError as e: 

1955 msg = "illegal image mode" 

1956 raise ValueError(msg) from e 

1957 

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

1959 band = 1 

1960 else: 

1961 band = 3 

1962 

1963 if isinstance(alpha, Image): 

1964 # alpha layer 

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

1966 msg = "illegal image mode" 

1967 raise ValueError(msg) 

1968 alpha.load() 

1969 if alpha.mode == "1": 

1970 alpha = alpha.convert("L") 

1971 else: 

1972 # constant alpha 

1973 try: 

1974 self.im.fillband(band, alpha) 

1975 except (AttributeError, ValueError): 

1976 # do things the hard way 

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

1978 else: 

1979 return 

1980 

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

1982 

1983 def putdata( 

1984 self, 

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

1986 scale: float = 1.0, 

1987 offset: float = 0.0, 

1988 ) -> None: 

1989 """ 

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

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

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

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

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

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

1996 

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

1998 information about values. 

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

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

2001 """ 

2002 

2003 self._ensure_mutable() 

2004 

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

2006 

2007 def putpalette( 

2008 self, 

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

2010 rawmode: str = "RGB", 

2011 ) -> None: 

2012 """ 

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

2014 or "LA" image. 

2015 

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

2017 integer value for each channel in the raw mode. 

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

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

2020 index in the 256 colors. 

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

2022 containing red, green, blue and alpha values. 

2023 

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

2025 

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

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

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

2029 """ 

2030 from . import ImagePalette 

2031 

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

2033 msg = "illegal image mode" 

2034 raise ValueError(msg) 

2035 if isinstance(data, ImagePalette.ImagePalette): 

2036 if data.rawmode is not None: 

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

2038 else: 

2039 palette = ImagePalette.ImagePalette(palette=data.palette) 

2040 palette.dirty = 1 

2041 else: 

2042 if not isinstance(data, bytes): 

2043 data = bytes(data) 

2044 palette = ImagePalette.raw(rawmode, data) 

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

2046 self.palette = palette 

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

2048 self.load() # install new palette 

2049 

2050 def putpixel( 

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

2052 ) -> None: 

2053 """ 

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

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

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

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

2058 

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

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

2061 module instead. 

2062 

2063 See: 

2064 

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

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

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

2068 

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

2070 :ref:`coordinate-system`. 

2071 :param value: The pixel value. 

2072 """ 

2073 

2074 if self.readonly: 

2075 self._copy() 

2076 self.load() 

2077 

2078 if ( 

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

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

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

2082 ): 

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

2084 if self.mode == "PA": 

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

2086 value = value[:3] 

2087 assert self.palette is not None 

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

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

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

2091 

2092 def remap_palette( 

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

2094 ) -> Image: 

2095 """ 

2096 Rewrites the image to reorder the palette. 

2097 

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

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

2100 is the identity transform. 

2101 :param source_palette: Bytes or None. 

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

2103 

2104 """ 

2105 from . import ImagePalette 

2106 

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

2108 msg = "illegal image mode" 

2109 raise ValueError(msg) 

2110 

2111 bands = 3 

2112 palette_mode = "RGB" 

2113 if source_palette is None: 

2114 if self.mode == "P": 

2115 self.load() 

2116 palette_mode = self.im.getpalettemode() 

2117 if palette_mode == "RGBA": 

2118 bands = 4 

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

2120 else: # L-mode 

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

2122 elif len(source_palette) > 768: 

2123 bands = 4 

2124 palette_mode = "RGBA" 

2125 

2126 palette_bytes = b"" 

2127 new_positions = [0] * 256 

2128 

2129 # pick only the used colors from the palette 

2130 for i, oldPosition in enumerate(dest_map): 

2131 palette_bytes += source_palette[ 

2132 oldPosition * bands : oldPosition * bands + bands 

2133 ] 

2134 new_positions[oldPosition] = i 

2135 

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

2137 

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

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

2140 # from palette 1 to palette 2. New_positions is 

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

2142 # palette 1 with any holes removed. 

2143 

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

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

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

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

2148 # sans palette thus converting the image bytes, then 

2149 # assigning the optimized RGB palette. 

2150 

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

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

2153 

2154 mapping_palette = bytearray(new_positions) 

2155 

2156 m_im = self.copy() 

2157 m_im._mode = "P" 

2158 

2159 m_im.palette = ImagePalette.ImagePalette( 

2160 palette_mode, palette=mapping_palette * bands 

2161 ) 

2162 # possibly set palette dirty, then 

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

2164 # or just force it. 

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

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

2167 

2168 m_im = m_im.convert("L") 

2169 

2170 m_im.putpalette(palette_bytes, palette_mode) 

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

2172 

2173 if "transparency" in self.info: 

2174 try: 

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

2176 except ValueError: 

2177 if "transparency" in m_im.info: 

2178 del m_im.info["transparency"] 

2179 

2180 return m_im 

2181 

2182 def _get_safe_box( 

2183 self, 

2184 size: tuple[int, int], 

2185 resample: Resampling, 

2186 box: tuple[float, float, float, float], 

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

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

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

2190 """ 

2191 filter_support = _filters_support[resample] - 0.5 

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

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

2194 support_x = filter_support * scale_x 

2195 support_y = filter_support * scale_y 

2196 

2197 return ( 

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

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

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

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

2202 ) 

2203 

2204 def resize( 

2205 self, 

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

2207 resample: int | None = None, 

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

2209 reducing_gap: float | None = None, 

2210 ) -> Image: 

2211 """ 

2212 Returns a resized copy of this image. 

2213 

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

2215 (width, height). 

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

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

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

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

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

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

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

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

2224 the source image region to be scaled. 

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

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

2227 :param reducing_gap: Apply optimization by resizing the image 

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

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

2230 Second, resizing using regular resampling. The last step 

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

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

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

2234 the closer the result to the fair resampling. 

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

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

2237 indistinguishable from fair resampling in most cases. 

2238 The default value is None (no optimization). 

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

2240 """ 

2241 

2242 if resample is None: 

2243 resample = Resampling.BICUBIC 

2244 elif resample not in ( 

2245 Resampling.NEAREST, 

2246 Resampling.BILINEAR, 

2247 Resampling.BICUBIC, 

2248 Resampling.LANCZOS, 

2249 Resampling.BOX, 

2250 Resampling.HAMMING, 

2251 ): 

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

2253 

2254 filters = [ 

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

2256 for filter in ( 

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

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

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

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

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

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

2263 ) 

2264 ] 

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

2266 raise ValueError(msg) 

2267 

2268 if reducing_gap is not None and reducing_gap < 1.0: 

2269 msg = "reducing_gap must be 1.0 or greater" 

2270 raise ValueError(msg) 

2271 

2272 if box is None: 

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

2274 

2275 size = tuple(size) 

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

2277 return self.copy() 

2278 

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

2280 resample = Resampling.NEAREST 

2281 

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

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

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

2285 return im.convert(self.mode) 

2286 

2287 self.load() 

2288 

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

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

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

2292 if factor_x > 1 or factor_y > 1: 

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

2294 factor = (factor_x, factor_y) 

2295 self = ( 

2296 self.reduce(factor, box=reduce_box) 

2297 if callable(self.reduce) 

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

2299 ) 

2300 box = ( 

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

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

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

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

2305 ) 

2306 

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

2308 

2309 def reduce( 

2310 self, 

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

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

2313 ) -> Image: 

2314 """ 

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

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

2317 the resulting size will be rounded up. 

2318 

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

2320 for width and height separately. 

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

2322 the source image region to be reduced. 

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

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

2325 """ 

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

2327 factor = (factor, factor) 

2328 

2329 if box is None: 

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

2331 

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

2333 return self.copy() 

2334 

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

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

2337 im = im.reduce(factor, box) 

2338 return im.convert(self.mode) 

2339 

2340 self.load() 

2341 

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

2343 

2344 def rotate( 

2345 self, 

2346 angle: float, 

2347 resample: Resampling = Resampling.NEAREST, 

2348 expand: int | bool = False, 

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

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

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

2352 ) -> Image: 

2353 """ 

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

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

2356 clockwise around its centre. 

2357 

2358 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2365 See :ref:`concept-filters`. 

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

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

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

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

2370 the center and no translation. 

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

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

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

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

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

2376 """ 

2377 

2378 angle = angle % 360.0 

2379 

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

2381 # translating or changing the center. 

2382 if not (center or translate): 

2383 if angle == 0: 

2384 return self.copy() 

2385 if angle == 180: 

2386 return self.transpose(Transpose.ROTATE_180) 

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

2388 return self.transpose( 

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

2390 ) 

2391 

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

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

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

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

2396 

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

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

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

2400 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2401 

2402 # The reverse matrix is thus: 

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

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

2405 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2406 

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

2408 # compensate for the expand flag. 

2409 

2410 w, h = self.size 

2411 

2412 if translate is None: 

2413 post_trans = (0, 0) 

2414 else: 

2415 post_trans = translate 

2416 if center is None: 

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

2418 

2419 angle = -math.radians(angle) 

2420 matrix = [ 

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

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

2423 0.0, 

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

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

2426 0.0, 

2427 ] 

2428 

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

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

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

2432 

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

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

2435 ) 

2436 matrix[2] += center[0] 

2437 matrix[5] += center[1] 

2438 

2439 if expand: 

2440 # calculate output size 

2441 xx = [] 

2442 yy = [] 

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

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

2445 xx.append(transformed_x) 

2446 yy.append(transformed_y) 

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

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

2449 

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

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

2452 # translation vector as new translation vector. 

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

2454 w, h = nw, nh 

2455 

2456 return self.transform( 

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

2458 ) 

2459 

2460 def save( 

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

2462 ) -> None: 

2463 """ 

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

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

2466 extension, if possible. 

2467 

2468 Keyword options can be used to provide additional instructions 

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

2470 silently ignored. The available options are described in the 

2471 :doc:`image format documentation 

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

2473 

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

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

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

2477 methods, and be opened in binary mode. 

2478 

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

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

2481 format to use is determined from the filename extension. 

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

2483 parameter should always be used. 

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

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

2486 saving multiple images:: 

2487 

2488 # Saving XMP data to a single image 

2489 from PIL import Image 

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

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

2492 

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

2494 from PIL import Image 

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

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

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

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

2499 :returns: None 

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

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

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

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

2504 """ 

2505 

2506 filename: str | bytes = "" 

2507 open_fp = False 

2508 if is_path(fp): 

2509 filename = os.fspath(fp) 

2510 open_fp = True 

2511 elif fp == sys.stdout: 

2512 try: 

2513 fp = sys.stdout.buffer 

2514 except AttributeError: 

2515 pass 

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

2517 # only set the name for metadata purposes 

2518 filename = os.fspath(fp.name) 

2519 

2520 preinit() 

2521 

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

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

2524 

2525 if not format: 

2526 if ext not in EXTENSION: 

2527 init() 

2528 try: 

2529 format = EXTENSION[ext] 

2530 except KeyError as e: 

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

2532 raise ValueError(msg) from e 

2533 

2534 from . import ImageFile 

2535 

2536 # may mutate self! 

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

2538 filename 

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

2540 self._ensure_mutable() 

2541 else: 

2542 self.load() 

2543 

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

2545 self._default_encoderinfo = params 

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

2547 self._attach_default_encoderinfo(self) 

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

2549 

2550 if format.upper() not in SAVE: 

2551 init() 

2552 if save_all or ( 

2553 save_all is None 

2554 and params.get("append_images") 

2555 and format.upper() in SAVE_ALL 

2556 ): 

2557 save_handler = SAVE_ALL[format.upper()] 

2558 else: 

2559 save_handler = SAVE[format.upper()] 

2560 

2561 created = False 

2562 if open_fp: 

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

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

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

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

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

2568 else: 

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

2570 else: 

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

2572 

2573 try: 

2574 save_handler(self, fp, filename) 

2575 except Exception: 

2576 if open_fp: 

2577 fp.close() 

2578 if created: 

2579 try: 

2580 os.remove(filename) 

2581 except PermissionError: 

2582 pass 

2583 raise 

2584 finally: 

2585 self.encoderinfo = encoderinfo 

2586 if open_fp: 

2587 fp.close() 

2588 

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

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

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

2592 return encoderinfo 

2593 

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

2595 """ 

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

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

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

2599 library automatically seeks to frame 0. 

2600 

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

2602 

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

2604 number of available frames. 

2605 

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

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

2608 of the sequence. 

2609 """ 

2610 

2611 # overridden by file handlers 

2612 if frame != 0: 

2613 msg = "no more images in file" 

2614 raise EOFError(msg) 

2615 

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

2617 """ 

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

2619 

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

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

2622 

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

2624 PNG format. 

2625 

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

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

2628 

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

2630 

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

2632 

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

2634 """ 

2635 

2636 _show(self, title=title) 

2637 

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

2639 """ 

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

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

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

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

2644 blue). 

2645 

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

2647 method can be more convenient and faster. 

2648 

2649 :returns: A tuple containing bands. 

2650 """ 

2651 

2652 self.load() 

2653 if self.im.bands == 1: 

2654 return (self.copy(),) 

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

2656 

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

2658 """ 

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

2660 

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

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

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

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

2665 

2666 .. versionadded:: 4.3.0 

2667 """ 

2668 self.load() 

2669 

2670 if isinstance(channel, str): 

2671 try: 

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

2673 except ValueError as e: 

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

2675 raise ValueError(msg) from e 

2676 

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

2678 

2679 def tell(self) -> int: 

2680 """ 

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

2682 

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

2684 number of available frames. 

2685 

2686 :returns: Frame number, starting with 0. 

2687 """ 

2688 return 0 

2689 

2690 def thumbnail( 

2691 self, 

2692 size: tuple[float, float], 

2693 resample: Resampling = Resampling.BICUBIC, 

2694 reducing_gap: float | None = 2.0, 

2695 ) -> None: 

2696 """ 

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

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

2699 the given size. This method calculates an appropriate thumbnail 

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

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

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

2703 

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

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

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

2707 image. 

2708 

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

2710 (width, height). 

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

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

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

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

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

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

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

2718 :param reducing_gap: Apply optimization by resizing the image 

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

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

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

2722 Second, resizing using regular resampling. The last step 

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

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

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

2726 the closer the result to the fair resampling. 

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

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

2729 indistinguishable from fair resampling in most cases. 

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

2731 while still being faster in many cases). 

2732 :returns: None 

2733 """ 

2734 

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

2736 

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

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

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

2740 

2741 x, y = provided_size 

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

2743 return None 

2744 

2745 aspect = self.width / self.height 

2746 if x / y >= aspect: 

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

2748 else: 

2749 y = round_aspect( 

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

2751 ) 

2752 return x, y 

2753 

2754 preserved_size = preserve_aspect_ratio() 

2755 if preserved_size is None: 

2756 return 

2757 final_size = preserved_size 

2758 

2759 box = None 

2760 if reducing_gap is not None: 

2761 res = self.draft( 

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

2763 ) 

2764 if res is not None: 

2765 box = res[1] 

2766 

2767 if self.size != final_size: 

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

2769 

2770 self.im = im.im 

2771 self._size = final_size 

2772 self._mode = self.im.mode 

2773 

2774 self.readonly = 0 

2775 

2776 # FIXME: the different transform methods need further explanation 

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

2778 def transform( 

2779 self, 

2780 size: tuple[int, int], 

2781 method: Transform | ImageTransformHandler | SupportsGetData, 

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

2783 resample: int = Resampling.NEAREST, 

2784 fill: int = 1, 

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

2786 ) -> Image: 

2787 """ 

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

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

2790 to the new image using the given transform. 

2791 

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

2793 (width, height). 

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

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

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

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

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

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

2800 in one operation). 

2801 

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

2803 object:: 

2804 

2805 class Example(Image.ImageTransformHandler): 

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

2807 # Return result 

2808 

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

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

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

2812 

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

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

2815 

2816 class Example: 

2817 def getdata(self): 

2818 method = Image.Transform.EXTENT 

2819 data = (0, 0, 100, 100) 

2820 return method, data 

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

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

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

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

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

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

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

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

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

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

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

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

2833 transform in the output image. 

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

2835 """ 

2836 

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

2838 return ( 

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

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

2841 .convert(self.mode) 

2842 ) 

2843 

2844 if isinstance(method, ImageTransformHandler): 

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

2846 

2847 if hasattr(method, "getdata"): 

2848 # compatibility w. old-style transform objects 

2849 method, data = method.getdata() 

2850 

2851 if data is None: 

2852 msg = "missing method data" 

2853 raise ValueError(msg) 

2854 

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

2856 if self.mode == "P" and self.palette: 

2857 im.palette = self.palette.copy() 

2858 im.info = self.info.copy() 

2859 if method == Transform.MESH: 

2860 # list of quads 

2861 for box, quad in data: 

2862 im.__transformer( 

2863 box, self, Transform.QUAD, quad, resample, fillcolor is None 

2864 ) 

2865 else: 

2866 im.__transformer( 

2867 (0, 0) + size, self, method, data, resample, fillcolor is None 

2868 ) 

2869 

2870 return im 

2871 

2872 def __transformer( 

2873 self, 

2874 box: tuple[int, int, int, int], 

2875 image: Image, 

2876 method: Transform, 

2877 data: Sequence[float], 

2878 resample: int = Resampling.NEAREST, 

2879 fill: bool = True, 

2880 ) -> None: 

2881 w = box[2] - box[0] 

2882 h = box[3] - box[1] 

2883 

2884 if method == Transform.AFFINE: 

2885 data = data[:6] 

2886 

2887 elif method == Transform.EXTENT: 

2888 # convert extent to an affine transform 

2889 x0, y0, x1, y1 = data 

2890 xs = (x1 - x0) / w 

2891 ys = (y1 - y0) / h 

2892 method = Transform.AFFINE 

2893 data = (xs, 0, x0, 0, ys, y0) 

2894 

2895 elif method == Transform.PERSPECTIVE: 

2896 data = data[:8] 

2897 

2898 elif method == Transform.QUAD: 

2899 # quadrilateral warp. data specifies the four corners 

2900 # given as NW, SW, SE, and NE. 

2901 nw = data[:2] 

2902 sw = data[2:4] 

2903 se = data[4:6] 

2904 ne = data[6:8] 

2905 x0, y0 = nw 

2906 As = 1.0 / w 

2907 At = 1.0 / h 

2908 data = ( 

2909 x0, 

2910 (ne[0] - x0) * As, 

2911 (sw[0] - x0) * At, 

2912 (se[0] - sw[0] - ne[0] + x0) * As * At, 

2913 y0, 

2914 (ne[1] - y0) * As, 

2915 (sw[1] - y0) * At, 

2916 (se[1] - sw[1] - ne[1] + y0) * As * At, 

2917 ) 

2918 

2919 else: 

2920 msg = "unknown transformation method" 

2921 raise ValueError(msg) 

2922 

2923 if resample not in ( 

2924 Resampling.NEAREST, 

2925 Resampling.BILINEAR, 

2926 Resampling.BICUBIC, 

2927 ): 

2928 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

2929 unusable: dict[int, str] = { 

2930 Resampling.BOX: "Image.Resampling.BOX", 

2931 Resampling.HAMMING: "Image.Resampling.HAMMING", 

2932 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

2933 } 

2934 msg = unusable[resample] + f" ({resample}) cannot be used." 

2935 else: 

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

2937 

2938 filters = [ 

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

2940 for filter in ( 

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

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

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

2944 ) 

2945 ] 

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

2947 raise ValueError(msg) 

2948 

2949 image.load() 

2950 

2951 self.load() 

2952 

2953 if image.mode in ("1", "P"): 

2954 resample = Resampling.NEAREST 

2955 

2956 self.im.transform(box, image.im, method, data, resample, fill) 

2957 

2958 def transpose(self, method: Transpose) -> Image: 

2959 """ 

2960 Transpose image (flip or rotate in 90 degree steps) 

2961 

2962 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

2963 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

2964 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

2965 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

2966 :returns: Returns a flipped or rotated copy of this image. 

2967 """ 

2968 

2969 self.load() 

2970 return self._new(self.im.transpose(method)) 

2971 

2972 def effect_spread(self, distance: int) -> Image: 

2973 """ 

2974 Randomly spread pixels in an image. 

2975 

2976 :param distance: Distance to spread pixels. 

2977 """ 

2978 self.load() 

2979 return self._new(self.im.effect_spread(distance)) 

2980 

2981 def toqimage(self) -> ImageQt.ImageQt: 

2982 """Returns a QImage copy of this image""" 

2983 from . import ImageQt 

2984 

2985 if not ImageQt.qt_is_installed: 

2986 msg = "Qt bindings are not installed" 

2987 raise ImportError(msg) 

2988 return ImageQt.toqimage(self) 

2989 

2990 def toqpixmap(self) -> ImageQt.QPixmap: 

2991 """Returns a QPixmap copy of this image""" 

2992 from . import ImageQt 

2993 

2994 if not ImageQt.qt_is_installed: 

2995 msg = "Qt bindings are not installed" 

2996 raise ImportError(msg) 

2997 return ImageQt.toqpixmap(self) 

2998 

2999 

3000# -------------------------------------------------------------------- 

3001# Abstract handlers. 

3002 

3003 

3004class ImagePointHandler(abc.ABC): 

3005 """ 

3006 Used as a mixin by point transforms 

3007 (for use with :py:meth:`~PIL.Image.Image.point`) 

3008 """ 

3009 

3010 @abc.abstractmethod 

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

3012 pass 

3013 

3014 

3015class ImageTransformHandler(abc.ABC): 

3016 """ 

3017 Used as a mixin by geometry transforms 

3018 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3019 """ 

3020 

3021 @abc.abstractmethod 

3022 def transform( 

3023 self, 

3024 size: tuple[int, int], 

3025 image: Image, 

3026 **options: Any, 

3027 ) -> Image: 

3028 pass 

3029 

3030 

3031# -------------------------------------------------------------------- 

3032# Factories 

3033 

3034 

3035def _check_size(size: Any) -> None: 

3036 """ 

3037 Common check to enforce type and sanity check on size tuples 

3038 

3039 :param size: Should be a 2 tuple of (width, height) 

3040 :returns: None, or raises a ValueError 

3041 """ 

3042 

3043 if not isinstance(size, (list, tuple)): 

3044 msg = "Size must be a list or tuple" 

3045 raise ValueError(msg) 

3046 if len(size) != 2: 

3047 msg = "Size must be a sequence of length 2" 

3048 raise ValueError(msg) 

3049 if size[0] < 0 or size[1] < 0: 

3050 msg = "Width and height must be >= 0" 

3051 raise ValueError(msg) 

3052 

3053 

3054def new( 

3055 mode: str, 

3056 size: tuple[int, int] | list[int], 

3057 color: float | tuple[float, ...] | str | None = 0, 

3058) -> Image: 

3059 """ 

3060 Creates a new image with the given mode and size. 

3061 

3062 :param mode: The mode to use for the new image. See: 

3063 :ref:`concept-modes`. 

3064 :param size: A 2-tuple, containing (width, height) in pixels. 

3065 :param color: What color to use for the image. Default is black. If given, 

3066 this should be a single integer or floating point value for single-band 

3067 modes, and a tuple for multi-band modes (one value per band). When 

3068 creating RGB or HSV images, you can also use color strings as supported 

3069 by the ImageColor module. See :ref:`colors` for more information. If the 

3070 color is None, the image is not initialised. 

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

3072 """ 

3073 

3074 _check_size(size) 

3075 

3076 if color is None: 

3077 # don't initialize 

3078 return Image()._new(core.new(mode, size)) 

3079 

3080 if isinstance(color, str): 

3081 # css3-style specifier 

3082 

3083 from . import ImageColor 

3084 

3085 color = ImageColor.getcolor(color, mode) 

3086 

3087 im = Image() 

3088 if ( 

3089 mode == "P" 

3090 and isinstance(color, (list, tuple)) 

3091 and all(isinstance(i, int) for i in color) 

3092 ): 

3093 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3094 if len(color_ints) == 3 or len(color_ints) == 4: 

3095 # RGB or RGBA value for a P image 

3096 from . import ImagePalette 

3097 

3098 im.palette = ImagePalette.ImagePalette() 

3099 color = im.palette.getcolor(color_ints) 

3100 return im._new(core.fill(mode, size, color)) 

3101 

3102 

3103def frombytes( 

3104 mode: str, 

3105 size: tuple[int, int], 

3106 data: bytes | bytearray | SupportsArrayInterface, 

3107 decoder_name: str = "raw", 

3108 *args: Any, 

3109) -> Image: 

3110 """ 

3111 Creates a copy of an image memory from pixel data in a buffer. 

3112 

3113 In its simplest form, this function takes three arguments 

3114 (mode, size, and unpacked pixel data). 

3115 

3116 You can also use any pixel decoder supported by PIL. For more 

3117 information on available decoders, see the section 

3118 :ref:`Writing Your Own File Codec <file-codecs>`. 

3119 

3120 Note that this function decodes pixel data only, not entire images. 

3121 If you have an entire image in a string, wrap it in a 

3122 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3123 it. 

3124 

3125 :param mode: The image mode. See: :ref:`concept-modes`. 

3126 :param size: The image size. 

3127 :param data: A byte buffer containing raw data for the given mode. 

3128 :param decoder_name: What decoder to use. 

3129 :param args: Additional parameters for the given decoder. 

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

3131 """ 

3132 

3133 _check_size(size) 

3134 

3135 im = new(mode, size) 

3136 if im.width != 0 and im.height != 0: 

3137 decoder_args: Any = args 

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

3139 # may pass tuple instead of argument list 

3140 decoder_args = decoder_args[0] 

3141 

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

3143 decoder_args = mode 

3144 

3145 im.frombytes(data, decoder_name, decoder_args) 

3146 return im 

3147 

3148 

3149def frombuffer( 

3150 mode: str, 

3151 size: tuple[int, int], 

3152 data: bytes | SupportsArrayInterface, 

3153 decoder_name: str = "raw", 

3154 *args: Any, 

3155) -> Image: 

3156 """ 

3157 Creates an image memory referencing pixel data in a byte buffer. 

3158 

3159 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3160 in the byte buffer, where possible. This means that changes to the 

3161 original buffer object are reflected in this image). Not all modes can 

3162 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3163 

3164 Note that this function decodes pixel data only, not entire images. 

3165 If you have an entire image file in a string, wrap it in a 

3166 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3167 

3168 The default parameters used for the "raw" decoder differs from that used for 

3169 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3170 future release. The current release issues a warning if you do this; to disable 

3171 the warning, you should provide the full set of parameters. See below for details. 

3172 

3173 :param mode: The image mode. See: :ref:`concept-modes`. 

3174 :param size: The image size. 

3175 :param data: A bytes or other buffer object containing raw 

3176 data for the given mode. 

3177 :param decoder_name: What decoder to use. 

3178 :param args: Additional parameters for the given decoder. For the 

3179 default encoder ("raw"), it's recommended that you provide the 

3180 full set of parameters:: 

3181 

3182 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3183 

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

3185 

3186 .. versionadded:: 1.1.4 

3187 """ 

3188 

3189 _check_size(size) 

3190 

3191 # may pass tuple instead of argument list 

3192 if len(args) == 1 and isinstance(args[0], tuple): 

3193 args = args[0] 

3194 

3195 if decoder_name == "raw": 

3196 if args == (): 

3197 args = mode, 0, 1 

3198 if args[0] in _MAPMODES: 

3199 im = new(mode, (0, 0)) 

3200 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3201 if mode == "P": 

3202 from . import ImagePalette 

3203 

3204 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3205 im.readonly = 1 

3206 return im 

3207 

3208 return frombytes(mode, size, data, decoder_name, args) 

3209 

3210 

3211class SupportsArrayInterface(Protocol): 

3212 """ 

3213 An object that has an ``__array_interface__`` dictionary. 

3214 """ 

3215 

3216 @property 

3217 def __array_interface__(self) -> dict[str, Any]: 

3218 raise NotImplementedError() 

3219 

3220 

3221class SupportsArrowArrayInterface(Protocol): 

3222 """ 

3223 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3224 data interface. 

3225 """ 

3226 

3227 def __arrow_c_array__( 

3228 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3229 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3230 raise NotImplementedError() 

3231 

3232 

3233def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3234 """ 

3235 Creates an image memory from an object exporting the array interface 

3236 (using the buffer protocol):: 

3237 

3238 from PIL import Image 

3239 import numpy as np 

3240 a = np.zeros((5, 5)) 

3241 im = Image.fromarray(a) 

3242 

3243 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3244 and :py:func:`~PIL.Image.frombuffer` is used. 

3245 

3246 In the case of NumPy, be aware that Pillow modes do not always correspond 

3247 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3248 32-bit signed integer pixels, and 32-bit floating point pixels. 

3249 

3250 Pillow images can also be converted to arrays:: 

3251 

3252 from PIL import Image 

3253 import numpy as np 

3254 im = Image.open("hopper.jpg") 

3255 a = np.asarray(im) 

3256 

3257 When converting Pillow images to arrays however, only pixel values are 

3258 transferred. This means that P and PA mode images will lose their palette. 

3259 

3260 :param obj: Object with array interface 

3261 :param mode: Optional mode to use when reading ``obj``. Will be determined from 

3262 type if ``None``. Deprecated. 

3263 

3264 This will not be used to convert the data after reading, but will be used to 

3265 change how the data is read:: 

3266 

3267 from PIL import Image 

3268 import numpy as np 

3269 a = np.full((1, 1), 300) 

3270 im = Image.fromarray(a, mode="L") 

3271 im.getpixel((0, 0)) # 44 

3272 im = Image.fromarray(a, mode="RGB") 

3273 im.getpixel((0, 0)) # (44, 1, 0) 

3274 

3275 See: :ref:`concept-modes` for general information about modes. 

3276 :returns: An image object. 

3277 

3278 .. versionadded:: 1.1.6 

3279 """ 

3280 arr = obj.__array_interface__ 

3281 shape = arr["shape"] 

3282 ndim = len(shape) 

3283 strides = arr.get("strides", None) 

3284 if mode is None: 

3285 try: 

3286 typekey = (1, 1) + shape[2:], arr["typestr"] 

3287 except KeyError as e: 

3288 msg = "Cannot handle this data type" 

3289 raise TypeError(msg) from e 

3290 try: 

3291 mode, rawmode = _fromarray_typemap[typekey] 

3292 except KeyError as e: 

3293 typekey_shape, typestr = typekey 

3294 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3295 raise TypeError(msg) from e 

3296 else: 

3297 deprecate("'mode' parameter", 13) 

3298 rawmode = mode 

3299 if mode in ["1", "L", "I", "P", "F"]: 

3300 ndmax = 2 

3301 elif mode == "RGB": 

3302 ndmax = 3 

3303 else: 

3304 ndmax = 4 

3305 if ndim > ndmax: 

3306 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3307 raise ValueError(msg) 

3308 

3309 size = 1 if ndim == 1 else shape[1], shape[0] 

3310 if strides is not None: 

3311 if hasattr(obj, "tobytes"): 

3312 obj = obj.tobytes() 

3313 elif hasattr(obj, "tostring"): 

3314 obj = obj.tostring() 

3315 else: 

3316 msg = "'strides' requires either tobytes() or tostring()" 

3317 raise ValueError(msg) 

3318 

3319 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3320 

3321 

3322def fromarrow( 

3323 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3324) -> Image: 

3325 """Creates an image with zero-copy shared memory from an object exporting 

3326 the arrow_c_array interface protocol:: 

3327 

3328 from PIL import Image 

3329 import pyarrow as pa 

3330 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3331 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3332 

3333 If the data representation of the ``obj`` is not compatible with 

3334 Pillow internal storage, a ValueError is raised. 

3335 

3336 Pillow images can also be converted to Arrow objects:: 

3337 

3338 from PIL import Image 

3339 import pyarrow as pa 

3340 im = Image.open('hopper.jpg') 

3341 arr = pa.array(im) 

3342 

3343 As with array support, when converting Pillow images to arrays, 

3344 only pixel values are transferred. This means that P and PA mode 

3345 images will lose their palette. 

3346 

3347 :param obj: Object with an arrow_c_array interface 

3348 :param mode: Image mode. 

3349 :param size: Image size. This must match the storage of the arrow object. 

3350 :returns: An Image object 

3351 

3352 Note that according to the Arrow spec, both the producer and the 

3353 consumer should consider the exported array to be immutable, as 

3354 unsynchronized updates will potentially cause inconsistent data. 

3355 

3356 See: :ref:`arrow-support` for more detailed information 

3357 

3358 .. versionadded:: 11.2.1 

3359 

3360 """ 

3361 if not hasattr(obj, "__arrow_c_array__"): 

3362 msg = "arrow_c_array interface not found" 

3363 raise ValueError(msg) 

3364 

3365 (schema_capsule, array_capsule) = obj.__arrow_c_array__() 

3366 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3367 if _im: 

3368 return Image()._new(_im) 

3369 

3370 msg = "new_arrow returned None without an exception" 

3371 raise ValueError(msg) 

3372 

3373 

3374def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3375 """Creates an image instance from a QImage image""" 

3376 from . import ImageQt 

3377 

3378 if not ImageQt.qt_is_installed: 

3379 msg = "Qt bindings are not installed" 

3380 raise ImportError(msg) 

3381 return ImageQt.fromqimage(im) 

3382 

3383 

3384def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3385 """Creates an image instance from a QPixmap image""" 

3386 from . import ImageQt 

3387 

3388 if not ImageQt.qt_is_installed: 

3389 msg = "Qt bindings are not installed" 

3390 raise ImportError(msg) 

3391 return ImageQt.fromqpixmap(im) 

3392 

3393 

3394_fromarray_typemap = { 

3395 # (shape, typestr) => mode, rawmode 

3396 # first two members of shape are set to one 

3397 ((1, 1), "|b1"): ("1", "1;8"), 

3398 ((1, 1), "|u1"): ("L", "L"), 

3399 ((1, 1), "|i1"): ("I", "I;8"), 

3400 ((1, 1), "<u2"): ("I", "I;16"), 

3401 ((1, 1), ">u2"): ("I", "I;16B"), 

3402 ((1, 1), "<i2"): ("I", "I;16S"), 

3403 ((1, 1), ">i2"): ("I", "I;16BS"), 

3404 ((1, 1), "<u4"): ("I", "I;32"), 

3405 ((1, 1), ">u4"): ("I", "I;32B"), 

3406 ((1, 1), "<i4"): ("I", "I;32S"), 

3407 ((1, 1), ">i4"): ("I", "I;32BS"), 

3408 ((1, 1), "<f4"): ("F", "F;32F"), 

3409 ((1, 1), ">f4"): ("F", "F;32BF"), 

3410 ((1, 1), "<f8"): ("F", "F;64F"), 

3411 ((1, 1), ">f8"): ("F", "F;64BF"), 

3412 ((1, 1, 2), "|u1"): ("LA", "LA"), 

3413 ((1, 1, 3), "|u1"): ("RGB", "RGB"), 

3414 ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), 

3415 # shortcuts: 

3416 ((1, 1), f"{_ENDIAN}i4"): ("I", "I"), 

3417 ((1, 1), f"{_ENDIAN}f4"): ("F", "F"), 

3418} 

3419 

3420 

3421def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3422 if MAX_IMAGE_PIXELS is None: 

3423 return 

3424 

3425 pixels = max(1, size[0]) * max(1, size[1]) 

3426 

3427 if pixels > 2 * MAX_IMAGE_PIXELS: 

3428 msg = ( 

3429 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3430 "pixels, could be decompression bomb DOS attack." 

3431 ) 

3432 raise DecompressionBombError(msg) 

3433 

3434 if pixels > MAX_IMAGE_PIXELS: 

3435 warnings.warn( 

3436 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3437 "could be decompression bomb DOS attack.", 

3438 DecompressionBombWarning, 

3439 ) 

3440 

3441 

3442def open( 

3443 fp: StrOrBytesPath | IO[bytes], 

3444 mode: Literal["r"] = "r", 

3445 formats: list[str] | tuple[str, ...] | None = None, 

3446) -> ImageFile.ImageFile: 

3447 """ 

3448 Opens and identifies the given image file. 

3449 

3450 This is a lazy operation; this function identifies the file, but 

3451 the file remains open and the actual image data is not read from 

3452 the file until you try to process the data (or call the 

3453 :py:meth:`~PIL.Image.Image.load` method). See 

3454 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3455 

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

3457 The file object must implement ``file.read``, 

3458 ``file.seek``, and ``file.tell`` methods, 

3459 and be opened in binary mode. The file object will also seek to zero 

3460 before reading. 

3461 :param mode: The mode. If given, this argument must be "r". 

3462 :param formats: A list or tuple of formats to attempt to load the file in. 

3463 This can be used to restrict the set of formats checked. 

3464 Pass ``None`` to try all supported formats. You can print the set of 

3465 available formats by running ``python3 -m PIL`` or using 

3466 the :py:func:`PIL.features.pilinfo` function. 

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

3468 :exception FileNotFoundError: If the file cannot be found. 

3469 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3470 identified. 

3471 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3472 instance is used for ``fp``. 

3473 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3474 """ 

3475 

3476 if mode != "r": 

3477 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3478 raise ValueError(msg) 

3479 elif isinstance(fp, io.StringIO): 

3480 msg = ( # type: ignore[unreachable] 

3481 "StringIO cannot be used to open an image. " 

3482 "Binary data must be used instead." 

3483 ) 

3484 raise ValueError(msg) 

3485 

3486 if formats is None: 

3487 formats = ID 

3488 elif not isinstance(formats, (list, tuple)): 

3489 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3490 raise TypeError(msg) 

3491 

3492 exclusive_fp = False 

3493 filename: str | bytes = "" 

3494 if is_path(fp): 

3495 filename = os.fspath(fp) 

3496 fp = builtins.open(filename, "rb") 

3497 exclusive_fp = True 

3498 else: 

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

3500 

3501 try: 

3502 fp.seek(0) 

3503 except (AttributeError, io.UnsupportedOperation): 

3504 fp = io.BytesIO(fp.read()) 

3505 exclusive_fp = True 

3506 

3507 prefix = fp.read(16) 

3508 

3509 preinit() 

3510 

3511 warning_messages: list[str] = [] 

3512 

3513 def _open_core( 

3514 fp: IO[bytes], 

3515 filename: str | bytes, 

3516 prefix: bytes, 

3517 formats: list[str] | tuple[str, ...], 

3518 ) -> ImageFile.ImageFile | None: 

3519 for i in formats: 

3520 i = i.upper() 

3521 if i not in OPEN: 

3522 init() 

3523 try: 

3524 factory, accept = OPEN[i] 

3525 result = not accept or accept(prefix) 

3526 if isinstance(result, str): 

3527 warning_messages.append(result) 

3528 elif result: 

3529 fp.seek(0) 

3530 im = factory(fp, filename) 

3531 _decompression_bomb_check(im.size) 

3532 return im 

3533 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3534 if WARN_POSSIBLE_FORMATS: 

3535 warning_messages.append(i + " opening failed. " + str(e)) 

3536 except BaseException: 

3537 if exclusive_fp: 

3538 fp.close() 

3539 raise 

3540 return None 

3541 

3542 im = _open_core(fp, filename, prefix, formats) 

3543 

3544 if im is None and formats is ID: 

3545 checked_formats = ID.copy() 

3546 if init(): 

3547 im = _open_core( 

3548 fp, 

3549 filename, 

3550 prefix, 

3551 tuple(format for format in formats if format not in checked_formats), 

3552 ) 

3553 

3554 if im: 

3555 im._exclusive_fp = exclusive_fp 

3556 return im 

3557 

3558 if exclusive_fp: 

3559 fp.close() 

3560 for message in warning_messages: 

3561 warnings.warn(message) 

3562 msg = "cannot identify image file %r" % (filename if filename else fp) 

3563 raise UnidentifiedImageError(msg) 

3564 

3565 

3566# 

3567# Image processing. 

3568 

3569 

3570def alpha_composite(im1: Image, im2: Image) -> Image: 

3571 """ 

3572 Alpha composite im2 over im1. 

3573 

3574 :param im1: The first image. Must have mode RGBA. 

3575 :param im2: The second image. Must have mode RGBA, and the same size as 

3576 the first image. 

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

3578 """ 

3579 

3580 im1.load() 

3581 im2.load() 

3582 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3583 

3584 

3585def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3586 """ 

3587 Creates a new image by interpolating between two input images, using 

3588 a constant alpha:: 

3589 

3590 out = image1 * (1.0 - alpha) + image2 * alpha 

3591 

3592 :param im1: The first image. 

3593 :param im2: The second image. Must have the same mode and size as 

3594 the first image. 

3595 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3596 copy of the first image is returned. If alpha is 1.0, a copy of 

3597 the second image is returned. There are no restrictions on the 

3598 alpha value. If necessary, the result is clipped to fit into 

3599 the allowed output range. 

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

3601 """ 

3602 

3603 im1.load() 

3604 im2.load() 

3605 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3606 

3607 

3608def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3609 """ 

3610 Create composite image by blending images using a transparency mask. 

3611 

3612 :param image1: The first image. 

3613 :param image2: The second image. Must have the same mode and 

3614 size as the first image. 

3615 :param mask: A mask image. This image can have mode 

3616 "1", "L", or "RGBA", and must have the same size as the 

3617 other two images. 

3618 """ 

3619 

3620 image = image2.copy() 

3621 image.paste(image1, None, mask) 

3622 return image 

3623 

3624 

3625def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3626 """ 

3627 Applies the function (which should take one argument) to each pixel 

3628 in the given image. If the image has more than one band, the same 

3629 function is applied to each band. Note that the function is 

3630 evaluated once for each possible pixel value, so you cannot use 

3631 random components or other generators. 

3632 

3633 :param image: The input image. 

3634 :param function: A function object, taking one integer argument. 

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

3636 """ 

3637 

3638 return image.point(args[0]) 

3639 

3640 

3641def merge(mode: str, bands: Sequence[Image]) -> Image: 

3642 """ 

3643 Merge a set of single band images into a new multiband image. 

3644 

3645 :param mode: The mode to use for the output image. See: 

3646 :ref:`concept-modes`. 

3647 :param bands: A sequence containing one single-band image for 

3648 each band in the output image. All bands must have the 

3649 same size. 

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

3651 """ 

3652 

3653 if getmodebands(mode) != len(bands) or "*" in mode: 

3654 msg = "wrong number of bands" 

3655 raise ValueError(msg) 

3656 for band in bands[1:]: 

3657 if band.mode != getmodetype(mode): 

3658 msg = "mode mismatch" 

3659 raise ValueError(msg) 

3660 if band.size != bands[0].size: 

3661 msg = "size mismatch" 

3662 raise ValueError(msg) 

3663 for band in bands: 

3664 band.load() 

3665 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3666 

3667 

3668# -------------------------------------------------------------------- 

3669# Plugin registry 

3670 

3671 

3672def register_open( 

3673 id: str, 

3674 factory: ( 

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

3676 | type[ImageFile.ImageFile] 

3677 ), 

3678 accept: Callable[[bytes], bool | str] | None = None, 

3679) -> None: 

3680 """ 

3681 Register an image file plugin. This function should not be used 

3682 in application code. 

3683 

3684 :param id: An image format identifier. 

3685 :param factory: An image file factory method. 

3686 :param accept: An optional function that can be used to quickly 

3687 reject images having another format. 

3688 """ 

3689 id = id.upper() 

3690 if id not in ID: 

3691 ID.append(id) 

3692 OPEN[id] = factory, accept 

3693 

3694 

3695def register_mime(id: str, mimetype: str) -> None: 

3696 """ 

3697 Registers an image MIME type by populating ``Image.MIME``. This function 

3698 should not be used in application code. 

3699 

3700 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3701 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3702 provide a different result for specific images. 

3703 

3704 :param id: An image format identifier. 

3705 :param mimetype: The image MIME type for this format. 

3706 """ 

3707 MIME[id.upper()] = mimetype 

3708 

3709 

3710def register_save( 

3711 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3712) -> None: 

3713 """ 

3714 Registers an image save function. This function should not be 

3715 used in application code. 

3716 

3717 :param id: An image format identifier. 

3718 :param driver: A function to save images in this format. 

3719 """ 

3720 SAVE[id.upper()] = driver 

3721 

3722 

3723def register_save_all( 

3724 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3725) -> None: 

3726 """ 

3727 Registers an image function to save all the frames 

3728 of a multiframe format. This function should not be 

3729 used in application code. 

3730 

3731 :param id: An image format identifier. 

3732 :param driver: A function to save images in this format. 

3733 """ 

3734 SAVE_ALL[id.upper()] = driver 

3735 

3736 

3737def register_extension(id: str, extension: str) -> None: 

3738 """ 

3739 Registers an image extension. This function should not be 

3740 used in application code. 

3741 

3742 :param id: An image format identifier. 

3743 :param extension: An extension used for this format. 

3744 """ 

3745 EXTENSION[extension.lower()] = id.upper() 

3746 

3747 

3748def register_extensions(id: str, extensions: list[str]) -> None: 

3749 """ 

3750 Registers image extensions. This function should not be 

3751 used in application code. 

3752 

3753 :param id: An image format identifier. 

3754 :param extensions: A list of extensions used for this format. 

3755 """ 

3756 for extension in extensions: 

3757 register_extension(id, extension) 

3758 

3759 

3760def registered_extensions() -> dict[str, str]: 

3761 """ 

3762 Returns a dictionary containing all file extensions belonging 

3763 to registered plugins 

3764 """ 

3765 init() 

3766 return EXTENSION 

3767 

3768 

3769def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3770 """ 

3771 Registers an image decoder. This function should not be 

3772 used in application code. 

3773 

3774 :param name: The name of the decoder 

3775 :param decoder: An ImageFile.PyDecoder object 

3776 

3777 .. versionadded:: 4.1.0 

3778 """ 

3779 DECODERS[name] = decoder 

3780 

3781 

3782def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3783 """ 

3784 Registers an image encoder. This function should not be 

3785 used in application code. 

3786 

3787 :param name: The name of the encoder 

3788 :param encoder: An ImageFile.PyEncoder object 

3789 

3790 .. versionadded:: 4.1.0 

3791 """ 

3792 ENCODERS[name] = encoder 

3793 

3794 

3795# -------------------------------------------------------------------- 

3796# Simple display support. 

3797 

3798 

3799def _show(image: Image, **options: Any) -> None: 

3800 from . import ImageShow 

3801 

3802 ImageShow.show(image, **options) 

3803 

3804 

3805# -------------------------------------------------------------------- 

3806# Effects 

3807 

3808 

3809def effect_mandelbrot( 

3810 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3811) -> Image: 

3812 """ 

3813 Generate a Mandelbrot set covering the given extent. 

3814 

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

3816 (width, height). 

3817 :param extent: The extent to cover, as a 4-tuple: 

3818 (x0, y0, x1, y1). 

3819 :param quality: Quality. 

3820 """ 

3821 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3822 

3823 

3824def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3825 """ 

3826 Generate Gaussian noise centered around 128. 

3827 

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

3829 (width, height). 

3830 :param sigma: Standard deviation of noise. 

3831 """ 

3832 return Image()._new(core.effect_noise(size, sigma)) 

3833 

3834 

3835def linear_gradient(mode: str) -> Image: 

3836 """ 

3837 Generate 256x256 linear gradient from black to white, top to bottom. 

3838 

3839 :param mode: Input mode. 

3840 """ 

3841 return Image()._new(core.linear_gradient(mode)) 

3842 

3843 

3844def radial_gradient(mode: str) -> Image: 

3845 """ 

3846 Generate 256x256 radial gradient from black to white, centre to edge. 

3847 

3848 :param mode: Input mode. 

3849 """ 

3850 return Image()._new(core.radial_gradient(mode)) 

3851 

3852 

3853# -------------------------------------------------------------------- 

3854# Resources 

3855 

3856 

3857def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

3858 env_dict = env if env is not None else os.environ 

3859 

3860 for var_name, setter in [ 

3861 ("PILLOW_ALIGNMENT", core.set_alignment), 

3862 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

3863 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

3864 ]: 

3865 if var_name not in env_dict: 

3866 continue 

3867 

3868 var = env_dict[var_name].lower() 

3869 

3870 units = 1 

3871 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

3872 if var.endswith(postfix): 

3873 units = mul 

3874 var = var[: -len(postfix)] 

3875 

3876 try: 

3877 var_int = int(var) * units 

3878 except ValueError: 

3879 warnings.warn(f"{var_name} is not int") 

3880 continue 

3881 

3882 try: 

3883 setter(var_int) 

3884 except ValueError as e: 

3885 warnings.warn(f"{var_name}: {e}") 

3886 

3887 

3888_apply_env_variables() 

3889atexit.register(core.clear_cache) 

3890 

3891 

3892if TYPE_CHECKING: 

3893 _ExifBase = MutableMapping[int, Any] 

3894else: 

3895 _ExifBase = MutableMapping 

3896 

3897 

3898class Exif(_ExifBase): 

3899 """ 

3900 This class provides read and write access to EXIF image data:: 

3901 

3902 from PIL import Image 

3903 im = Image.open("exif.png") 

3904 exif = im.getexif() # Returns an instance of this class 

3905 

3906 Information can be read and written, iterated over or deleted:: 

3907 

3908 print(exif[274]) # 1 

3909 exif[274] = 2 

3910 for k, v in exif.items(): 

3911 print("Tag", k, "Value", v) # Tag 274 Value 2 

3912 del exif[274] 

3913 

3914 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

3915 returns a dictionary:: 

3916 

3917 from PIL import ExifTags 

3918 im = Image.open("exif_gps.jpg") 

3919 exif = im.getexif() 

3920 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

3921 print(gps_ifd) 

3922 

3923 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

3924 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

3925 

3926 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

3927 

3928 print(exif[ExifTags.Base.Software]) # PIL 

3929 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

3930 """ 

3931 

3932 endian: str | None = None 

3933 bigtiff = False 

3934 _loaded = False 

3935 

3936 def __init__(self) -> None: 

3937 self._data: dict[int, Any] = {} 

3938 self._hidden_data: dict[int, Any] = {} 

3939 self._ifds: dict[int, dict[int, Any]] = {} 

3940 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

3941 self._loaded_exif: bytes | None = None 

3942 

3943 def _fixup(self, value: Any) -> Any: 

3944 try: 

3945 if len(value) == 1 and isinstance(value, tuple): 

3946 return value[0] 

3947 except Exception: 

3948 pass 

3949 return value 

3950 

3951 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

3952 # Helper function 

3953 # returns a dict with any single item tuples/lists as individual values 

3954 return {k: self._fixup(v) for k, v in src_dict.items()} 

3955 

3956 def _get_ifd_dict( 

3957 self, offset: int, group: int | None = None 

3958 ) -> dict[int, Any] | None: 

3959 try: 

3960 # an offset pointer to the location of the nested embedded IFD. 

3961 # It should be a long, but may be corrupted. 

3962 self.fp.seek(offset) 

3963 except (KeyError, TypeError): 

3964 return None 

3965 else: 

3966 from . import TiffImagePlugin 

3967 

3968 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

3969 info.load(self.fp) 

3970 return self._fixup_dict(dict(info)) 

3971 

3972 def _get_head(self) -> bytes: 

3973 version = b"\x2b" if self.bigtiff else b"\x2a" 

3974 if self.endian == "<": 

3975 head = b"II" + version + b"\x00" + o32le(8) 

3976 else: 

3977 head = b"MM\x00" + version + o32be(8) 

3978 if self.bigtiff: 

3979 head += o32le(8) if self.endian == "<" else o32be(8) 

3980 head += b"\x00\x00\x00\x00" 

3981 return head 

3982 

3983 def load(self, data: bytes) -> None: 

3984 # Extract EXIF information. This is highly experimental, 

3985 # and is likely to be replaced with something better in a future 

3986 # version. 

3987 

3988 # The EXIF record consists of a TIFF file embedded in a JPEG 

3989 # application marker (!). 

3990 if data == self._loaded_exif: 

3991 return 

3992 self._loaded_exif = data 

3993 self._data.clear() 

3994 self._hidden_data.clear() 

3995 self._ifds.clear() 

3996 while data and data.startswith(b"Exif\x00\x00"): 

3997 data = data[6:] 

3998 if not data: 

3999 self._info = None 

4000 return 

4001 

4002 self.fp: IO[bytes] = io.BytesIO(data) 

4003 self.head = self.fp.read(8) 

4004 # process dictionary 

4005 from . import TiffImagePlugin 

4006 

4007 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4008 self.endian = self._info._endian 

4009 self.fp.seek(self._info.next) 

4010 self._info.load(self.fp) 

4011 

4012 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4013 self._loaded_exif = None 

4014 self._data.clear() 

4015 self._hidden_data.clear() 

4016 self._ifds.clear() 

4017 

4018 # process dictionary 

4019 from . import TiffImagePlugin 

4020 

4021 self.fp = fp 

4022 if offset is not None: 

4023 self.head = self._get_head() 

4024 else: 

4025 self.head = self.fp.read(8) 

4026 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4027 if self.endian is None: 

4028 self.endian = self._info._endian 

4029 if offset is None: 

4030 offset = self._info.next 

4031 self.fp.tell() 

4032 self.fp.seek(offset) 

4033 self._info.load(self.fp) 

4034 

4035 def _get_merged_dict(self) -> dict[int, Any]: 

4036 merged_dict = dict(self) 

4037 

4038 # get EXIF extension 

4039 if ExifTags.IFD.Exif in self: 

4040 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4041 if ifd: 

4042 merged_dict.update(ifd) 

4043 

4044 # GPS 

4045 if ExifTags.IFD.GPSInfo in self: 

4046 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4047 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4048 ) 

4049 

4050 return merged_dict 

4051 

4052 def tobytes(self, offset: int = 8) -> bytes: 

4053 from . import TiffImagePlugin 

4054 

4055 head = self._get_head() 

4056 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4057 for tag, ifd_dict in self._ifds.items(): 

4058 if tag not in self: 

4059 ifd[tag] = ifd_dict 

4060 for tag, value in self.items(): 

4061 if tag in [ 

4062 ExifTags.IFD.Exif, 

4063 ExifTags.IFD.GPSInfo, 

4064 ] and not isinstance(value, dict): 

4065 value = self.get_ifd(tag) 

4066 if ( 

4067 tag == ExifTags.IFD.Exif 

4068 and ExifTags.IFD.Interop in value 

4069 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4070 ): 

4071 value = value.copy() 

4072 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4073 ifd[tag] = value 

4074 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4075 

4076 def get_ifd(self, tag: int) -> dict[int, Any]: 

4077 if tag not in self._ifds: 

4078 if tag == ExifTags.IFD.IFD1: 

4079 if self._info is not None and self._info.next != 0: 

4080 ifd = self._get_ifd_dict(self._info.next) 

4081 if ifd is not None: 

4082 self._ifds[tag] = ifd 

4083 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4084 offset = self._hidden_data.get(tag, self.get(tag)) 

4085 if offset is not None: 

4086 ifd = self._get_ifd_dict(offset, tag) 

4087 if ifd is not None: 

4088 self._ifds[tag] = ifd 

4089 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4090 if ExifTags.IFD.Exif not in self._ifds: 

4091 self.get_ifd(ExifTags.IFD.Exif) 

4092 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4093 if tag == ExifTags.IFD.MakerNote: 

4094 from .TiffImagePlugin import ImageFileDirectory_v2 

4095 

4096 if tag_data.startswith(b"FUJIFILM"): 

4097 ifd_offset = i32le(tag_data, 8) 

4098 ifd_data = tag_data[ifd_offset:] 

4099 

4100 makernote = {} 

4101 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4102 ifd_tag, typ, count, data = struct.unpack( 

4103 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4104 ) 

4105 try: 

4106 ( 

4107 unit_size, 

4108 handler, 

4109 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4110 except KeyError: 

4111 continue 

4112 size = count * unit_size 

4113 if size > 4: 

4114 (offset,) = struct.unpack("<L", data) 

4115 data = ifd_data[offset - 12 : offset + size - 12] 

4116 else: 

4117 data = data[:size] 

4118 

4119 if len(data) != size: 

4120 warnings.warn( 

4121 "Possibly corrupt EXIF MakerNote data. " 

4122 f"Expecting to read {size} bytes but only got " 

4123 f"{len(data)}. Skipping tag {ifd_tag}" 

4124 ) 

4125 continue 

4126 

4127 if not data: 

4128 continue 

4129 

4130 makernote[ifd_tag] = handler( 

4131 ImageFileDirectory_v2(), data, False 

4132 ) 

4133 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4134 elif self.get(0x010F) == "Nintendo": 

4135 makernote = {} 

4136 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4137 ifd_tag, typ, count, data = struct.unpack( 

4138 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4139 ) 

4140 if ifd_tag == 0x1101: 

4141 # CameraInfo 

4142 (offset,) = struct.unpack(">L", data) 

4143 self.fp.seek(offset) 

4144 

4145 camerainfo: dict[str, int | bytes] = { 

4146 "ModelID": self.fp.read(4) 

4147 } 

4148 

4149 self.fp.read(4) 

4150 # Seconds since 2000 

4151 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4152 

4153 self.fp.read(4) 

4154 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4155 

4156 self.fp.read(12) 

4157 parallax = self.fp.read(4) 

4158 handler = ImageFileDirectory_v2._load_dispatch[ 

4159 TiffTags.FLOAT 

4160 ][1] 

4161 camerainfo["Parallax"] = handler( 

4162 ImageFileDirectory_v2(), parallax, False 

4163 )[0] 

4164 

4165 self.fp.read(4) 

4166 camerainfo["Category"] = self.fp.read(2) 

4167 

4168 makernote = {0x1101: camerainfo} 

4169 self._ifds[tag] = makernote 

4170 else: 

4171 # Interop 

4172 ifd = self._get_ifd_dict(tag_data, tag) 

4173 if ifd is not None: 

4174 self._ifds[tag] = ifd 

4175 ifd = self._ifds.setdefault(tag, {}) 

4176 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4177 ifd = { 

4178 k: v 

4179 for (k, v) in ifd.items() 

4180 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4181 } 

4182 return ifd 

4183 

4184 def hide_offsets(self) -> None: 

4185 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4186 if tag in self: 

4187 self._hidden_data[tag] = self[tag] 

4188 del self[tag] 

4189 

4190 def __str__(self) -> str: 

4191 if self._info is not None: 

4192 # Load all keys into self._data 

4193 for tag in self._info: 

4194 self[tag] 

4195 

4196 return str(self._data) 

4197 

4198 def __len__(self) -> int: 

4199 keys = set(self._data) 

4200 if self._info is not None: 

4201 keys.update(self._info) 

4202 return len(keys) 

4203 

4204 def __getitem__(self, tag: int) -> Any: 

4205 if self._info is not None and tag not in self._data and tag in self._info: 

4206 self._data[tag] = self._fixup(self._info[tag]) 

4207 del self._info[tag] 

4208 return self._data[tag] 

4209 

4210 def __contains__(self, tag: object) -> bool: 

4211 return tag in self._data or (self._info is not None and tag in self._info) 

4212 

4213 def __setitem__(self, tag: int, value: Any) -> None: 

4214 if self._info is not None and tag in self._info: 

4215 del self._info[tag] 

4216 self._data[tag] = value 

4217 

4218 def __delitem__(self, tag: int) -> None: 

4219 if self._info is not None and tag in self._info: 

4220 del self._info[tag] 

4221 else: 

4222 del self._data[tag] 

4223 

4224 def __iter__(self) -> Iterator[int]: 

4225 keys = set(self._data) 

4226 if self._info is not None: 

4227 keys.update(self._info) 

4228 return iter(keys)