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

1725 statements  

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# the Image class wrapper 

6# 

7# partial release history: 

8# 1995-09-09 fl Created 

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

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

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

12# 2000-06-07 fl PIL release 1.1 

13# 2000-10-20 fl PIL release 1.1.1 

14# 2001-05-07 fl PIL release 1.1.2 

15# 2002-03-15 fl PIL release 1.1.3 

16# 2003-05-10 fl PIL release 1.1.4 

17# 2005-03-28 fl PIL release 1.1.5 

18# 2006-12-02 fl PIL release 1.1.6 

19# 2009-11-15 fl PIL release 1.1.7 

20# 

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

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

23# 

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

25# 

26 

27from __future__ import annotations 

28 

29import abc 

30import atexit 

31import builtins 

32import io 

33import logging 

34import math 

35import os 

36import re 

37import struct 

38import sys 

39import tempfile 

40import warnings 

41from collections.abc import MutableMapping 

42from enum import IntEnum 

43from typing import IO, Protocol, cast 

44 

45# VERSION was removed in Pillow 6.0.0. 

46# PILLOW_VERSION was removed in Pillow 9.0.0. 

47# Use __version__ instead. 

48from . import ( 

49 ExifTags, 

50 ImageMode, 

51 TiffTags, 

52 UnidentifiedImageError, 

53 __version__, 

54 _plugins, 

55) 

56from ._binary import i32le, o32be, o32le 

57from ._deprecate import deprecate 

58from ._util import DeferredError, is_path 

59 

60ElementTree: ModuleType | None 

61try: 

62 from defusedxml import ElementTree 

63except ImportError: 

64 ElementTree = None 

65 

66TYPE_CHECKING = False 

67if TYPE_CHECKING: 

68 from collections.abc import Callable, Iterator, Sequence 

69 from types import ModuleType 

70 from typing import Any, Literal 

71 

72logger = logging.getLogger(__name__) 

73 

74 

75class DecompressionBombWarning(RuntimeWarning): 

76 pass 

77 

78 

79class DecompressionBombError(Exception): 

80 pass 

81 

82 

83WARN_POSSIBLE_FORMATS: bool = False 

84 

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

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

87 

88 

89try: 

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

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

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

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

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

95 from . import _imaging as core 

96 

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

98 msg = ( 

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

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

101 f"Pillow version: {__version__}" 

102 ) 

103 raise ImportError(msg) 

104 

105except ImportError as v: 

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

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

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

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

110 # possible. 

111 warnings.warn( 

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

113 RuntimeWarning, 

114 ) 

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

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

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

118 # see docs/porting.rst 

119 raise 

120 

121 

122# 

123# Constants 

124 

125 

126# transpose 

127class Transpose(IntEnum): 

128 FLIP_LEFT_RIGHT = 0 

129 FLIP_TOP_BOTTOM = 1 

130 ROTATE_90 = 2 

131 ROTATE_180 = 3 

132 ROTATE_270 = 4 

133 TRANSPOSE = 5 

134 TRANSVERSE = 6 

135 

136 

137# transforms (also defined in Imaging.h) 

138class Transform(IntEnum): 

139 AFFINE = 0 

140 EXTENT = 1 

141 PERSPECTIVE = 2 

142 QUAD = 3 

143 MESH = 4 

144 

145 

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

147class Resampling(IntEnum): 

148 NEAREST = 0 

149 BOX = 4 

150 BILINEAR = 2 

151 HAMMING = 5 

152 BICUBIC = 3 

153 LANCZOS = 1 

154 

155 

156_filters_support = { 

157 Resampling.BOX: 0.5, 

158 Resampling.BILINEAR: 1.0, 

159 Resampling.HAMMING: 1.0, 

160 Resampling.BICUBIC: 2.0, 

161 Resampling.LANCZOS: 3.0, 

162} 

163 

164 

165# dithers 

166class Dither(IntEnum): 

167 NONE = 0 

168 ORDERED = 1 # Not yet implemented 

169 RASTERIZE = 2 # Not yet implemented 

170 FLOYDSTEINBERG = 3 # default 

171 

172 

173# palettes/quantizers 

174class Palette(IntEnum): 

175 WEB = 0 

176 ADAPTIVE = 1 

177 

178 

179class Quantize(IntEnum): 

180 MEDIANCUT = 0 

181 MAXCOVERAGE = 1 

182 FASTOCTREE = 2 

183 LIBIMAGEQUANT = 3 

184 

185 

186module = sys.modules[__name__] 

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

188 for item in enum: 

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

190 

191 

192if hasattr(core, "DEFAULT_STRATEGY"): 

193 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

194 FILTERED = core.FILTERED 

195 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

196 RLE = core.RLE 

197 FIXED = core.FIXED 

198 

199 

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

201# Registries 

202 

203TYPE_CHECKING = False 

204if TYPE_CHECKING: 

205 import mmap 

206 from xml.etree.ElementTree import Element 

207 

208 from IPython.lib.pretty import PrettyPrinter 

209 

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

211 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath 

212ID: list[str] = [] 

213OPEN: dict[ 

214 str, 

215 tuple[ 

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

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

218 ], 

219] = {} 

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

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

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

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

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

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

226 

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

228# Modes 

229 

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

231 

232 

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

234 m = ImageMode.getmode(im.mode) 

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

236 extra = len(m.bands) 

237 if extra != 1: 

238 shape += (extra,) 

239 return shape, m.typestr 

240 

241 

242MODES = [ 

243 "1", 

244 "CMYK", 

245 "F", 

246 "HSV", 

247 "I", 

248 "I;16", 

249 "I;16B", 

250 "I;16L", 

251 "I;16N", 

252 "L", 

253 "LA", 

254 "La", 

255 "LAB", 

256 "P", 

257 "PA", 

258 "RGB", 

259 "RGBA", 

260 "RGBa", 

261 "RGBX", 

262 "YCbCr", 

263] 

264 

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

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

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

268 

269 

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

271 """ 

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

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

274 contain color data. 

275 

276 :param mode: Input mode. 

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

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

279 """ 

280 return ImageMode.getmode(mode).basemode 

281 

282 

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

284 """ 

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

286 single-layer mode suitable for storing individual bands. 

287 

288 :param mode: Input mode. 

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

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

291 """ 

292 return ImageMode.getmode(mode).basetype 

293 

294 

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

296 """ 

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

298 a tuple containing the names of individual bands (use 

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

300 individual band. 

301 

302 :param mode: Input mode. 

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

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

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

306 """ 

307 return ImageMode.getmode(mode).bands 

308 

309 

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

311 """ 

312 Gets the number of individual bands for this mode. 

313 

314 :param mode: Input mode. 

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

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

317 """ 

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

319 

320 

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

322# Helpers 

323 

324_initialized = 0 

325 

326 

327def preinit() -> None: 

328 """ 

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

330 

331 It is called when opening or saving images. 

332 """ 

333 

334 global _initialized 

335 if _initialized >= 1: 

336 return 

337 

338 try: 

339 from . import BmpImagePlugin 

340 

341 assert BmpImagePlugin 

342 except ImportError: 

343 pass 

344 try: 

345 from . import GifImagePlugin 

346 

347 assert GifImagePlugin 

348 except ImportError: 

349 pass 

350 try: 

351 from . import JpegImagePlugin 

352 

353 assert JpegImagePlugin 

354 except ImportError: 

355 pass 

356 try: 

357 from . import PpmImagePlugin 

358 

359 assert PpmImagePlugin 

360 except ImportError: 

361 pass 

362 try: 

363 from . import PngImagePlugin 

364 

365 assert PngImagePlugin 

366 except ImportError: 

367 pass 

368 

369 _initialized = 1 

370 

371 

372def init() -> bool: 

373 """ 

374 Explicitly initializes the Python Imaging Library. This function 

375 loads all available file format drivers. 

376 

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

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

379 """ 

380 

381 global _initialized 

382 if _initialized >= 2: 

383 return False 

384 

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

386 for plugin in _plugins: 

387 try: 

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

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

390 except ImportError as e: 

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

392 

393 if OPEN or SAVE: 

394 _initialized = 2 

395 return True 

396 return False 

397 

398 

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

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

401 

402 

403def _getdecoder( 

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

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

406 # tweak arguments 

407 if args is None: 

408 args = () 

409 elif not isinstance(args, tuple): 

410 args = (args,) 

411 

412 try: 

413 decoder = DECODERS[decoder_name] 

414 except KeyError: 

415 pass 

416 else: 

417 return decoder(mode, *args + extra) 

418 

419 try: 

420 # get decoder 

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

422 except AttributeError as e: 

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

424 raise OSError(msg) from e 

425 return decoder(mode, *args + extra) 

426 

427 

428def _getencoder( 

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

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

431 # tweak arguments 

432 if args is None: 

433 args = () 

434 elif not isinstance(args, tuple): 

435 args = (args,) 

436 

437 try: 

438 encoder = ENCODERS[encoder_name] 

439 except KeyError: 

440 pass 

441 else: 

442 return encoder(mode, *args + extra) 

443 

444 try: 

445 # get encoder 

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

447 except AttributeError as e: 

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

449 raise OSError(msg) from e 

450 return encoder(mode, *args + extra) 

451 

452 

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

454# Simple expression analyzer 

455 

456 

457class ImagePointTransform: 

458 """ 

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

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

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

462 """ 

463 

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

465 self.scale = scale 

466 self.offset = offset 

467 

468 def __neg__(self) -> ImagePointTransform: 

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

470 

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

472 if isinstance(other, ImagePointTransform): 

473 return ImagePointTransform( 

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

475 ) 

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

477 

478 __radd__ = __add__ 

479 

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

481 return self + -other 

482 

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

484 return other + -self 

485 

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

487 if isinstance(other, ImagePointTransform): 

488 return NotImplemented 

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

490 

491 __rmul__ = __mul__ 

492 

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

494 if isinstance(other, ImagePointTransform): 

495 return NotImplemented 

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

497 

498 

499def _getscaleoffset( 

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

501) -> tuple[float, float]: 

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

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

504 

505 

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

507# Implementation wrapper 

508 

509 

510class SupportsGetData(Protocol): 

511 def getdata( 

512 self, 

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

514 

515 

516class Image: 

517 """ 

518 This class represents an image object. To create 

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

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

521 directly. 

522 

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

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

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

526 """ 

527 

528 format: str | None = None 

529 format_description: str | None = None 

530 _close_exclusive_fp_after_loading = True 

531 

532 def __init__(self) -> None: 

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

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

535 self._mode = "" 

536 self._size = (0, 0) 

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

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

539 self.readonly = 0 

540 self._exif: Exif | None = None 

541 

542 @property 

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

544 if isinstance(self._im, DeferredError): 

545 raise self._im.ex 

546 assert self._im is not None 

547 return self._im 

548 

549 @im.setter 

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

551 self._im = im 

552 

553 @property 

554 def width(self) -> int: 

555 return self.size[0] 

556 

557 @property 

558 def height(self) -> int: 

559 return self.size[1] 

560 

561 @property 

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

563 return self._size 

564 

565 @property 

566 def mode(self) -> str: 

567 return self._mode 

568 

569 @property 

570 def readonly(self) -> int: 

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

572 

573 @readonly.setter 

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

575 self._readonly = readonly 

576 

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

578 new = Image() 

579 new.im = im 

580 new._mode = im.mode 

581 new._size = im.size 

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

583 if self.palette: 

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

585 else: 

586 from . import ImagePalette 

587 

588 new.palette = ImagePalette.ImagePalette() 

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

590 return new 

591 

592 # Context manager support 

593 def __enter__(self): 

594 return self 

595 

596 def __exit__(self, *args): 

597 from . import ImageFile 

598 

599 if isinstance(self, ImageFile.ImageFile): 

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

601 self._close_fp() 

602 self.fp = None 

603 

604 def close(self) -> None: 

605 """ 

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

607 The image data will be unusable afterward. 

608 

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

610 have not had their file read and closed by the 

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

612 more information. 

613 """ 

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

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

616 self.map.close() 

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

618 

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

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

621 # object is gone. 

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

623 

624 def _copy(self) -> None: 

625 self.load() 

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

627 self.readonly = 0 

628 

629 def _ensure_mutable(self) -> None: 

630 if self.readonly: 

631 self._copy() 

632 else: 

633 self.load() 

634 

635 def _dump( 

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

637 ) -> str: 

638 suffix = "" 

639 if format: 

640 suffix = f".{format}" 

641 

642 if not file: 

643 f, filename = tempfile.mkstemp(suffix) 

644 os.close(f) 

645 else: 

646 filename = file 

647 if not filename.endswith(suffix): 

648 filename = filename + suffix 

649 

650 self.load() 

651 

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

653 self.im.save_ppm(filename) 

654 else: 

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

656 

657 return filename 

658 

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

660 if self.__class__ is not other.__class__: 

661 return False 

662 assert isinstance(other, Image) 

663 return ( 

664 self.mode == other.mode 

665 and self.size == other.size 

666 and self.info == other.info 

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

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

669 ) 

670 

671 def __repr__(self) -> str: 

672 return ( 

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

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

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

676 ) 

677 

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

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

680 

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

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

683 p.text( 

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

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

686 ) 

687 

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

689 """Helper function for iPython display hook. 

690 

691 :param image_format: Image format. 

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

693 """ 

694 b = io.BytesIO() 

695 try: 

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

697 except Exception: 

698 return None 

699 return b.getvalue() 

700 

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

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

703 

704 :returns: PNG version of the image as bytes 

705 """ 

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

707 

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

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

710 

711 :returns: JPEG version of the image as bytes 

712 """ 

713 return self._repr_image("JPEG") 

714 

715 @property 

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

717 # numpy array interface support 

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

719 if self.mode == "1": 

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

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

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

723 else: 

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

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

726 return new 

727 

728 def __arrow_c_schema__(self) -> object: 

729 self.load() 

730 return self.im.__arrow_c_schema__() 

731 

732 def __arrow_c_array__( 

733 self, requested_schema: object | None = None 

734 ) -> tuple[object, object]: 

735 self.load() 

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

737 

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

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

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

741 

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

743 Image.__init__(self) 

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

745 self.info = info 

746 self._mode = mode 

747 self._size = size 

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

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

750 self.putpalette(palette) 

751 self.frombytes(data) 

752 

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

754 """ 

755 Return image as a bytes object. 

756 

757 .. warning:: 

758 

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

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

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

762 

763 :param encoder_name: What encoder to use. 

764 

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

766 To see how this packs pixel data into the returned 

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

768 

769 A list of C encoders can be seen under codecs 

770 section of the function array in 

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

772 within the relevant plugins. 

773 :param args: Extra arguments to the encoder. 

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

775 """ 

776 

777 encoder_args: Any = args 

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

779 # may pass tuple instead of argument list 

780 encoder_args = encoder_args[0] 

781 

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

783 encoder_args = self.mode 

784 

785 self.load() 

786 

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

788 return b"" 

789 

790 # unpack data 

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

792 e.setimage(self.im) 

793 

794 from . import ImageFile 

795 

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

797 

798 output = [] 

799 while True: 

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

801 output.append(data) 

802 if errcode: 

803 break 

804 if errcode < 0: 

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

806 raise RuntimeError(msg) 

807 

808 return b"".join(output) 

809 

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

811 """ 

812 Returns the image converted to an X11 bitmap. 

813 

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

815 

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

817 :returns: A string containing an X11 bitmap. 

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

819 """ 

820 

821 self.load() 

822 if self.mode != "1": 

823 msg = "not a bitmap" 

824 raise ValueError(msg) 

825 data = self.tobytes("xbm") 

826 return b"".join( 

827 [ 

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

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

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

831 data, 

832 b"};", 

833 ] 

834 ) 

835 

836 def frombytes( 

837 self, 

838 data: bytes | bytearray | SupportsArrayInterface, 

839 decoder_name: str = "raw", 

840 *args: Any, 

841 ) -> None: 

842 """ 

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

844 

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

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

847 """ 

848 

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

850 return 

851 

852 decoder_args: Any = args 

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

854 # may pass tuple instead of argument list 

855 decoder_args = decoder_args[0] 

856 

857 # default format 

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

859 decoder_args = self.mode 

860 

861 # unpack data 

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

863 d.setimage(self.im) 

864 s = d.decode(data) 

865 

866 if s[0] >= 0: 

867 msg = "not enough image data" 

868 raise ValueError(msg) 

869 if s[1] != 0: 

870 msg = "cannot decode image data" 

871 raise ValueError(msg) 

872 

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

874 """ 

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

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

877 Image class automatically loads an opened image when it is 

878 accessed for the first time. 

879 

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

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

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

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

884 

885 :returns: An image access object. 

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

887 """ 

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

889 # realize palette 

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

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

892 self.palette.dirty = 0 

893 self.palette.rawmode = None 

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

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

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

897 else: 

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

899 self.palette.mode = "RGBA" 

900 else: 

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

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

903 ) 

904 

905 if self._im is not None: 

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

907 return None 

908 

909 def verify(self) -> None: 

910 """ 

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

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

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

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

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

916 file. 

917 """ 

918 pass 

919 

920 def convert( 

921 self, 

922 mode: str | None = None, 

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

924 dither: Dither | None = None, 

925 palette: Palette = Palette.WEB, 

926 colors: int = 256, 

927 ) -> Image: 

928 """ 

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

930 method translates pixels through the palette. If mode is 

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

932 and the palette can be represented without a palette. 

933 

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

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

936 

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

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

939 

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

941 

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

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

944 dither to approximate the original image luminosity levels. If 

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

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

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

948 

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

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

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

952 

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

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

955 

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

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

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

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

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

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

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

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

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

965 :data:`Palette.ADAPTIVE`. 

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

967 palette. Defaults to 256. 

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

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

970 """ 

971 

972 self.load() 

973 

974 has_transparency = "transparency" in self.info 

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

976 # determine default mode 

977 if self.palette: 

978 mode = self.palette.mode 

979 else: 

980 mode = "RGB" 

981 if mode == "RGB" and has_transparency: 

982 mode = "RGBA" 

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

984 return self.copy() 

985 

986 if matrix: 

987 # matrix conversion 

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

989 msg = "illegal conversion" 

990 raise ValueError(msg) 

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

992 new_im = self._new(im) 

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

994 transparency = new_im.info["transparency"] 

995 

996 def convert_transparency( 

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

998 ) -> int: 

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

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

1001 

1002 if mode == "L": 

1003 transparency = convert_transparency(matrix, transparency) 

1004 elif len(mode) == 3: 

1005 transparency = tuple( 

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

1007 for i in range(len(transparency)) 

1008 ) 

1009 new_im.info["transparency"] = transparency 

1010 return new_im 

1011 

1012 if self.mode == "RGBA": 

1013 if mode == "P": 

1014 return self.quantize(colors) 

1015 elif mode == "PA": 

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

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

1018 p = rgb.quantize(colors) 

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

1020 

1021 trns = None 

1022 delete_trns = False 

1023 # transparency handling 

1024 if has_transparency: 

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

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

1027 ): 

1028 # Use transparent conversion to promote from transparent 

1029 # color to an alpha channel. 

1030 new_im = self._new( 

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

1032 ) 

1033 del new_im.info["transparency"] 

1034 return new_im 

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

1036 t = self.info["transparency"] 

1037 if isinstance(t, bytes): 

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

1039 warnings.warn( 

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

1041 "converted to RGBA images" 

1042 ) 

1043 delete_trns = True 

1044 else: 

1045 # get the new transparency color. 

1046 # use existing conversions 

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

1048 if self.mode == "P": 

1049 assert self.palette is not None 

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

1051 if isinstance(t, tuple): 

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

1053 assert trns_im.palette is not None 

1054 try: 

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

1056 except ValueError as e: 

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

1058 # If all 256 colors are in use, 

1059 # then there is no need for transparency 

1060 t = None 

1061 else: 

1062 raise ValueError(err) from e 

1063 if t is None: 

1064 trns = None 

1065 else: 

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

1067 

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

1069 trns_im = trns_im.convert(mode) 

1070 else: 

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

1072 # after quantization. 

1073 trns_im = trns_im.convert("RGB") 

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

1075 

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

1077 t = self.info["transparency"] 

1078 delete_trns = True 

1079 

1080 if isinstance(t, bytes): 

1081 self.im.putpalettealphas(t) 

1082 elif isinstance(t, int): 

1083 self.im.putpalettealpha(t, 0) 

1084 else: 

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

1086 raise ValueError(msg) 

1087 

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

1089 im = self.im.quantize(colors) 

1090 new_im = self._new(im) 

1091 from . import ImagePalette 

1092 

1093 new_im.palette = ImagePalette.ImagePalette( 

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

1095 ) 

1096 if delete_trns: 

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

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

1099 del new_im.info["transparency"] 

1100 if trns is not None: 

1101 try: 

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

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

1104 new_im, 

1105 ) 

1106 except Exception: 

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

1108 # transparency hanging around to mess us up. 

1109 del new_im.info["transparency"] 

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

1111 return new_im 

1112 

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

1114 im = self 

1115 if mode == "LAB": 

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

1117 im = im.convert("RGBA") 

1118 other_mode = im.mode 

1119 else: 

1120 other_mode = mode 

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

1122 from . import ImageCms 

1123 

1124 srgb = ImageCms.createProfile("sRGB") 

1125 lab = ImageCms.createProfile("LAB") 

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

1127 transform = ImageCms.buildTransform( 

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

1129 ) 

1130 return transform.apply(im) 

1131 

1132 # colorspace conversion 

1133 if dither is None: 

1134 dither = Dither.FLOYDSTEINBERG 

1135 

1136 try: 

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

1138 except ValueError: 

1139 try: 

1140 # normalize source image and try again 

1141 modebase = getmodebase(self.mode) 

1142 if modebase == self.mode: 

1143 raise 

1144 im = self.im.convert(modebase) 

1145 im = im.convert(mode, dither) 

1146 except KeyError as e: 

1147 msg = "illegal conversion" 

1148 raise ValueError(msg) from e 

1149 

1150 new_im = self._new(im) 

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

1152 from . import ImagePalette 

1153 

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

1155 if delete_trns: 

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

1157 del new_im.info["transparency"] 

1158 if trns is not None: 

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

1160 try: 

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

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

1163 ) 

1164 except ValueError as e: 

1165 del new_im.info["transparency"] 

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

1167 # If all 256 colors are in use, 

1168 # then there is no need for transparency 

1169 warnings.warn( 

1170 "Couldn't allocate palette entry for transparency" 

1171 ) 

1172 else: 

1173 new_im.info["transparency"] = trns 

1174 return new_im 

1175 

1176 def quantize( 

1177 self, 

1178 colors: int = 256, 

1179 method: int | None = None, 

1180 kmeans: int = 0, 

1181 palette: Image | None = None, 

1182 dither: Dither = Dither.FLOYDSTEINBERG, 

1183 ) -> Image: 

1184 """ 

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

1186 of colors. 

1187 

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

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

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

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

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

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

1194 ``feature="libimagequant"``). 

1195 

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

1197 

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

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

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

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

1202 :param palette: Quantize to the palette of given 

1203 :py:class:`PIL.Image.Image`. 

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

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

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

1207 (default). 

1208 :returns: A new image 

1209 """ 

1210 

1211 self.load() 

1212 

1213 if method is None: 

1214 # defaults: 

1215 method = Quantize.MEDIANCUT 

1216 if self.mode == "RGBA": 

1217 method = Quantize.FASTOCTREE 

1218 

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

1220 Quantize.FASTOCTREE, 

1221 Quantize.LIBIMAGEQUANT, 

1222 ): 

1223 # Caller specified an invalid mode. 

1224 msg = ( 

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

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

1227 ) 

1228 raise ValueError(msg) 

1229 

1230 if palette: 

1231 # use palette from reference image 

1232 palette.load() 

1233 if palette.mode != "P": 

1234 msg = "bad mode for palette image" 

1235 raise ValueError(msg) 

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

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

1238 raise ValueError(msg) 

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

1240 new_im = self._new(im) 

1241 assert palette.palette is not None 

1242 new_im.palette = palette.palette.copy() 

1243 return new_im 

1244 

1245 if kmeans < 0: 

1246 msg = "kmeans must not be negative" 

1247 raise ValueError(msg) 

1248 

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

1250 

1251 from . import ImagePalette 

1252 

1253 mode = im.im.getpalettemode() 

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

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

1256 

1257 return im 

1258 

1259 def copy(self) -> Image: 

1260 """ 

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

1262 into an image, but still retain the original. 

1263 

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

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

1266 """ 

1267 self.load() 

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

1269 

1270 __copy__ = copy 

1271 

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

1273 """ 

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

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

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

1277 

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

1279 

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

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

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

1283 """ 

1284 

1285 if box is None: 

1286 return self.copy() 

1287 

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

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

1290 raise ValueError(msg) 

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

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

1293 raise ValueError(msg) 

1294 

1295 self.load() 

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

1297 

1298 def _crop( 

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

1300 ) -> core.ImagingCore: 

1301 """ 

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

1303 

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

1305 includes additional sanity checks. 

1306 

1307 :param im: a core image object 

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

1309 :returns: A core image object. 

1310 """ 

1311 

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

1313 

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

1315 

1316 _decompression_bomb_check(absolute_values) 

1317 

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

1319 

1320 def draft( 

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

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

1323 """ 

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

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

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

1327 JPEG to grayscale while loading it. 

1328 

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

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

1331 

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

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

1334 effect. 

1335 

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

1337 currently implemented only for JPEG and MPO images. 

1338 

1339 :param mode: The requested mode. 

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

1341 (width, height). 

1342 """ 

1343 pass 

1344 

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

1346 """ 

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

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

1349 

1350 :param filter: Filter kernel. 

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

1352 

1353 from . import ImageFilter 

1354 

1355 self.load() 

1356 

1357 if callable(filter): 

1358 filter = filter() 

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

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

1361 raise TypeError(msg) 

1362 

1363 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1366 

1367 ims = [ 

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

1369 ] 

1370 return merge(self.mode, ims) 

1371 

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

1373 """ 

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

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

1376 

1377 :returns: A tuple containing band names. 

1378 :rtype: tuple 

1379 """ 

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

1381 

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

1383 """ 

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

1385 image. 

1386 

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

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

1389 Otherwise, trim pixels when all channels are zero. 

1390 Keyword-only argument. 

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

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

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

1394 method returns None. 

1395 

1396 """ 

1397 

1398 self.load() 

1399 return self.im.getbbox(alpha_only) 

1400 

1401 def getcolors( 

1402 self, maxcolors: int = 256 

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

1404 """ 

1405 Returns a list of colors used in this image. 

1406 

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

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

1409 return the index of the color in the palette. 

1410 

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

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

1413 256 colors. 

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

1415 """ 

1416 

1417 self.load() 

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

1419 h = self.im.histogram() 

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

1421 if len(out) > maxcolors: 

1422 return None 

1423 return out 

1424 return self.im.getcolors(maxcolors) 

1425 

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

1427 """ 

1428 Returns the contents of this image as a sequence object 

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

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

1431 line zero, and so on. 

1432 

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

1434 internal PIL data type, which only supports certain sequence 

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

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

1437 

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

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

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

1441 :returns: A sequence-like object. 

1442 """ 

1443 

1444 self.load() 

1445 if band is not None: 

1446 return self.im.getband(band) 

1447 return self.im # could be abused 

1448 

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

1450 """ 

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

1452 the image. 

1453 

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

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

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

1457 """ 

1458 

1459 self.load() 

1460 if self.im.bands > 1: 

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

1462 return self.im.getextrema() 

1463 

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

1465 """ 

1466 Returns a dictionary containing the XMP tags. 

1467 Requires defusedxml to be installed. 

1468 

1469 :returns: XMP tags in a dictionary. 

1470 """ 

1471 

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

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

1474 

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

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

1477 children = list(element) 

1478 if children: 

1479 for child in children: 

1480 name = get_name(child.tag) 

1481 child_value = get_value(child) 

1482 if name in value: 

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

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

1485 value[name].append(child_value) 

1486 else: 

1487 value[name] = child_value 

1488 elif value: 

1489 if element.text: 

1490 value["text"] = element.text 

1491 else: 

1492 return element.text 

1493 return value 

1494 

1495 if ElementTree is None: 

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

1497 return {} 

1498 if "xmp" not in self.info: 

1499 return {} 

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

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

1502 

1503 def getexif(self) -> Exif: 

1504 """ 

1505 Gets EXIF data from the image. 

1506 

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

1508 """ 

1509 if self._exif is None: 

1510 self._exif = Exif() 

1511 elif self._exif._loaded: 

1512 return self._exif 

1513 self._exif._loaded = True 

1514 

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

1516 if exif_info is None: 

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

1518 exif_info = bytes.fromhex( 

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

1520 ) 

1521 elif hasattr(self, "tag_v2"): 

1522 from . import TiffImagePlugin 

1523 

1524 assert isinstance(self, TiffImagePlugin.TiffImageFile) 

1525 self._exif.bigtiff = self.tag_v2._bigtiff 

1526 self._exif.endian = self.tag_v2._endian 

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

1528 if exif_info is not None: 

1529 self._exif.load(exif_info) 

1530 

1531 # XMP tags 

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

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

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

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

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

1537 if xmp_tags: 

1538 match = re.search(pattern, xmp_tags) 

1539 if match: 

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

1541 

1542 return self._exif 

1543 

1544 def _reload_exif(self) -> None: 

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

1546 return 

1547 self._exif._loaded = False 

1548 self.getexif() 

1549 

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

1551 from . import ImageFile 

1552 

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

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

1555 

1556 def getim(self) -> CapsuleType: 

1557 """ 

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

1559 

1560 :returns: A capsule object. 

1561 """ 

1562 

1563 self.load() 

1564 return self.im.ptr 

1565 

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

1567 """ 

1568 Returns the image palette as a list. 

1569 

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

1571 return the palette in its current mode. 

1572 

1573 .. versionadded:: 9.1.0 

1574 

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

1576 image has no palette. 

1577 """ 

1578 

1579 self.load() 

1580 try: 

1581 mode = self.im.getpalettemode() 

1582 except ValueError: 

1583 return None # no palette 

1584 if rawmode is None: 

1585 rawmode = mode 

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

1587 

1588 @property 

1589 def has_transparency_data(self) -> bool: 

1590 """ 

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

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

1593 in the info dictionary. 

1594 

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

1596 within are opaque. 

1597 

1598 :returns: A boolean. 

1599 """ 

1600 if ( 

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

1602 or "transparency" in self.info 

1603 ): 

1604 return True 

1605 if self.mode == "P": 

1606 assert self.palette is not None 

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

1608 return False 

1609 

1610 def apply_transparency(self) -> None: 

1611 """ 

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

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

1614 Otherwise, the image is unchanged. 

1615 """ 

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

1617 return 

1618 

1619 from . import ImagePalette 

1620 

1621 palette = self.getpalette("RGBA") 

1622 assert palette is not None 

1623 transparency = self.info["transparency"] 

1624 if isinstance(transparency, bytes): 

1625 for i, alpha in enumerate(transparency): 

1626 palette[i * 4 + 3] = alpha 

1627 else: 

1628 palette[transparency * 4 + 3] = 0 

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

1630 self.palette.dirty = 1 

1631 

1632 del self.info["transparency"] 

1633 

1634 def getpixel( 

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

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

1637 """ 

1638 Returns the pixel value at a given position. 

1639 

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

1641 :ref:`coordinate-system`. 

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

1643 this method returns a tuple. 

1644 """ 

1645 

1646 self.load() 

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

1648 

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

1650 """ 

1651 Get projection to x and y axes 

1652 

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

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

1655 """ 

1656 

1657 self.load() 

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

1659 return list(x), list(y) 

1660 

1661 def histogram( 

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

1663 ) -> list[int]: 

1664 """ 

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

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

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

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

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

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

1671 

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

1673 by this method. 

1674 

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

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

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

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

1679 

1680 :param mask: An optional mask. 

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

1682 :returns: A list containing pixel counts. 

1683 """ 

1684 self.load() 

1685 if mask: 

1686 mask.load() 

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

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

1689 return self.im.histogram( 

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

1691 ) 

1692 return self.im.histogram() 

1693 

1694 def entropy( 

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

1696 ) -> float: 

1697 """ 

1698 Calculates and returns the entropy for the image. 

1699 

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

1701 image by this method. 

1702 

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

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

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

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

1707 

1708 :param mask: An optional mask. 

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

1710 :returns: A float value representing the image entropy 

1711 """ 

1712 self.load() 

1713 if mask: 

1714 mask.load() 

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

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

1717 return self.im.entropy( 

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

1719 ) 

1720 return self.im.entropy() 

1721 

1722 def paste( 

1723 self, 

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

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

1726 mask: Image | None = None, 

1727 ) -> None: 

1728 """ 

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

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

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

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

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

1734 

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

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

1737 details). 

1738 

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

1740 containing pixel values. The method then fills the region 

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

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

1743 :ref:`colors` for more information. 

1744 

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

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

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

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

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

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

1751 channels if they have them. 

1752 

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

1754 combine images with respect to their alpha channels. 

1755 

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

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

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

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

1760 upper left corner. 

1761 

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

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

1764 is interpreted as a mask image. 

1765 :param mask: An optional mask image. 

1766 """ 

1767 

1768 if isinstance(box, Image): 

1769 if mask is not None: 

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

1771 raise ValueError(msg) 

1772 # abbreviated paste(im, mask) syntax 

1773 mask = box 

1774 box = None 

1775 

1776 if box is None: 

1777 box = (0, 0) 

1778 

1779 if len(box) == 2: 

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

1781 if isinstance(im, Image): 

1782 size = im.size 

1783 elif isinstance(mask, Image): 

1784 size = mask.size 

1785 else: 

1786 # FIXME: use self.size here? 

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

1788 raise ValueError(msg) 

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

1790 

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

1792 if isinstance(im, str): 

1793 from . import ImageColor 

1794 

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

1796 elif isinstance(im, Image): 

1797 im.load() 

1798 if self.mode != im.mode: 

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

1800 # should use an adapter for this! 

1801 im = im.convert(self.mode) 

1802 source = im.im 

1803 else: 

1804 source = im 

1805 

1806 self._ensure_mutable() 

1807 

1808 if mask: 

1809 mask.load() 

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

1811 else: 

1812 self.im.paste(source, box) 

1813 

1814 def alpha_composite( 

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

1816 ) -> None: 

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

1818 onto this image. 

1819 

1820 :param im: image to composite over this one 

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

1822 left corner in this (destination) image. 

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

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

1825 bottom) for the bounds of the source rectangle 

1826 

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

1828 """ 

1829 

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

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

1832 raise ValueError(msg) 

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

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

1835 raise ValueError(msg) 

1836 

1837 if len(source) == 4: 

1838 overlay_crop_box = tuple(source) 

1839 elif len(source) == 2: 

1840 overlay_crop_box = tuple(source) + im.size 

1841 else: 

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

1843 raise ValueError(msg) 

1844 

1845 if not len(dest) == 2: 

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

1847 raise ValueError(msg) 

1848 if min(source) < 0: 

1849 msg = "Source must be non-negative" 

1850 raise ValueError(msg) 

1851 

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

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

1854 overlay = im 

1855 else: 

1856 overlay = im.crop(overlay_crop_box) 

1857 

1858 # target for the paste 

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

1860 

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

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

1863 background = self 

1864 else: 

1865 background = self.crop(box) 

1866 

1867 result = alpha_composite(background, overlay) 

1868 self.paste(result, box) 

1869 

1870 def point( 

1871 self, 

1872 lut: ( 

1873 Sequence[float] 

1874 | NumpyArray 

1875 | Callable[[int], float] 

1876 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1877 | ImagePointHandler 

1878 ), 

1879 mode: str | None = None, 

1880 ) -> Image: 

1881 """ 

1882 Maps this image through a lookup table or function. 

1883 

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

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

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

1887 single argument. The function is called once for each 

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

1889 all bands of the image. 

1890 

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

1892 object:: 

1893 

1894 class Example(Image.ImagePointHandler): 

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

1896 # Return result 

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

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

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

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

1901 """ 

1902 

1903 self.load() 

1904 

1905 if isinstance(lut, ImagePointHandler): 

1906 return lut.point(self) 

1907 

1908 if callable(lut): 

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

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

1911 # check if the function can be used with point_transform 

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

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

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

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

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

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

1918 else: 

1919 flatLut = lut 

1920 

1921 if self.mode == "F": 

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

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

1924 raise ValueError(msg) 

1925 

1926 if mode != "F": 

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

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

1929 

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

1931 """ 

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

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

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

1935 

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

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

1938 """ 

1939 

1940 self._ensure_mutable() 

1941 

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

1943 # attempt to promote self to a matching alpha mode 

1944 try: 

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

1946 try: 

1947 self.im.setmode(mode) 

1948 except (AttributeError, ValueError) as e: 

1949 # do things the hard way 

1950 im = self.im.convert(mode) 

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

1952 msg = "alpha channel could not be added" 

1953 raise ValueError(msg) from e # sanity check 

1954 self.im = im 

1955 self._mode = self.im.mode 

1956 except KeyError as e: 

1957 msg = "illegal image mode" 

1958 raise ValueError(msg) from e 

1959 

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

1961 band = 1 

1962 else: 

1963 band = 3 

1964 

1965 if isinstance(alpha, Image): 

1966 # alpha layer 

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

1968 msg = "illegal image mode" 

1969 raise ValueError(msg) 

1970 alpha.load() 

1971 if alpha.mode == "1": 

1972 alpha = alpha.convert("L") 

1973 else: 

1974 # constant alpha 

1975 try: 

1976 self.im.fillband(band, alpha) 

1977 except (AttributeError, ValueError): 

1978 # do things the hard way 

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

1980 else: 

1981 return 

1982 

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

1984 

1985 def putdata( 

1986 self, 

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

1988 scale: float = 1.0, 

1989 offset: float = 0.0, 

1990 ) -> None: 

1991 """ 

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

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

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

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

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

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

1998 

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

2000 information about values. 

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

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

2003 """ 

2004 

2005 self._ensure_mutable() 

2006 

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

2008 

2009 def putpalette( 

2010 self, 

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

2012 rawmode: str = "RGB", 

2013 ) -> None: 

2014 """ 

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

2016 or "LA" image. 

2017 

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

2019 integer value for each channel in the raw mode. 

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

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

2022 index in the 256 colors. 

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

2024 containing red, green, blue and alpha values. 

2025 

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

2027 

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

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

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

2031 """ 

2032 from . import ImagePalette 

2033 

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

2035 msg = "illegal image mode" 

2036 raise ValueError(msg) 

2037 if isinstance(data, ImagePalette.ImagePalette): 

2038 if data.rawmode is not None: 

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

2040 else: 

2041 palette = ImagePalette.ImagePalette(palette=data.palette) 

2042 palette.dirty = 1 

2043 else: 

2044 if not isinstance(data, bytes): 

2045 data = bytes(data) 

2046 palette = ImagePalette.raw(rawmode, data) 

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

2048 self.palette = palette 

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

2050 self.load() # install new palette 

2051 

2052 def putpixel( 

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

2054 ) -> None: 

2055 """ 

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

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

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

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

2060 

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

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

2063 module instead. 

2064 

2065 See: 

2066 

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

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

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

2070 

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

2072 :ref:`coordinate-system`. 

2073 :param value: The pixel value. 

2074 """ 

2075 

2076 self._ensure_mutable() 

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 from . import ImageShow 

2637 

2638 ImageShow.show(self, title) 

2639 

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

2641 """ 

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

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

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

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

2646 blue). 

2647 

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

2649 method can be more convenient and faster. 

2650 

2651 :returns: A tuple containing bands. 

2652 """ 

2653 

2654 self.load() 

2655 if self.im.bands == 1: 

2656 return (self.copy(),) 

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

2658 

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

2660 """ 

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

2662 

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

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

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

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

2667 

2668 .. versionadded:: 4.3.0 

2669 """ 

2670 self.load() 

2671 

2672 if isinstance(channel, str): 

2673 try: 

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

2675 except ValueError as e: 

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

2677 raise ValueError(msg) from e 

2678 

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

2680 

2681 def tell(self) -> int: 

2682 """ 

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

2684 

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

2686 number of available frames. 

2687 

2688 :returns: Frame number, starting with 0. 

2689 """ 

2690 return 0 

2691 

2692 def thumbnail( 

2693 self, 

2694 size: tuple[float, float], 

2695 resample: Resampling = Resampling.BICUBIC, 

2696 reducing_gap: float | None = 2.0, 

2697 ) -> None: 

2698 """ 

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

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

2701 the given size. This method calculates an appropriate thumbnail 

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

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

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

2705 

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

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

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

2709 image. 

2710 

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

2712 (width, height). 

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

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

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

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

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

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

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

2720 :param reducing_gap: Apply optimization by resizing the image 

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

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

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

2724 Second, resizing using regular resampling. The last step 

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

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

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

2728 the closer the result to the fair resampling. 

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

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

2731 indistinguishable from fair resampling in most cases. 

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

2733 while still being faster in many cases). 

2734 :returns: None 

2735 """ 

2736 

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

2738 

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

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

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

2742 

2743 x, y = provided_size 

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

2745 return None 

2746 

2747 aspect = self.width / self.height 

2748 if x / y >= aspect: 

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

2750 else: 

2751 y = round_aspect( 

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

2753 ) 

2754 return x, y 

2755 

2756 preserved_size = preserve_aspect_ratio() 

2757 if preserved_size is None: 

2758 return 

2759 final_size = preserved_size 

2760 

2761 box = None 

2762 if reducing_gap is not None: 

2763 res = self.draft( 

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

2765 ) 

2766 if res is not None: 

2767 box = res[1] 

2768 

2769 if self.size != final_size: 

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

2771 

2772 self.im = im.im 

2773 self._size = final_size 

2774 self._mode = self.im.mode 

2775 

2776 self.readonly = 0 

2777 

2778 # FIXME: the different transform methods need further explanation 

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

2780 def transform( 

2781 self, 

2782 size: tuple[int, int], 

2783 method: Transform | ImageTransformHandler | SupportsGetData, 

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

2785 resample: int = Resampling.NEAREST, 

2786 fill: int = 1, 

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

2788 ) -> Image: 

2789 """ 

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

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

2792 to the new image using the given transform. 

2793 

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

2795 (width, height). 

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

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

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

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

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

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

2802 in one operation). 

2803 

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

2805 object:: 

2806 

2807 class Example(Image.ImageTransformHandler): 

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

2809 # Return result 

2810 

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

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

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

2814 

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

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

2817 

2818 class Example: 

2819 def getdata(self): 

2820 method = Image.Transform.EXTENT 

2821 data = (0, 0, 100, 100) 

2822 return method, data 

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

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

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

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

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

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

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

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

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

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

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

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

2835 transform in the output image. 

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

2837 """ 

2838 

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

2840 return ( 

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

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

2843 .convert(self.mode) 

2844 ) 

2845 

2846 if isinstance(method, ImageTransformHandler): 

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

2848 

2849 if hasattr(method, "getdata"): 

2850 # compatibility w. old-style transform objects 

2851 method, data = method.getdata() 

2852 

2853 if data is None: 

2854 msg = "missing method data" 

2855 raise ValueError(msg) 

2856 

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

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

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

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

2861 if method == Transform.MESH: 

2862 # list of quads 

2863 for box, quad in data: 

2864 im.__transformer( 

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

2866 ) 

2867 else: 

2868 im.__transformer( 

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

2870 ) 

2871 

2872 return im 

2873 

2874 def __transformer( 

2875 self, 

2876 box: tuple[int, int, int, int], 

2877 image: Image, 

2878 method: Transform, 

2879 data: Sequence[float], 

2880 resample: int = Resampling.NEAREST, 

2881 fill: bool = True, 

2882 ) -> None: 

2883 w = box[2] - box[0] 

2884 h = box[3] - box[1] 

2885 

2886 if method == Transform.AFFINE: 

2887 data = data[:6] 

2888 

2889 elif method == Transform.EXTENT: 

2890 # convert extent to an affine transform 

2891 x0, y0, x1, y1 = data 

2892 xs = (x1 - x0) / w 

2893 ys = (y1 - y0) / h 

2894 method = Transform.AFFINE 

2895 data = (xs, 0, x0, 0, ys, y0) 

2896 

2897 elif method == Transform.PERSPECTIVE: 

2898 data = data[:8] 

2899 

2900 elif method == Transform.QUAD: 

2901 # quadrilateral warp. data specifies the four corners 

2902 # given as NW, SW, SE, and NE. 

2903 nw = data[:2] 

2904 sw = data[2:4] 

2905 se = data[4:6] 

2906 ne = data[6:8] 

2907 x0, y0 = nw 

2908 As = 1.0 / w 

2909 At = 1.0 / h 

2910 data = ( 

2911 x0, 

2912 (ne[0] - x0) * As, 

2913 (sw[0] - x0) * At, 

2914 (se[0] - sw[0] - ne[0] + x0) * As * At, 

2915 y0, 

2916 (ne[1] - y0) * As, 

2917 (sw[1] - y0) * At, 

2918 (se[1] - sw[1] - ne[1] + y0) * As * At, 

2919 ) 

2920 

2921 else: 

2922 msg = "unknown transformation method" 

2923 raise ValueError(msg) 

2924 

2925 if resample not in ( 

2926 Resampling.NEAREST, 

2927 Resampling.BILINEAR, 

2928 Resampling.BICUBIC, 

2929 ): 

2930 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

2931 unusable: dict[int, str] = { 

2932 Resampling.BOX: "Image.Resampling.BOX", 

2933 Resampling.HAMMING: "Image.Resampling.HAMMING", 

2934 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

2935 } 

2936 msg = unusable[resample] + f" ({resample}) cannot be used." 

2937 else: 

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

2939 

2940 filters = [ 

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

2942 for filter in ( 

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

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

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

2946 ) 

2947 ] 

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

2949 raise ValueError(msg) 

2950 

2951 image.load() 

2952 

2953 self.load() 

2954 

2955 if image.mode in ("1", "P"): 

2956 resample = Resampling.NEAREST 

2957 

2958 self.im.transform(box, image.im, method, data, resample, fill) 

2959 

2960 def transpose(self, method: Transpose) -> Image: 

2961 """ 

2962 Transpose image (flip or rotate in 90 degree steps) 

2963 

2964 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

2965 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

2966 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

2967 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

2968 :returns: Returns a flipped or rotated copy of this image. 

2969 """ 

2970 

2971 self.load() 

2972 return self._new(self.im.transpose(method)) 

2973 

2974 def effect_spread(self, distance: int) -> Image: 

2975 """ 

2976 Randomly spread pixels in an image. 

2977 

2978 :param distance: Distance to spread pixels. 

2979 """ 

2980 self.load() 

2981 return self._new(self.im.effect_spread(distance)) 

2982 

2983 def toqimage(self) -> ImageQt.ImageQt: 

2984 """Returns a QImage copy of this image""" 

2985 from . import ImageQt 

2986 

2987 if not ImageQt.qt_is_installed: 

2988 msg = "Qt bindings are not installed" 

2989 raise ImportError(msg) 

2990 return ImageQt.toqimage(self) 

2991 

2992 def toqpixmap(self) -> ImageQt.QPixmap: 

2993 """Returns a QPixmap copy of this image""" 

2994 from . import ImageQt 

2995 

2996 if not ImageQt.qt_is_installed: 

2997 msg = "Qt bindings are not installed" 

2998 raise ImportError(msg) 

2999 return ImageQt.toqpixmap(self) 

3000 

3001 

3002# -------------------------------------------------------------------- 

3003# Abstract handlers. 

3004 

3005 

3006class ImagePointHandler(abc.ABC): 

3007 """ 

3008 Used as a mixin by point transforms 

3009 (for use with :py:meth:`~PIL.Image.Image.point`) 

3010 """ 

3011 

3012 @abc.abstractmethod 

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

3014 pass 

3015 

3016 

3017class ImageTransformHandler(abc.ABC): 

3018 """ 

3019 Used as a mixin by geometry transforms 

3020 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3021 """ 

3022 

3023 @abc.abstractmethod 

3024 def transform( 

3025 self, 

3026 size: tuple[int, int], 

3027 image: Image, 

3028 **options: Any, 

3029 ) -> Image: 

3030 pass 

3031 

3032 

3033# -------------------------------------------------------------------- 

3034# Factories 

3035 

3036 

3037def _check_size(size: Any) -> None: 

3038 """ 

3039 Common check to enforce type and sanity check on size tuples 

3040 

3041 :param size: Should be a 2 tuple of (width, height) 

3042 :returns: None, or raises a ValueError 

3043 """ 

3044 

3045 if not isinstance(size, (list, tuple)): 

3046 msg = "Size must be a list or tuple" 

3047 raise ValueError(msg) 

3048 if len(size) != 2: 

3049 msg = "Size must be a sequence of length 2" 

3050 raise ValueError(msg) 

3051 if size[0] < 0 or size[1] < 0: 

3052 msg = "Width and height must be >= 0" 

3053 raise ValueError(msg) 

3054 

3055 

3056def new( 

3057 mode: str, 

3058 size: tuple[int, int] | list[int], 

3059 color: float | tuple[float, ...] | str | None = 0, 

3060) -> Image: 

3061 """ 

3062 Creates a new image with the given mode and size. 

3063 

3064 :param mode: The mode to use for the new image. See: 

3065 :ref:`concept-modes`. 

3066 :param size: A 2-tuple, containing (width, height) in pixels. 

3067 :param color: What color to use for the image. Default is black. If given, 

3068 this should be a single integer or floating point value for single-band 

3069 modes, and a tuple for multi-band modes (one value per band). When 

3070 creating RGB or HSV images, you can also use color strings as supported 

3071 by the ImageColor module. See :ref:`colors` for more information. If the 

3072 color is None, the image is not initialised. 

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

3074 """ 

3075 

3076 _check_size(size) 

3077 

3078 if color is None: 

3079 # don't initialize 

3080 return Image()._new(core.new(mode, size)) 

3081 

3082 if isinstance(color, str): 

3083 # css3-style specifier 

3084 

3085 from . import ImageColor 

3086 

3087 color = ImageColor.getcolor(color, mode) 

3088 

3089 im = Image() 

3090 if ( 

3091 mode == "P" 

3092 and isinstance(color, (list, tuple)) 

3093 and all(isinstance(i, int) for i in color) 

3094 ): 

3095 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3096 if len(color_ints) == 3 or len(color_ints) == 4: 

3097 # RGB or RGBA value for a P image 

3098 from . import ImagePalette 

3099 

3100 im.palette = ImagePalette.ImagePalette() 

3101 color = im.palette.getcolor(color_ints) 

3102 return im._new(core.fill(mode, size, color)) 

3103 

3104 

3105def frombytes( 

3106 mode: str, 

3107 size: tuple[int, int], 

3108 data: bytes | bytearray | SupportsArrayInterface, 

3109 decoder_name: str = "raw", 

3110 *args: Any, 

3111) -> Image: 

3112 """ 

3113 Creates a copy of an image memory from pixel data in a buffer. 

3114 

3115 In its simplest form, this function takes three arguments 

3116 (mode, size, and unpacked pixel data). 

3117 

3118 You can also use any pixel decoder supported by PIL. For more 

3119 information on available decoders, see the section 

3120 :ref:`Writing Your Own File Codec <file-codecs>`. 

3121 

3122 Note that this function decodes pixel data only, not entire images. 

3123 If you have an entire image in a string, wrap it in a 

3124 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3125 it. 

3126 

3127 :param mode: The image mode. See: :ref:`concept-modes`. 

3128 :param size: The image size. 

3129 :param data: A byte buffer containing raw data for the given mode. 

3130 :param decoder_name: What decoder to use. 

3131 :param args: Additional parameters for the given decoder. 

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

3133 """ 

3134 

3135 _check_size(size) 

3136 

3137 im = new(mode, size) 

3138 if im.width != 0 and im.height != 0: 

3139 decoder_args: Any = args 

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

3141 # may pass tuple instead of argument list 

3142 decoder_args = decoder_args[0] 

3143 

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

3145 decoder_args = mode 

3146 

3147 im.frombytes(data, decoder_name, decoder_args) 

3148 return im 

3149 

3150 

3151def frombuffer( 

3152 mode: str, 

3153 size: tuple[int, int], 

3154 data: bytes | SupportsArrayInterface, 

3155 decoder_name: str = "raw", 

3156 *args: Any, 

3157) -> Image: 

3158 """ 

3159 Creates an image memory referencing pixel data in a byte buffer. 

3160 

3161 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3162 in the byte buffer, where possible. This means that changes to the 

3163 original buffer object are reflected in this image). Not all modes can 

3164 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3165 

3166 Note that this function decodes pixel data only, not entire images. 

3167 If you have an entire image file in a string, wrap it in a 

3168 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3169 

3170 The default parameters used for the "raw" decoder differs from that used for 

3171 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3172 future release. The current release issues a warning if you do this; to disable 

3173 the warning, you should provide the full set of parameters. See below for details. 

3174 

3175 :param mode: The image mode. See: :ref:`concept-modes`. 

3176 :param size: The image size. 

3177 :param data: A bytes or other buffer object containing raw 

3178 data for the given mode. 

3179 :param decoder_name: What decoder to use. 

3180 :param args: Additional parameters for the given decoder. For the 

3181 default encoder ("raw"), it's recommended that you provide the 

3182 full set of parameters:: 

3183 

3184 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3185 

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

3187 

3188 .. versionadded:: 1.1.4 

3189 """ 

3190 

3191 _check_size(size) 

3192 

3193 # may pass tuple instead of argument list 

3194 if len(args) == 1 and isinstance(args[0], tuple): 

3195 args = args[0] 

3196 

3197 if decoder_name == "raw": 

3198 if args == (): 

3199 args = mode, 0, 1 

3200 if args[0] in _MAPMODES: 

3201 im = new(mode, (0, 0)) 

3202 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3203 if mode == "P": 

3204 from . import ImagePalette 

3205 

3206 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3207 im.readonly = 1 

3208 return im 

3209 

3210 return frombytes(mode, size, data, decoder_name, args) 

3211 

3212 

3213class SupportsArrayInterface(Protocol): 

3214 """ 

3215 An object that has an ``__array_interface__`` dictionary. 

3216 """ 

3217 

3218 @property 

3219 def __array_interface__(self) -> dict[str, Any]: 

3220 raise NotImplementedError() 

3221 

3222 

3223class SupportsArrowArrayInterface(Protocol): 

3224 """ 

3225 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3226 data interface. 

3227 """ 

3228 

3229 def __arrow_c_array__( 

3230 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3231 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3232 raise NotImplementedError() 

3233 

3234 

3235def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3236 """ 

3237 Creates an image memory from an object exporting the array interface 

3238 (using the buffer protocol):: 

3239 

3240 from PIL import Image 

3241 import numpy as np 

3242 a = np.zeros((5, 5)) 

3243 im = Image.fromarray(a) 

3244 

3245 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3246 and :py:func:`~PIL.Image.frombuffer` is used. 

3247 

3248 In the case of NumPy, be aware that Pillow modes do not always correspond 

3249 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3250 32-bit signed integer pixels, and 32-bit floating point pixels. 

3251 

3252 Pillow images can also be converted to arrays:: 

3253 

3254 from PIL import Image 

3255 import numpy as np 

3256 im = Image.open("hopper.jpg") 

3257 a = np.asarray(im) 

3258 

3259 When converting Pillow images to arrays however, only pixel values are 

3260 transferred. This means that P and PA mode images will lose their palette. 

3261 

3262 :param obj: Object with array interface 

3263 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not 

3264 contain information about palettes or color spaces, this can be used to place 

3265 grayscale L mode data within a P mode image, or read RGB data as YCbCr for 

3266 example. 

3267 

3268 See: :ref:`concept-modes` for general information about modes. 

3269 :returns: An image object. 

3270 

3271 .. versionadded:: 1.1.6 

3272 """ 

3273 arr = obj.__array_interface__ 

3274 shape = arr["shape"] 

3275 ndim = len(shape) 

3276 strides = arr.get("strides", None) 

3277 try: 

3278 typekey = (1, 1) + shape[2:], arr["typestr"] 

3279 except KeyError as e: 

3280 if mode is not None: 

3281 typekey = None 

3282 color_modes: list[str] = [] 

3283 else: 

3284 msg = "Cannot handle this data type" 

3285 raise TypeError(msg) from e 

3286 if typekey is not None: 

3287 try: 

3288 typemode, rawmode, color_modes = _fromarray_typemap[typekey] 

3289 except KeyError as e: 

3290 typekey_shape, typestr = typekey 

3291 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3292 raise TypeError(msg) from e 

3293 if mode is not None: 

3294 if mode != typemode and mode not in color_modes: 

3295 deprecate("'mode' parameter for changing data types", 13) 

3296 rawmode = mode 

3297 else: 

3298 mode = typemode 

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, color modes 

3396 # first two members of shape are set to one 

3397 ((1, 1), "|b1"): ("1", "1;8", []), 

3398 ((1, 1), "|u1"): ("L", "L", ["P"]), 

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", ["La", "PA"]), 

3413 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), 

3414 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), 

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 or LA. 

3575 :param im2: The second image. Must have the same mode and size as the first image. 

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

3577 """ 

3578 

3579 im1.load() 

3580 im2.load() 

3581 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3582 

3583 

3584def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3585 """ 

3586 Creates a new image by interpolating between two input images, using 

3587 a constant alpha:: 

3588 

3589 out = image1 * (1.0 - alpha) + image2 * alpha 

3590 

3591 :param im1: The first image. 

3592 :param im2: The second image. Must have the same mode and size as 

3593 the first image. 

3594 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3595 copy of the first image is returned. If alpha is 1.0, a copy of 

3596 the second image is returned. There are no restrictions on the 

3597 alpha value. If necessary, the result is clipped to fit into 

3598 the allowed output range. 

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

3600 """ 

3601 

3602 im1.load() 

3603 im2.load() 

3604 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3605 

3606 

3607def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3608 """ 

3609 Create composite image by blending images using a transparency mask. 

3610 

3611 :param image1: The first image. 

3612 :param image2: The second image. Must have the same mode and 

3613 size as the first image. 

3614 :param mask: A mask image. This image can have mode 

3615 "1", "L", or "RGBA", and must have the same size as the 

3616 other two images. 

3617 """ 

3618 

3619 image = image2.copy() 

3620 image.paste(image1, None, mask) 

3621 return image 

3622 

3623 

3624def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3625 """ 

3626 Applies the function (which should take one argument) to each pixel 

3627 in the given image. If the image has more than one band, the same 

3628 function is applied to each band. Note that the function is 

3629 evaluated once for each possible pixel value, so you cannot use 

3630 random components or other generators. 

3631 

3632 :param image: The input image. 

3633 :param function: A function object, taking one integer argument. 

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

3635 """ 

3636 

3637 return image.point(args[0]) 

3638 

3639 

3640def merge(mode: str, bands: Sequence[Image]) -> Image: 

3641 """ 

3642 Merge a set of single band images into a new multiband image. 

3643 

3644 :param mode: The mode to use for the output image. See: 

3645 :ref:`concept-modes`. 

3646 :param bands: A sequence containing one single-band image for 

3647 each band in the output image. All bands must have the 

3648 same size. 

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

3650 """ 

3651 

3652 if getmodebands(mode) != len(bands) or "*" in mode: 

3653 msg = "wrong number of bands" 

3654 raise ValueError(msg) 

3655 for band in bands[1:]: 

3656 if band.mode != getmodetype(mode): 

3657 msg = "mode mismatch" 

3658 raise ValueError(msg) 

3659 if band.size != bands[0].size: 

3660 msg = "size mismatch" 

3661 raise ValueError(msg) 

3662 for band in bands: 

3663 band.load() 

3664 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3665 

3666 

3667# -------------------------------------------------------------------- 

3668# Plugin registry 

3669 

3670 

3671def register_open( 

3672 id: str, 

3673 factory: ( 

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

3675 | type[ImageFile.ImageFile] 

3676 ), 

3677 accept: Callable[[bytes], bool | str] | None = None, 

3678) -> None: 

3679 """ 

3680 Register an image file plugin. This function should not be used 

3681 in application code. 

3682 

3683 :param id: An image format identifier. 

3684 :param factory: An image file factory method. 

3685 :param accept: An optional function that can be used to quickly 

3686 reject images having another format. 

3687 """ 

3688 id = id.upper() 

3689 if id not in ID: 

3690 ID.append(id) 

3691 OPEN[id] = factory, accept 

3692 

3693 

3694def register_mime(id: str, mimetype: str) -> None: 

3695 """ 

3696 Registers an image MIME type by populating ``Image.MIME``. This function 

3697 should not be used in application code. 

3698 

3699 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3700 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3701 provide a different result for specific images. 

3702 

3703 :param id: An image format identifier. 

3704 :param mimetype: The image MIME type for this format. 

3705 """ 

3706 MIME[id.upper()] = mimetype 

3707 

3708 

3709def register_save( 

3710 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3711) -> None: 

3712 """ 

3713 Registers an image save function. This function should not be 

3714 used in application code. 

3715 

3716 :param id: An image format identifier. 

3717 :param driver: A function to save images in this format. 

3718 """ 

3719 SAVE[id.upper()] = driver 

3720 

3721 

3722def register_save_all( 

3723 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3724) -> None: 

3725 """ 

3726 Registers an image function to save all the frames 

3727 of a multiframe format. This function should not be 

3728 used in application code. 

3729 

3730 :param id: An image format identifier. 

3731 :param driver: A function to save images in this format. 

3732 """ 

3733 SAVE_ALL[id.upper()] = driver 

3734 

3735 

3736def register_extension(id: str, extension: str) -> None: 

3737 """ 

3738 Registers an image extension. This function should not be 

3739 used in application code. 

3740 

3741 :param id: An image format identifier. 

3742 :param extension: An extension used for this format. 

3743 """ 

3744 EXTENSION[extension.lower()] = id.upper() 

3745 

3746 

3747def register_extensions(id: str, extensions: list[str]) -> None: 

3748 """ 

3749 Registers image extensions. This function should not be 

3750 used in application code. 

3751 

3752 :param id: An image format identifier. 

3753 :param extensions: A list of extensions used for this format. 

3754 """ 

3755 for extension in extensions: 

3756 register_extension(id, extension) 

3757 

3758 

3759def registered_extensions() -> dict[str, str]: 

3760 """ 

3761 Returns a dictionary containing all file extensions belonging 

3762 to registered plugins 

3763 """ 

3764 init() 

3765 return EXTENSION 

3766 

3767 

3768def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3769 """ 

3770 Registers an image decoder. This function should not be 

3771 used in application code. 

3772 

3773 :param name: The name of the decoder 

3774 :param decoder: An ImageFile.PyDecoder object 

3775 

3776 .. versionadded:: 4.1.0 

3777 """ 

3778 DECODERS[name] = decoder 

3779 

3780 

3781def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3782 """ 

3783 Registers an image encoder. This function should not be 

3784 used in application code. 

3785 

3786 :param name: The name of the encoder 

3787 :param encoder: An ImageFile.PyEncoder object 

3788 

3789 .. versionadded:: 4.1.0 

3790 """ 

3791 ENCODERS[name] = encoder 

3792 

3793 

3794# -------------------------------------------------------------------- 

3795# Simple display support. 

3796 

3797 

3798def _show(image: Image, **options: Any) -> None: 

3799 from . import ImageShow 

3800 

3801 deprecate("Image._show", 13, "ImageShow.show") 

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 if tag in self._ifds: 

4224 del self._ifds[tag] 

4225 

4226 def __iter__(self) -> Iterator[int]: 

4227 keys = set(self._data) 

4228 if self._info is not None: 

4229 keys.update(self._info) 

4230 return iter(keys)