Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/pillow-11.0.0-py3.10-linux-x86_64.egg/PIL/Image.py: 24%

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

1721 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 Callable, Iterator, MutableMapping, Sequence 

42from enum import IntEnum 

43from types import ModuleType 

44from typing import ( 

45 IO, 

46 TYPE_CHECKING, 

47 Any, 

48 Literal, 

49 Protocol, 

50 cast, 

51) 

52 

53# VERSION was removed in Pillow 6.0.0. 

54# PILLOW_VERSION was removed in Pillow 9.0.0. 

55# Use __version__ instead. 

56from . import ( 

57 ExifTags, 

58 ImageMode, 

59 TiffTags, 

60 UnidentifiedImageError, 

61 __version__, 

62 _plugins, 

63) 

64from ._binary import i32le, o32be, o32le 

65from ._deprecate import deprecate 

66from ._util import DeferredError, is_path 

67 

68ElementTree: ModuleType | None 

69try: 

70 from defusedxml import ElementTree 

71except ImportError: 

72 ElementTree = None 

73 

74logger = logging.getLogger(__name__) 

75 

76 

77class DecompressionBombWarning(RuntimeWarning): 

78 pass 

79 

80 

81class DecompressionBombError(Exception): 

82 pass 

83 

84 

85WARN_POSSIBLE_FORMATS: bool = False 

86 

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

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

89 

90 

91try: 

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

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

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

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

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

97 from . import _imaging as core 

98 

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

100 msg = ( 

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

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

103 f"Pillow version: {__version__}" 

104 ) 

105 raise ImportError(msg) 

106 

107except ImportError as v: 

108 core = DeferredError.new(ImportError("The _imaging C module is not installed.")) 

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

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

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

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

113 # possible. 

114 warnings.warn( 

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

116 RuntimeWarning, 

117 ) 

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

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

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

121 # see docs/porting.rst 

122 raise 

123 

124 

125def isImageType(t: Any) -> TypeGuard[Image]: 

126 """ 

127 Checks if an object is an image object. 

128 

129 .. warning:: 

130 

131 This function is for internal use only. 

132 

133 :param t: object to check if it's an image 

134 :returns: True if the object is an image 

135 """ 

136 deprecate("Image.isImageType(im)", 12, "isinstance(im, Image.Image)") 

137 return hasattr(t, "im") 

138 

139 

140# 

141# Constants 

142 

143 

144# transpose 

145class Transpose(IntEnum): 

146 FLIP_LEFT_RIGHT = 0 

147 FLIP_TOP_BOTTOM = 1 

148 ROTATE_90 = 2 

149 ROTATE_180 = 3 

150 ROTATE_270 = 4 

151 TRANSPOSE = 5 

152 TRANSVERSE = 6 

153 

154 

155# transforms (also defined in Imaging.h) 

156class Transform(IntEnum): 

157 AFFINE = 0 

158 EXTENT = 1 

159 PERSPECTIVE = 2 

160 QUAD = 3 

161 MESH = 4 

162 

163 

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

165class Resampling(IntEnum): 

166 NEAREST = 0 

167 BOX = 4 

168 BILINEAR = 2 

169 HAMMING = 5 

170 BICUBIC = 3 

171 LANCZOS = 1 

172 

173 

174_filters_support = { 

175 Resampling.BOX: 0.5, 

176 Resampling.BILINEAR: 1.0, 

177 Resampling.HAMMING: 1.0, 

178 Resampling.BICUBIC: 2.0, 

179 Resampling.LANCZOS: 3.0, 

180} 

181 

182 

183# dithers 

184class Dither(IntEnum): 

185 NONE = 0 

186 ORDERED = 1 # Not yet implemented 

187 RASTERIZE = 2 # Not yet implemented 

188 FLOYDSTEINBERG = 3 # default 

189 

190 

191# palettes/quantizers 

192class Palette(IntEnum): 

193 WEB = 0 

194 ADAPTIVE = 1 

195 

196 

197class Quantize(IntEnum): 

198 MEDIANCUT = 0 

199 MAXCOVERAGE = 1 

200 FASTOCTREE = 2 

201 LIBIMAGEQUANT = 3 

202 

203 

204module = sys.modules[__name__] 

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

206 for item in enum: 

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

208 

209 

210if hasattr(core, "DEFAULT_STRATEGY"): 

211 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

212 FILTERED = core.FILTERED 

213 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

214 RLE = core.RLE 

215 FIXED = core.FIXED 

216 

217 

218# -------------------------------------------------------------------- 

219# Registries 

220 

221if TYPE_CHECKING: 

222 import mmap 

223 from xml.etree.ElementTree import Element 

224 

225 from IPython.lib.pretty import PrettyPrinter 

226 

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

228 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath, TypeGuard 

229ID: list[str] = [] 

230OPEN: dict[ 

231 str, 

232 tuple[ 

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

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

235 ], 

236] = {} 

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

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

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

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

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

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

243 

244# -------------------------------------------------------------------- 

245# Modes 

246 

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

248 

249 

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

251 m = ImageMode.getmode(im.mode) 

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

253 extra = len(m.bands) 

254 if extra != 1: 

255 shape += (extra,) 

256 return shape, m.typestr 

257 

258 

259MODES = [ 

260 "1", 

261 "CMYK", 

262 "F", 

263 "HSV", 

264 "I", 

265 "I;16", 

266 "I;16B", 

267 "I;16L", 

268 "I;16N", 

269 "L", 

270 "LA", 

271 "La", 

272 "LAB", 

273 "P", 

274 "PA", 

275 "RGB", 

276 "RGBA", 

277 "RGBa", 

278 "RGBX", 

279 "YCbCr", 

280] 

281 

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

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

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

285 

286 

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

288 """ 

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

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

291 contain color data. 

292 

293 :param mode: Input mode. 

294 :returns: "L" or "RGB". 

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

296 """ 

297 return ImageMode.getmode(mode).basemode 

298 

299 

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

301 """ 

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

303 single-layer mode suitable for storing individual bands. 

304 

305 :param mode: Input mode. 

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

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

308 """ 

309 return ImageMode.getmode(mode).basetype 

310 

311 

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

313 """ 

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

315 a tuple containing the names of individual bands (use 

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

317 individual band. 

318 

319 :param mode: Input mode. 

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

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

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

323 """ 

324 return ImageMode.getmode(mode).bands 

325 

326 

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

328 """ 

329 Gets the number of individual bands for this mode. 

330 

331 :param mode: Input mode. 

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

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

334 """ 

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

336 

337 

338# -------------------------------------------------------------------- 

339# Helpers 

340 

341_initialized = 0 

342 

343 

344def preinit() -> None: 

345 """ 

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

347 

348 It is called when opening or saving images. 

349 """ 

350 

351 global _initialized 

352 if _initialized >= 1: 

353 return 

354 

355 try: 

356 from . import BmpImagePlugin 

357 

358 assert BmpImagePlugin 

359 except ImportError: 

360 pass 

361 try: 

362 from . import GifImagePlugin 

363 

364 assert GifImagePlugin 

365 except ImportError: 

366 pass 

367 try: 

368 from . import JpegImagePlugin 

369 

370 assert JpegImagePlugin 

371 except ImportError: 

372 pass 

373 try: 

374 from . import PpmImagePlugin 

375 

376 assert PpmImagePlugin 

377 except ImportError: 

378 pass 

379 try: 

380 from . import PngImagePlugin 

381 

382 assert PngImagePlugin 

383 except ImportError: 

384 pass 

385 

386 _initialized = 1 

387 

388 

389def init() -> bool: 

390 """ 

391 Explicitly initializes the Python Imaging Library. This function 

392 loads all available file format drivers. 

393 

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

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

396 """ 

397 

398 global _initialized 

399 if _initialized >= 2: 

400 return False 

401 

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

403 for plugin in _plugins: 

404 try: 

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

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

407 except ImportError as e: 

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

409 

410 if OPEN or SAVE: 

411 _initialized = 2 

412 return True 

413 return False 

414 

415 

416# -------------------------------------------------------------------- 

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

418 

419 

420def _getdecoder( 

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

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

423 # tweak arguments 

424 if args is None: 

425 args = () 

426 elif not isinstance(args, tuple): 

427 args = (args,) 

428 

429 try: 

430 decoder = DECODERS[decoder_name] 

431 except KeyError: 

432 pass 

433 else: 

434 return decoder(mode, *args + extra) 

435 

436 try: 

437 # get decoder 

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

439 except AttributeError as e: 

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

441 raise OSError(msg) from e 

442 return decoder(mode, *args + extra) 

443 

444 

445def _getencoder( 

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

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

448 # tweak arguments 

449 if args is None: 

450 args = () 

451 elif not isinstance(args, tuple): 

452 args = (args,) 

453 

454 try: 

455 encoder = ENCODERS[encoder_name] 

456 except KeyError: 

457 pass 

458 else: 

459 return encoder(mode, *args + extra) 

460 

461 try: 

462 # get encoder 

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

464 except AttributeError as e: 

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

466 raise OSError(msg) from e 

467 return encoder(mode, *args + extra) 

468 

469 

470# -------------------------------------------------------------------- 

471# Simple expression analyzer 

472 

473 

474class ImagePointTransform: 

475 """ 

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

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

478 ``scale`` and ``offset`` is added. 

479 """ 

480 

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

482 self.scale = scale 

483 self.offset = offset 

484 

485 def __neg__(self) -> ImagePointTransform: 

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

487 

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

489 if isinstance(other, ImagePointTransform): 

490 return ImagePointTransform( 

491 self.scale + other.scale, self.offset + other.offset 

492 ) 

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

494 

495 __radd__ = __add__ 

496 

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

498 return self + -other 

499 

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

501 return other + -self 

502 

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

504 if isinstance(other, ImagePointTransform): 

505 return NotImplemented 

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

507 

508 __rmul__ = __mul__ 

509 

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

511 if isinstance(other, ImagePointTransform): 

512 return NotImplemented 

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

514 

515 

516def _getscaleoffset( 

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

518) -> tuple[float, float]: 

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

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

521 

522 

523# -------------------------------------------------------------------- 

524# Implementation wrapper 

525 

526 

527class SupportsGetData(Protocol): 

528 def getdata( 

529 self, 

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

531 

532 

533class Image: 

534 """ 

535 This class represents an image object. To create 

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

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

538 directly. 

539 

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

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

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

543 """ 

544 

545 format: str | None = None 

546 format_description: str | None = None 

547 _close_exclusive_fp_after_loading = True 

548 

549 def __init__(self) -> None: 

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

551 # FIXME: turn mode and size into delegating properties? 

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

553 self._mode = "" 

554 self._size = (0, 0) 

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

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

557 self.readonly = 0 

558 self._exif: Exif | None = None 

559 

560 @property 

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

562 if isinstance(self._im, DeferredError): 

563 raise self._im.ex 

564 assert self._im is not None 

565 return self._im 

566 

567 @im.setter 

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

569 self._im = im 

570 

571 @property 

572 def width(self) -> int: 

573 return self.size[0] 

574 

575 @property 

576 def height(self) -> int: 

577 return self.size[1] 

578 

579 @property 

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

581 return self._size 

582 

583 @property 

584 def mode(self) -> str: 

585 return self._mode 

586 

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

588 new = Image() 

589 new.im = im 

590 new._mode = im.mode 

591 new._size = im.size 

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

593 if self.palette: 

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

595 else: 

596 from . import ImagePalette 

597 

598 new.palette = ImagePalette.ImagePalette() 

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

600 return new 

601 

602 # Context manager support 

603 def __enter__(self): 

604 return self 

605 

606 def _close_fp(self): 

607 if getattr(self, "_fp", False): 

608 if self._fp != self.fp: 

609 self._fp.close() 

610 self._fp = DeferredError(ValueError("Operation on closed image")) 

611 if self.fp: 

612 self.fp.close() 

613 

614 def __exit__(self, *args): 

615 if hasattr(self, "fp"): 

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

617 self._close_fp() 

618 self.fp = None 

619 

620 def close(self) -> None: 

621 """ 

622 Closes the file pointer, if possible. 

623 

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

625 The image data will be unusable afterward. 

626 

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

628 have not had their file read and closed by the 

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

630 more information. 

631 """ 

632 if hasattr(self, "fp"): 

633 try: 

634 self._close_fp() 

635 self.fp = None 

636 except Exception as msg: 

637 logger.debug("Error closing: %s", msg) 

638 

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

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

641 

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

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

644 # object is gone. 

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

646 

647 def _copy(self) -> None: 

648 self.load() 

649 self.im = self.im.copy() 

650 self.readonly = 0 

651 

652 def _ensure_mutable(self) -> None: 

653 if self.readonly: 

654 self._copy() 

655 else: 

656 self.load() 

657 

658 def _dump( 

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

660 ) -> str: 

661 suffix = "" 

662 if format: 

663 suffix = f".{format}" 

664 

665 if not file: 

666 f, filename = tempfile.mkstemp(suffix) 

667 os.close(f) 

668 else: 

669 filename = file 

670 if not filename.endswith(suffix): 

671 filename = filename + suffix 

672 

673 self.load() 

674 

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

676 self.im.save_ppm(filename) 

677 else: 

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

679 

680 return filename 

681 

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

683 if self.__class__ is not other.__class__: 

684 return False 

685 assert isinstance(other, Image) 

686 return ( 

687 self.mode == other.mode 

688 and self.size == other.size 

689 and self.info == other.info 

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

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

692 ) 

693 

694 def __repr__(self) -> str: 

695 return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( 

696 self.__class__.__module__, 

697 self.__class__.__name__, 

698 self.mode, 

699 self.size[0], 

700 self.size[1], 

701 id(self), 

702 ) 

703 

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

705 """IPython plain text display support""" 

706 

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

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

709 p.text( 

710 "<%s.%s image mode=%s size=%dx%d>" 

711 % ( 

712 self.__class__.__module__, 

713 self.__class__.__name__, 

714 self.mode, 

715 self.size[0], 

716 self.size[1], 

717 ) 

718 ) 

719 

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

721 """Helper function for iPython display hook. 

722 

723 :param image_format: Image format. 

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

725 """ 

726 b = io.BytesIO() 

727 try: 

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

729 except Exception: 

730 return None 

731 return b.getvalue() 

732 

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

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

735 

736 :returns: PNG version of the image as bytes 

737 """ 

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

739 

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

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

742 

743 :returns: JPEG version of the image as bytes 

744 """ 

745 return self._repr_image("JPEG") 

746 

747 @property 

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

749 # numpy array interface support 

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

751 if self.mode == "1": 

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

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

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

755 else: 

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

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

758 return new 

759 

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

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

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

763 

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

765 Image.__init__(self) 

766 info, mode, size, palette, data = state 

767 self.info = info 

768 self._mode = mode 

769 self._size = size 

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

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

772 self.putpalette(palette) 

773 self.frombytes(data) 

774 

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

776 """ 

777 Return image as a bytes object. 

778 

779 .. warning:: 

780 

781 This method returns the raw image data from the internal 

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

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

784 data. 

785 

786 :param encoder_name: What encoder to use. The default is to 

787 use the standard "raw" encoder. 

788 

789 A list of C encoders can be seen under 

790 codecs section of the function array in 

791 :file:`_imaging.c`. Python encoders are 

792 registered within the relevant plugins. 

793 :param args: Extra arguments to the encoder. 

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

795 """ 

796 

797 encoder_args: Any = args 

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

799 # may pass tuple instead of argument list 

800 encoder_args = encoder_args[0] 

801 

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

803 encoder_args = self.mode 

804 

805 self.load() 

806 

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

808 return b"" 

809 

810 # unpack data 

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

812 e.setimage(self.im) 

813 

814 bufsize = max(65536, self.size[0] * 4) # see RawEncode.c 

815 

816 output = [] 

817 while True: 

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

819 output.append(data) 

820 if errcode: 

821 break 

822 if errcode < 0: 

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

824 raise RuntimeError(msg) 

825 

826 return b"".join(output) 

827 

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

829 """ 

830 Returns the image converted to an X11 bitmap. 

831 

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

833 

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

835 :returns: A string containing an X11 bitmap. 

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

837 """ 

838 

839 self.load() 

840 if self.mode != "1": 

841 msg = "not a bitmap" 

842 raise ValueError(msg) 

843 data = self.tobytes("xbm") 

844 return b"".join( 

845 [ 

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

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

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

849 data, 

850 b"};", 

851 ] 

852 ) 

853 

854 def frombytes( 

855 self, 

856 data: bytes | bytearray | SupportsArrayInterface, 

857 decoder_name: str = "raw", 

858 *args: Any, 

859 ) -> None: 

860 """ 

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

862 

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

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

865 """ 

866 

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

868 return 

869 

870 decoder_args: Any = args 

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

872 # may pass tuple instead of argument list 

873 decoder_args = decoder_args[0] 

874 

875 # default format 

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

877 decoder_args = self.mode 

878 

879 # unpack data 

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

881 d.setimage(self.im) 

882 s = d.decode(data) 

883 

884 if s[0] >= 0: 

885 msg = "not enough image data" 

886 raise ValueError(msg) 

887 if s[1] != 0: 

888 msg = "cannot decode image data" 

889 raise ValueError(msg) 

890 

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

892 """ 

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

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

895 Image class automatically loads an opened image when it is 

896 accessed for the first time. 

897 

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

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

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

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

902 

903 :returns: An image access object. 

904 :rtype: :py:class:`.PixelAccess` 

905 """ 

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

907 # realize palette 

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

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

910 self.palette.dirty = 0 

911 self.palette.rawmode = None 

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

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

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

915 else: 

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

917 self.palette.mode = "RGBA" 

918 else: 

919 self.palette.palette = self.im.getpalette( 

920 self.palette.mode, self.palette.mode 

921 ) 

922 

923 if self._im is not None: 

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

925 return None 

926 

927 def verify(self) -> None: 

928 """ 

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

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

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

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

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

934 file. 

935 """ 

936 pass 

937 

938 def convert( 

939 self, 

940 mode: str | None = None, 

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

942 dither: Dither | None = None, 

943 palette: Palette = Palette.WEB, 

944 colors: int = 256, 

945 ) -> Image: 

946 """ 

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

948 method translates pixels through the palette. If mode is 

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

950 and the palette can be represented without a palette. 

951 

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

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

954 

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

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

957 

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

959 

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

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

962 dither to approximate the original image luminosity levels. If 

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

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

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

966 

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

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

969 and ``dither`` and ``palette`` are ignored. 

970 

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

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

973 

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

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

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

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

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

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

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

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

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

983 :data:`Palette.ADAPTIVE`. 

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

985 palette. Defaults to 256. 

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

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

988 """ 

989 

990 if mode in ("BGR;15", "BGR;16", "BGR;24"): 

991 deprecate(mode, 12) 

992 

993 self.load() 

994 

995 has_transparency = "transparency" in self.info 

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

997 # determine default mode 

998 if self.palette: 

999 mode = self.palette.mode 

1000 else: 

1001 mode = "RGB" 

1002 if mode == "RGB" and has_transparency: 

1003 mode = "RGBA" 

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

1005 return self.copy() 

1006 

1007 if matrix: 

1008 # matrix conversion 

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

1010 msg = "illegal conversion" 

1011 raise ValueError(msg) 

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

1013 new_im = self._new(im) 

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

1015 transparency = new_im.info["transparency"] 

1016 

1017 def convert_transparency( 

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

1019 ) -> int: 

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

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

1022 

1023 if mode == "L": 

1024 transparency = convert_transparency(matrix, transparency) 

1025 elif len(mode) == 3: 

1026 transparency = tuple( 

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

1028 for i in range(0, len(transparency)) 

1029 ) 

1030 new_im.info["transparency"] = transparency 

1031 return new_im 

1032 

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

1034 return self.quantize(colors) 

1035 

1036 trns = None 

1037 delete_trns = False 

1038 # transparency handling 

1039 if has_transparency: 

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

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

1042 ): 

1043 # Use transparent conversion to promote from transparent 

1044 # color to an alpha channel. 

1045 new_im = self._new( 

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

1047 ) 

1048 del new_im.info["transparency"] 

1049 return new_im 

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

1051 t = self.info["transparency"] 

1052 if isinstance(t, bytes): 

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

1054 warnings.warn( 

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

1056 "converted to RGBA images" 

1057 ) 

1058 delete_trns = True 

1059 else: 

1060 # get the new transparency color. 

1061 # use existing conversions 

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

1063 if self.mode == "P": 

1064 assert self.palette is not None 

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

1066 if isinstance(t, tuple): 

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

1068 assert trns_im.palette is not None 

1069 try: 

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

1071 except ValueError as e: 

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

1073 # If all 256 colors are in use, 

1074 # then there is no need for transparency 

1075 t = None 

1076 else: 

1077 raise ValueError(err) from e 

1078 if t is None: 

1079 trns = None 

1080 else: 

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

1082 

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

1084 trns_im = trns_im.convert(mode) 

1085 else: 

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

1087 # after quantization. 

1088 trns_im = trns_im.convert("RGB") 

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

1090 

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

1092 t = self.info["transparency"] 

1093 delete_trns = True 

1094 

1095 if isinstance(t, bytes): 

1096 self.im.putpalettealphas(t) 

1097 elif isinstance(t, int): 

1098 self.im.putpalettealpha(t, 0) 

1099 else: 

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

1101 raise ValueError(msg) 

1102 

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

1104 im = self.im.quantize(colors) 

1105 new_im = self._new(im) 

1106 from . import ImagePalette 

1107 

1108 new_im.palette = ImagePalette.ImagePalette( 

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

1110 ) 

1111 if delete_trns: 

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

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

1114 del new_im.info["transparency"] 

1115 if trns is not None: 

1116 try: 

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

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

1119 new_im, 

1120 ) 

1121 except Exception: 

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

1123 # transparency hanging around to mess us up. 

1124 del new_im.info["transparency"] 

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

1126 return new_im 

1127 

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

1129 im = self 

1130 if mode == "LAB": 

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

1132 im = im.convert("RGBA") 

1133 other_mode = im.mode 

1134 else: 

1135 other_mode = mode 

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

1137 from . import ImageCms 

1138 

1139 srgb = ImageCms.createProfile("sRGB") 

1140 lab = ImageCms.createProfile("LAB") 

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

1142 transform = ImageCms.buildTransform( 

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

1144 ) 

1145 return transform.apply(im) 

1146 

1147 # colorspace conversion 

1148 if dither is None: 

1149 dither = Dither.FLOYDSTEINBERG 

1150 

1151 try: 

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

1153 except ValueError: 

1154 try: 

1155 # normalize source image and try again 

1156 modebase = getmodebase(self.mode) 

1157 if modebase == self.mode: 

1158 raise 

1159 im = self.im.convert(modebase) 

1160 im = im.convert(mode, dither) 

1161 except KeyError as e: 

1162 msg = "illegal conversion" 

1163 raise ValueError(msg) from e 

1164 

1165 new_im = self._new(im) 

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

1167 from . import ImagePalette 

1168 

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

1170 if delete_trns: 

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

1172 del new_im.info["transparency"] 

1173 if trns is not None: 

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

1175 try: 

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

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

1178 ) 

1179 except ValueError as e: 

1180 del new_im.info["transparency"] 

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

1182 # If all 256 colors are in use, 

1183 # then there is no need for transparency 

1184 warnings.warn( 

1185 "Couldn't allocate palette entry for transparency" 

1186 ) 

1187 else: 

1188 new_im.info["transparency"] = trns 

1189 return new_im 

1190 

1191 def quantize( 

1192 self, 

1193 colors: int = 256, 

1194 method: int | None = None, 

1195 kmeans: int = 0, 

1196 palette: Image | None = None, 

1197 dither: Dither = Dither.FLOYDSTEINBERG, 

1198 ) -> Image: 

1199 """ 

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

1201 of colors. 

1202 

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

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

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

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

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

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

1209 ``feature="libimagequant"``). 

1210 

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

1212 

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

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

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

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

1217 :param palette: Quantize to the palette of given 

1218 :py:class:`PIL.Image.Image`. 

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

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

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

1222 (default). 

1223 :returns: A new image 

1224 """ 

1225 

1226 self.load() 

1227 

1228 if method is None: 

1229 # defaults: 

1230 method = Quantize.MEDIANCUT 

1231 if self.mode == "RGBA": 

1232 method = Quantize.FASTOCTREE 

1233 

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

1235 Quantize.FASTOCTREE, 

1236 Quantize.LIBIMAGEQUANT, 

1237 ): 

1238 # Caller specified an invalid mode. 

1239 msg = ( 

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

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

1242 ) 

1243 raise ValueError(msg) 

1244 

1245 if palette: 

1246 # use palette from reference image 

1247 palette.load() 

1248 if palette.mode != "P": 

1249 msg = "bad mode for palette image" 

1250 raise ValueError(msg) 

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

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

1253 raise ValueError(msg) 

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

1255 new_im = self._new(im) 

1256 assert palette.palette is not None 

1257 new_im.palette = palette.palette.copy() 

1258 return new_im 

1259 

1260 if kmeans < 0: 

1261 msg = "kmeans must not be negative" 

1262 raise ValueError(msg) 

1263 

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

1265 

1266 from . import ImagePalette 

1267 

1268 mode = im.im.getpalettemode() 

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

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

1271 

1272 return im 

1273 

1274 def copy(self) -> Image: 

1275 """ 

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

1277 into an image, but still retain the original. 

1278 

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

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

1281 """ 

1282 self.load() 

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

1284 

1285 __copy__ = copy 

1286 

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

1288 """ 

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

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

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

1292 

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

1294 

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

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

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

1298 """ 

1299 

1300 if box is None: 

1301 return self.copy() 

1302 

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

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

1305 raise ValueError(msg) 

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

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

1308 raise ValueError(msg) 

1309 

1310 self.load() 

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

1312 

1313 def _crop( 

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

1315 ) -> core.ImagingCore: 

1316 """ 

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

1318 

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

1320 includes additional sanity checks. 

1321 

1322 :param im: a core image object 

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

1324 :returns: A core image object. 

1325 """ 

1326 

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

1328 

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

1330 

1331 _decompression_bomb_check(absolute_values) 

1332 

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

1334 

1335 def draft( 

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

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

1338 """ 

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

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

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

1342 JPEG to grayscale while loading it. 

1343 

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

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

1346 

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

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

1349 effect. 

1350 

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

1352 currently implemented only for JPEG and MPO images. 

1353 

1354 :param mode: The requested mode. 

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

1356 (width, height). 

1357 """ 

1358 pass 

1359 

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

1361 if ymargin is None: 

1362 ymargin = xmargin 

1363 self.load() 

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

1365 

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

1367 """ 

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

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

1370 

1371 :param filter: Filter kernel. 

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

1373 

1374 from . import ImageFilter 

1375 

1376 self.load() 

1377 

1378 if callable(filter): 

1379 filter = filter() 

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

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

1382 raise TypeError(msg) 

1383 

1384 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1387 

1388 ims = [ 

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

1390 ] 

1391 return merge(self.mode, ims) 

1392 

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

1394 """ 

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

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

1397 

1398 :returns: A tuple containing band names. 

1399 :rtype: tuple 

1400 """ 

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

1402 

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

1404 """ 

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

1406 image. 

1407 

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

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

1410 Otherwise, trim pixels when all channels are zero. 

1411 Keyword-only argument. 

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

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

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

1415 method returns None. 

1416 

1417 """ 

1418 

1419 self.load() 

1420 return self.im.getbbox(alpha_only) 

1421 

1422 def getcolors( 

1423 self, maxcolors: int = 256 

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

1425 """ 

1426 Returns a list of colors used in this image. 

1427 

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

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

1430 return the index of the color in the palette. 

1431 

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

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

1434 256 colors. 

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

1436 """ 

1437 

1438 self.load() 

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

1440 h = self.im.histogram() 

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

1442 if len(out) > maxcolors: 

1443 return None 

1444 return out 

1445 return self.im.getcolors(maxcolors) 

1446 

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

1448 """ 

1449 Returns the contents of this image as a sequence object 

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

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

1452 line zero, and so on. 

1453 

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

1455 internal PIL data type, which only supports certain sequence 

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

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

1458 

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

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

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

1462 :returns: A sequence-like object. 

1463 """ 

1464 

1465 self.load() 

1466 if band is not None: 

1467 return self.im.getband(band) 

1468 return self.im # could be abused 

1469 

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

1471 """ 

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

1473 the image. 

1474 

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

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

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

1478 """ 

1479 

1480 self.load() 

1481 if self.im.bands > 1: 

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

1483 return self.im.getextrema() 

1484 

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

1486 """ 

1487 Returns a dictionary containing the XMP tags. 

1488 Requires defusedxml to be installed. 

1489 

1490 :returns: XMP tags in a dictionary. 

1491 """ 

1492 

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

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

1495 

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

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

1498 children = list(element) 

1499 if children: 

1500 for child in children: 

1501 name = get_name(child.tag) 

1502 child_value = get_value(child) 

1503 if name in value: 

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

1505 value[name] = [value[name]] 

1506 value[name].append(child_value) 

1507 else: 

1508 value[name] = child_value 

1509 elif value: 

1510 if element.text: 

1511 value["text"] = element.text 

1512 else: 

1513 return element.text 

1514 return value 

1515 

1516 if ElementTree is None: 

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

1518 return {} 

1519 if "xmp" not in self.info: 

1520 return {} 

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

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

1523 

1524 def getexif(self) -> Exif: 

1525 """ 

1526 Gets EXIF data from the image. 

1527 

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

1529 """ 

1530 if self._exif is None: 

1531 self._exif = Exif() 

1532 elif self._exif._loaded: 

1533 return self._exif 

1534 self._exif._loaded = True 

1535 

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

1537 if exif_info is None: 

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

1539 exif_info = bytes.fromhex( 

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

1541 ) 

1542 elif hasattr(self, "tag_v2"): 

1543 self._exif.bigtiff = self.tag_v2._bigtiff 

1544 self._exif.endian = self.tag_v2._endian 

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

1546 if exif_info is not None: 

1547 self._exif.load(exif_info) 

1548 

1549 # XMP tags 

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

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

1552 if xmp_tags: 

1553 match = re.search(r'tiff:Orientation(="|>)([0-9])', xmp_tags) 

1554 if match: 

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

1556 

1557 return self._exif 

1558 

1559 def _reload_exif(self) -> None: 

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

1561 return 

1562 self._exif._loaded = False 

1563 self.getexif() 

1564 

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

1566 child_images = [] 

1567 exif = self.getexif() 

1568 ifds = [] 

1569 if ExifTags.Base.SubIFDs in exif: 

1570 subifd_offsets = exif[ExifTags.Base.SubIFDs] 

1571 if subifd_offsets: 

1572 if not isinstance(subifd_offsets, tuple): 

1573 subifd_offsets = (subifd_offsets,) 

1574 for subifd_offset in subifd_offsets: 

1575 ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset)) 

1576 ifd1 = exif.get_ifd(ExifTags.IFD.IFD1) 

1577 if ifd1 and ifd1.get(513): 

1578 assert exif._info is not None 

1579 ifds.append((ifd1, exif._info.next)) 

1580 

1581 offset = None 

1582 for ifd, ifd_offset in ifds: 

1583 current_offset = self.fp.tell() 

1584 if offset is None: 

1585 offset = current_offset 

1586 

1587 fp = self.fp 

1588 if ifd is not None: 

1589 thumbnail_offset = ifd.get(513) 

1590 if thumbnail_offset is not None: 

1591 thumbnail_offset += getattr(self, "_exif_offset", 0) 

1592 self.fp.seek(thumbnail_offset) 

1593 data = self.fp.read(ifd.get(514)) 

1594 fp = io.BytesIO(data) 

1595 

1596 with open(fp) as im: 

1597 from . import TiffImagePlugin 

1598 

1599 if thumbnail_offset is None and isinstance( 

1600 im, TiffImagePlugin.TiffImageFile 

1601 ): 

1602 im._frame_pos = [ifd_offset] 

1603 im._seek(0) 

1604 im.load() 

1605 child_images.append(im) 

1606 

1607 if offset is not None: 

1608 self.fp.seek(offset) 

1609 return child_images 

1610 

1611 def getim(self) -> CapsuleType: 

1612 """ 

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

1614 

1615 :returns: A capsule object. 

1616 """ 

1617 

1618 self.load() 

1619 return self.im.ptr 

1620 

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

1622 """ 

1623 Returns the image palette as a list. 

1624 

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

1626 return the palette in its current mode. 

1627 

1628 .. versionadded:: 9.1.0 

1629 

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

1631 image has no palette. 

1632 """ 

1633 

1634 self.load() 

1635 try: 

1636 mode = self.im.getpalettemode() 

1637 except ValueError: 

1638 return None # no palette 

1639 if rawmode is None: 

1640 rawmode = mode 

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

1642 

1643 @property 

1644 def has_transparency_data(self) -> bool: 

1645 """ 

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

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

1648 in the info dictionary. 

1649 

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

1651 within are opaque. 

1652 

1653 :returns: A boolean. 

1654 """ 

1655 if ( 

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

1657 or "transparency" in self.info 

1658 ): 

1659 return True 

1660 if self.mode == "P": 

1661 assert self.palette is not None 

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

1663 return False 

1664 

1665 def apply_transparency(self) -> None: 

1666 """ 

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

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

1669 Otherwise, the image is unchanged. 

1670 """ 

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

1672 return 

1673 

1674 from . import ImagePalette 

1675 

1676 palette = self.getpalette("RGBA") 

1677 assert palette is not None 

1678 transparency = self.info["transparency"] 

1679 if isinstance(transparency, bytes): 

1680 for i, alpha in enumerate(transparency): 

1681 palette[i * 4 + 3] = alpha 

1682 else: 

1683 palette[transparency * 4 + 3] = 0 

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

1685 self.palette.dirty = 1 

1686 

1687 del self.info["transparency"] 

1688 

1689 def getpixel( 

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

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

1692 """ 

1693 Returns the pixel value at a given position. 

1694 

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

1696 :ref:`coordinate-system`. 

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

1698 this method returns a tuple. 

1699 """ 

1700 

1701 self.load() 

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

1703 

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

1705 """ 

1706 Get projection to x and y axes 

1707 

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

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

1710 """ 

1711 

1712 self.load() 

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

1714 return list(x), list(y) 

1715 

1716 def histogram( 

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

1718 ) -> list[int]: 

1719 """ 

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

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

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

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

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

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

1726 

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

1728 by this method. 

1729 

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

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

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

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

1734 

1735 :param mask: An optional mask. 

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

1737 :returns: A list containing pixel counts. 

1738 """ 

1739 self.load() 

1740 if mask: 

1741 mask.load() 

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

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

1744 return self.im.histogram( 

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

1746 ) 

1747 return self.im.histogram() 

1748 

1749 def entropy( 

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

1751 ) -> float: 

1752 """ 

1753 Calculates and returns the entropy for the image. 

1754 

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

1756 image by this method. 

1757 

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

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

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

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

1762 

1763 :param mask: An optional mask. 

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

1765 :returns: A float value representing the image entropy 

1766 """ 

1767 self.load() 

1768 if mask: 

1769 mask.load() 

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

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

1772 return self.im.entropy( 

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

1774 ) 

1775 return self.im.entropy() 

1776 

1777 def paste( 

1778 self, 

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

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

1781 mask: Image | None = None, 

1782 ) -> None: 

1783 """ 

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

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

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

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

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

1789 

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

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

1792 details). 

1793 

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

1795 containing pixel values. The method then fills the region 

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

1797 also use color strings as supported by the ImageColor module. 

1798 

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

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

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

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

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

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

1805 channels if they have them. 

1806 

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

1808 combine images with respect to their alpha channels. 

1809 

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

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

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

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

1814 upper left corner. 

1815 

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

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

1818 is interpreted as a mask image. 

1819 :param mask: An optional mask image. 

1820 """ 

1821 

1822 if isinstance(box, Image): 

1823 if mask is not None: 

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

1825 raise ValueError(msg) 

1826 # abbreviated paste(im, mask) syntax 

1827 mask = box 

1828 box = None 

1829 

1830 if box is None: 

1831 box = (0, 0) 

1832 

1833 if len(box) == 2: 

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

1835 if isinstance(im, Image): 

1836 size = im.size 

1837 elif isinstance(mask, Image): 

1838 size = mask.size 

1839 else: 

1840 # FIXME: use self.size here? 

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

1842 raise ValueError(msg) 

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

1844 

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

1846 if isinstance(im, str): 

1847 from . import ImageColor 

1848 

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

1850 elif isinstance(im, Image): 

1851 im.load() 

1852 if self.mode != im.mode: 

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

1854 # should use an adapter for this! 

1855 im = im.convert(self.mode) 

1856 source = im.im 

1857 else: 

1858 source = im 

1859 

1860 self._ensure_mutable() 

1861 

1862 if mask: 

1863 mask.load() 

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

1865 else: 

1866 self.im.paste(source, box) 

1867 

1868 def alpha_composite( 

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

1870 ) -> None: 

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

1872 onto this image. 

1873 

1874 :param im: image to composite over this one 

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

1876 left corner in this (destination) image. 

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

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

1879 bottom) for the bounds of the source rectangle 

1880 

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

1882 """ 

1883 

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

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

1886 raise ValueError(msg) 

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

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

1889 raise ValueError(msg) 

1890 

1891 if len(source) == 4: 

1892 overlay_crop_box = tuple(source) 

1893 elif len(source) == 2: 

1894 overlay_crop_box = tuple(source) + im.size 

1895 else: 

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

1897 raise ValueError(msg) 

1898 

1899 if not len(dest) == 2: 

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

1901 raise ValueError(msg) 

1902 if min(source) < 0: 

1903 msg = "Source must be non-negative" 

1904 raise ValueError(msg) 

1905 

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

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

1908 overlay = im 

1909 else: 

1910 overlay = im.crop(overlay_crop_box) 

1911 

1912 # target for the paste 

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

1914 

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

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

1917 background = self 

1918 else: 

1919 background = self.crop(box) 

1920 

1921 result = alpha_composite(background, overlay) 

1922 self.paste(result, box) 

1923 

1924 def point( 

1925 self, 

1926 lut: ( 

1927 Sequence[float] 

1928 | NumpyArray 

1929 | Callable[[int], float] 

1930 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1931 | ImagePointHandler 

1932 ), 

1933 mode: str | None = None, 

1934 ) -> Image: 

1935 """ 

1936 Maps this image through a lookup table or function. 

1937 

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

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

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

1941 single argument. The function is called once for each 

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

1943 all bands of the image. 

1944 

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

1946 object:: 

1947 

1948 class Example(Image.ImagePointHandler): 

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

1950 # Return result 

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

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

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

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

1955 """ 

1956 

1957 self.load() 

1958 

1959 if isinstance(lut, ImagePointHandler): 

1960 return lut.point(self) 

1961 

1962 if callable(lut): 

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

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

1965 # check if the function can be used with point_transform 

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

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

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

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

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

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

1972 else: 

1973 flatLut = lut 

1974 

1975 if self.mode == "F": 

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

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

1978 raise ValueError(msg) 

1979 

1980 if mode != "F": 

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

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

1983 

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

1985 """ 

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

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

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

1989 

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

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

1992 """ 

1993 

1994 self._ensure_mutable() 

1995 

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

1997 # attempt to promote self to a matching alpha mode 

1998 try: 

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

2000 try: 

2001 self.im.setmode(mode) 

2002 except (AttributeError, ValueError) as e: 

2003 # do things the hard way 

2004 im = self.im.convert(mode) 

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

2006 msg = "alpha channel could not be added" 

2007 raise ValueError(msg) from e # sanity check 

2008 self.im = im 

2009 self._mode = self.im.mode 

2010 except KeyError as e: 

2011 msg = "illegal image mode" 

2012 raise ValueError(msg) from e 

2013 

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

2015 band = 1 

2016 else: 

2017 band = 3 

2018 

2019 if isinstance(alpha, Image): 

2020 # alpha layer 

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

2022 msg = "illegal image mode" 

2023 raise ValueError(msg) 

2024 alpha.load() 

2025 if alpha.mode == "1": 

2026 alpha = alpha.convert("L") 

2027 else: 

2028 # constant alpha 

2029 try: 

2030 self.im.fillband(band, alpha) 

2031 except (AttributeError, ValueError): 

2032 # do things the hard way 

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

2034 else: 

2035 return 

2036 

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

2038 

2039 def putdata( 

2040 self, 

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

2042 scale: float = 1.0, 

2043 offset: float = 0.0, 

2044 ) -> None: 

2045 """ 

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

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

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

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

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

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

2052 

2053 :param data: A flattened sequence object. 

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

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

2056 """ 

2057 

2058 self._ensure_mutable() 

2059 

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

2061 

2062 def putpalette( 

2063 self, 

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

2065 rawmode: str = "RGB", 

2066 ) -> None: 

2067 """ 

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

2069 or "LA" image. 

2070 

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

2072 integer value for each channel in the raw mode. 

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

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

2075 index in the 256 colors. 

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

2077 containing red, green, blue and alpha values. 

2078 

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

2080 

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

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

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

2084 """ 

2085 from . import ImagePalette 

2086 

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

2088 msg = "illegal image mode" 

2089 raise ValueError(msg) 

2090 if isinstance(data, ImagePalette.ImagePalette): 

2091 if data.rawmode is not None: 

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

2093 else: 

2094 palette = ImagePalette.ImagePalette(palette=data.palette) 

2095 palette.dirty = 1 

2096 else: 

2097 if not isinstance(data, bytes): 

2098 data = bytes(data) 

2099 palette = ImagePalette.raw(rawmode, data) 

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

2101 self.palette = palette 

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

2103 self.load() # install new palette 

2104 

2105 def putpixel( 

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

2107 ) -> None: 

2108 """ 

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

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

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

2112 accepted for P and PA images. 

2113 

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

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

2116 module instead. 

2117 

2118 See: 

2119 

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

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

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

2123 

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

2125 :ref:`coordinate-system`. 

2126 :param value: The pixel value. 

2127 """ 

2128 

2129 if self.readonly: 

2130 self._copy() 

2131 self.load() 

2132 

2133 if ( 

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

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

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

2137 ): 

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

2139 if self.mode == "PA": 

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

2141 value = value[:3] 

2142 assert self.palette is not None 

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

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

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

2146 

2147 def remap_palette( 

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

2149 ) -> Image: 

2150 """ 

2151 Rewrites the image to reorder the palette. 

2152 

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

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

2155 is the identity transform. 

2156 :param source_palette: Bytes or None. 

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

2158 

2159 """ 

2160 from . import ImagePalette 

2161 

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

2163 msg = "illegal image mode" 

2164 raise ValueError(msg) 

2165 

2166 bands = 3 

2167 palette_mode = "RGB" 

2168 if source_palette is None: 

2169 if self.mode == "P": 

2170 self.load() 

2171 palette_mode = self.im.getpalettemode() 

2172 if palette_mode == "RGBA": 

2173 bands = 4 

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

2175 else: # L-mode 

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

2177 elif len(source_palette) > 768: 

2178 bands = 4 

2179 palette_mode = "RGBA" 

2180 

2181 palette_bytes = b"" 

2182 new_positions = [0] * 256 

2183 

2184 # pick only the used colors from the palette 

2185 for i, oldPosition in enumerate(dest_map): 

2186 palette_bytes += source_palette[ 

2187 oldPosition * bands : oldPosition * bands + bands 

2188 ] 

2189 new_positions[oldPosition] = i 

2190 

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

2192 

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

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

2195 # from palette 1 to palette 2. New_positions is 

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

2197 # palette 1 with any holes removed. 

2198 

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

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

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

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

2203 # sans palette thus converting the image bytes, then 

2204 # assigning the optimized RGB palette. 

2205 

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

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

2208 

2209 mapping_palette = bytearray(new_positions) 

2210 

2211 m_im = self.copy() 

2212 m_im._mode = "P" 

2213 

2214 m_im.palette = ImagePalette.ImagePalette( 

2215 palette_mode, palette=mapping_palette * bands 

2216 ) 

2217 # possibly set palette dirty, then 

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

2219 # or just force it. 

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

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

2222 

2223 m_im = m_im.convert("L") 

2224 

2225 m_im.putpalette(palette_bytes, palette_mode) 

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

2227 

2228 if "transparency" in self.info: 

2229 try: 

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

2231 except ValueError: 

2232 if "transparency" in m_im.info: 

2233 del m_im.info["transparency"] 

2234 

2235 return m_im 

2236 

2237 def _get_safe_box( 

2238 self, 

2239 size: tuple[int, int], 

2240 resample: Resampling, 

2241 box: tuple[float, float, float, float], 

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

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

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

2245 """ 

2246 filter_support = _filters_support[resample] - 0.5 

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

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

2249 support_x = filter_support * scale_x 

2250 support_y = filter_support * scale_y 

2251 

2252 return ( 

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

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

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

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

2257 ) 

2258 

2259 def resize( 

2260 self, 

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

2262 resample: int | None = None, 

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

2264 reducing_gap: float | None = None, 

2265 ) -> Image: 

2266 """ 

2267 Returns a resized copy of this image. 

2268 

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

2270 (width, height). 

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

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

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

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

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

2276 :py:data:`Resampling.NEAREST`. If the image mode is "BGR;15", 

2277 "BGR;16" or "BGR;24", then the default filter is 

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

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

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

2281 the source image region to be scaled. 

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

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

2284 :param reducing_gap: Apply optimization by resizing the image 

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

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

2287 Second, resizing using regular resampling. The last step 

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

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

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

2291 the closer the result to the fair resampling. 

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

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

2294 indistinguishable from fair resampling in most cases. 

2295 The default value is None (no optimization). 

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

2297 """ 

2298 

2299 if resample is None: 

2300 bgr = self.mode.startswith("BGR;") 

2301 resample = Resampling.NEAREST if bgr else Resampling.BICUBIC 

2302 elif resample not in ( 

2303 Resampling.NEAREST, 

2304 Resampling.BILINEAR, 

2305 Resampling.BICUBIC, 

2306 Resampling.LANCZOS, 

2307 Resampling.BOX, 

2308 Resampling.HAMMING, 

2309 ): 

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

2311 

2312 filters = [ 

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

2314 for filter in ( 

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

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

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

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

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

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

2321 ) 

2322 ] 

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

2324 raise ValueError(msg) 

2325 

2326 if reducing_gap is not None and reducing_gap < 1.0: 

2327 msg = "reducing_gap must be 1.0 or greater" 

2328 raise ValueError(msg) 

2329 

2330 if box is None: 

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

2332 

2333 size = tuple(size) 

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

2335 return self.copy() 

2336 

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

2338 resample = Resampling.NEAREST 

2339 

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

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

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

2343 return im.convert(self.mode) 

2344 

2345 self.load() 

2346 

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

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

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

2350 if factor_x > 1 or factor_y > 1: 

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

2352 factor = (factor_x, factor_y) 

2353 self = ( 

2354 self.reduce(factor, box=reduce_box) 

2355 if callable(self.reduce) 

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

2357 ) 

2358 box = ( 

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

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

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

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

2363 ) 

2364 

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

2366 

2367 def reduce( 

2368 self, 

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

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

2371 ) -> Image: 

2372 """ 

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

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

2375 the resulting size will be rounded up. 

2376 

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

2378 for width and height separately. 

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

2380 the source image region to be reduced. 

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

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

2383 """ 

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

2385 factor = (factor, factor) 

2386 

2387 if box is None: 

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

2389 

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

2391 return self.copy() 

2392 

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

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

2395 im = im.reduce(factor, box) 

2396 return im.convert(self.mode) 

2397 

2398 self.load() 

2399 

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

2401 

2402 def rotate( 

2403 self, 

2404 angle: float, 

2405 resample: Resampling = Resampling.NEAREST, 

2406 expand: int | bool = False, 

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

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

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

2410 ) -> Image: 

2411 """ 

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

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

2414 clockwise around its centre. 

2415 

2416 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2423 See :ref:`concept-filters`. 

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

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

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

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

2428 the center and no translation. 

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

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

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

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

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

2434 """ 

2435 

2436 angle = angle % 360.0 

2437 

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

2439 # translating or changing the center. 

2440 if not (center or translate): 

2441 if angle == 0: 

2442 return self.copy() 

2443 if angle == 180: 

2444 return self.transpose(Transpose.ROTATE_180) 

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

2446 return self.transpose( 

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

2448 ) 

2449 

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

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

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

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

2454 

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

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

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

2458 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2459 

2460 # The reverse matrix is thus: 

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

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

2463 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2464 

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

2466 # compensate for the expand flag. 

2467 

2468 w, h = self.size 

2469 

2470 if translate is None: 

2471 post_trans = (0, 0) 

2472 else: 

2473 post_trans = translate 

2474 if center is None: 

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

2476 

2477 angle = -math.radians(angle) 

2478 matrix = [ 

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

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

2481 0.0, 

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

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

2484 0.0, 

2485 ] 

2486 

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

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

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

2490 

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

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

2493 ) 

2494 matrix[2] += center[0] 

2495 matrix[5] += center[1] 

2496 

2497 if expand: 

2498 # calculate output size 

2499 xx = [] 

2500 yy = [] 

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

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

2503 xx.append(transformed_x) 

2504 yy.append(transformed_y) 

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

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

2507 

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

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

2510 # translation vector as new translation vector. 

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

2512 w, h = nw, nh 

2513 

2514 return self.transform( 

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

2516 ) 

2517 

2518 def save( 

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

2520 ) -> None: 

2521 """ 

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

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

2524 extension, if possible. 

2525 

2526 Keyword options can be used to provide additional instructions 

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

2528 silently ignored. The available options are described in the 

2529 :doc:`image format documentation 

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

2531 

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

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

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

2535 methods, and be opened in binary mode. 

2536 

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

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

2539 format to use is determined from the filename extension. 

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

2541 parameter should always be used. 

2542 :param params: Extra parameters to the image writer. 

2543 :returns: None 

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

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

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

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

2548 """ 

2549 

2550 filename: str | bytes = "" 

2551 open_fp = False 

2552 if is_path(fp): 

2553 filename = os.path.realpath(os.fspath(fp)) 

2554 open_fp = True 

2555 elif fp == sys.stdout: 

2556 try: 

2557 fp = sys.stdout.buffer 

2558 except AttributeError: 

2559 pass 

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

2561 # only set the name for metadata purposes 

2562 filename = os.path.realpath(os.fspath(fp.name)) 

2563 

2564 # may mutate self! 

2565 self._ensure_mutable() 

2566 

2567 save_all = params.pop("save_all", False) 

2568 self.encoderinfo = params 

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

2570 

2571 preinit() 

2572 

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

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

2575 

2576 if not format: 

2577 if ext not in EXTENSION: 

2578 init() 

2579 try: 

2580 format = EXTENSION[ext] 

2581 except KeyError as e: 

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

2583 raise ValueError(msg) from e 

2584 

2585 if format.upper() not in SAVE: 

2586 init() 

2587 if save_all: 

2588 save_handler = SAVE_ALL[format.upper()] 

2589 else: 

2590 save_handler = SAVE[format.upper()] 

2591 

2592 created = False 

2593 if open_fp: 

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

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

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

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

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

2599 else: 

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

2601 else: 

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

2603 

2604 try: 

2605 save_handler(self, fp, filename) 

2606 except Exception: 

2607 if open_fp: 

2608 fp.close() 

2609 if created: 

2610 try: 

2611 os.remove(filename) 

2612 except PermissionError: 

2613 pass 

2614 raise 

2615 if open_fp: 

2616 fp.close() 

2617 

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

2619 """ 

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

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

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

2623 library automatically seeks to frame 0. 

2624 

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

2626 

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

2628 number of available frames. 

2629 

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

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

2632 of the sequence. 

2633 """ 

2634 

2635 # overridden by file handlers 

2636 if frame != 0: 

2637 msg = "no more images in file" 

2638 raise EOFError(msg) 

2639 

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

2641 """ 

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

2643 

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

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

2646 

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

2648 PNG format. 

2649 

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

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

2652 

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

2654 

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

2656 

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

2658 """ 

2659 

2660 _show(self, title=title) 

2661 

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

2663 """ 

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

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

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

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

2668 blue). 

2669 

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

2671 method can be more convenient and faster. 

2672 

2673 :returns: A tuple containing bands. 

2674 """ 

2675 

2676 self.load() 

2677 if self.im.bands == 1: 

2678 return (self.copy(),) 

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

2680 

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

2682 """ 

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

2684 

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

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

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

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

2689 

2690 .. versionadded:: 4.3.0 

2691 """ 

2692 self.load() 

2693 

2694 if isinstance(channel, str): 

2695 try: 

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

2697 except ValueError as e: 

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

2699 raise ValueError(msg) from e 

2700 

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

2702 

2703 def tell(self) -> int: 

2704 """ 

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

2706 

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

2708 number of available frames. 

2709 

2710 :returns: Frame number, starting with 0. 

2711 """ 

2712 return 0 

2713 

2714 def thumbnail( 

2715 self, 

2716 size: tuple[float, float], 

2717 resample: Resampling = Resampling.BICUBIC, 

2718 reducing_gap: float | None = 2.0, 

2719 ) -> None: 

2720 """ 

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

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

2723 the given size. This method calculates an appropriate thumbnail 

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

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

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

2727 

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

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

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

2731 image. 

2732 

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

2734 (width, height). 

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

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

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

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

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

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

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

2742 :param reducing_gap: Apply optimization by resizing the image 

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

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

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

2746 Second, resizing using regular resampling. The last step 

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

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

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

2750 the closer the result to the fair resampling. 

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

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

2753 indistinguishable from fair resampling in most cases. 

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

2755 while still being faster in many cases). 

2756 :returns: None 

2757 """ 

2758 

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

2760 

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

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

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

2764 

2765 x, y = provided_size 

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

2767 return None 

2768 

2769 aspect = self.width / self.height 

2770 if x / y >= aspect: 

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

2772 else: 

2773 y = round_aspect( 

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

2775 ) 

2776 return x, y 

2777 

2778 preserved_size = preserve_aspect_ratio() 

2779 if preserved_size is None: 

2780 return 

2781 final_size = preserved_size 

2782 

2783 box = None 

2784 if reducing_gap is not None: 

2785 res = self.draft( 

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

2787 ) 

2788 if res is not None: 

2789 box = res[1] 

2790 

2791 if self.size != final_size: 

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

2793 

2794 self.im = im.im 

2795 self._size = final_size 

2796 self._mode = self.im.mode 

2797 

2798 self.readonly = 0 

2799 

2800 # FIXME: the different transform methods need further explanation 

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

2802 def transform( 

2803 self, 

2804 size: tuple[int, int], 

2805 method: Transform | ImageTransformHandler | SupportsGetData, 

2806 data: Sequence[Any] | None = None, 

2807 resample: int = Resampling.NEAREST, 

2808 fill: int = 1, 

2809 fillcolor: float | tuple[float, ...] | str | None = None, 

2810 ) -> Image: 

2811 """ 

2812 Transforms this image. This method creates a new image with the 

2813 given size, and the same mode as the original, and copies data 

2814 to the new image using the given transform. 

2815 

2816 :param size: The output size in pixels, as a 2-tuple: 

2817 (width, height). 

2818 :param method: The transformation method. This is one of 

2819 :py:data:`Transform.EXTENT` (cut out a rectangular subregion), 

2820 :py:data:`Transform.AFFINE` (affine transform), 

2821 :py:data:`Transform.PERSPECTIVE` (perspective transform), 

2822 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or 

2823 :py:data:`Transform.MESH` (map a number of source quadrilaterals 

2824 in one operation). 

2825 

2826 It may also be an :py:class:`~PIL.Image.ImageTransformHandler` 

2827 object:: 

2828 

2829 class Example(Image.ImageTransformHandler): 

2830 def transform(self, size, data, resample, fill=1): 

2831 # Return result 

2832 

2833 Implementations of :py:class:`~PIL.Image.ImageTransformHandler` 

2834 for some of the :py:class:`Transform` methods are provided 

2835 in :py:mod:`~PIL.ImageTransform`. 

2836 

2837 It may also be an object with a ``method.getdata`` method 

2838 that returns a tuple supplying new ``method`` and ``data`` values:: 

2839 

2840 class Example: 

2841 def getdata(self): 

2842 method = Image.Transform.EXTENT 

2843 data = (0, 0, 100, 100) 

2844 return method, data 

2845 :param data: Extra data to the transformation method. 

2846 :param resample: Optional resampling filter. It can be one of 

2847 :py:data:`Resampling.NEAREST` (use nearest neighbour), 

2848 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 

2849 environment), or :py:data:`Resampling.BICUBIC` (cubic spline 

2850 interpolation in a 4x4 environment). If omitted, or if the image 

2851 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. 

2852 See: :ref:`concept-filters`. 

2853 :param fill: If ``method`` is an 

2854 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of 

2855 the arguments passed to it. Otherwise, it is unused. 

2856 :param fillcolor: Optional fill color for the area outside the 

2857 transform in the output image. 

2858 :returns: An :py:class:`~PIL.Image.Image` object. 

2859 """ 

2860 

2861 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: 

2862 return ( 

2863 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2864 .transform(size, method, data, resample, fill, fillcolor) 

2865 .convert(self.mode) 

2866 ) 

2867 

2868 if isinstance(method, ImageTransformHandler): 

2869 return method.transform(size, self, resample=resample, fill=fill) 

2870 

2871 if hasattr(method, "getdata"): 

2872 # compatibility w. old-style transform objects 

2873 method, data = method.getdata() 

2874 

2875 if data is None: 

2876 msg = "missing method data" 

2877 raise ValueError(msg) 

2878 

2879 im = new(self.mode, size, fillcolor) 

2880 if self.mode == "P" and self.palette: 

2881 im.palette = self.palette.copy() 

2882 im.info = self.info.copy() 

2883 if method == Transform.MESH: 

2884 # list of quads 

2885 for box, quad in data: 

2886 im.__transformer( 

2887 box, self, Transform.QUAD, quad, resample, fillcolor is None 

2888 ) 

2889 else: 

2890 im.__transformer( 

2891 (0, 0) + size, self, method, data, resample, fillcolor is None 

2892 ) 

2893 

2894 return im 

2895 

2896 def __transformer( 

2897 self, 

2898 box: tuple[int, int, int, int], 

2899 image: Image, 

2900 method: Transform, 

2901 data: Sequence[float], 

2902 resample: int = Resampling.NEAREST, 

2903 fill: bool = True, 

2904 ) -> None: 

2905 w = box[2] - box[0] 

2906 h = box[3] - box[1] 

2907 

2908 if method == Transform.AFFINE: 

2909 data = data[:6] 

2910 

2911 elif method == Transform.EXTENT: 

2912 # convert extent to an affine transform 

2913 x0, y0, x1, y1 = data 

2914 xs = (x1 - x0) / w 

2915 ys = (y1 - y0) / h 

2916 method = Transform.AFFINE 

2917 data = (xs, 0, x0, 0, ys, y0) 

2918 

2919 elif method == Transform.PERSPECTIVE: 

2920 data = data[:8] 

2921 

2922 elif method == Transform.QUAD: 

2923 # quadrilateral warp. data specifies the four corners 

2924 # given as NW, SW, SE, and NE. 

2925 nw = data[:2] 

2926 sw = data[2:4] 

2927 se = data[4:6] 

2928 ne = data[6:8] 

2929 x0, y0 = nw 

2930 As = 1.0 / w 

2931 At = 1.0 / h 

2932 data = ( 

2933 x0, 

2934 (ne[0] - x0) * As, 

2935 (sw[0] - x0) * At, 

2936 (se[0] - sw[0] - ne[0] + x0) * As * At, 

2937 y0, 

2938 (ne[1] - y0) * As, 

2939 (sw[1] - y0) * At, 

2940 (se[1] - sw[1] - ne[1] + y0) * As * At, 

2941 ) 

2942 

2943 else: 

2944 msg = "unknown transformation method" 

2945 raise ValueError(msg) 

2946 

2947 if resample not in ( 

2948 Resampling.NEAREST, 

2949 Resampling.BILINEAR, 

2950 Resampling.BICUBIC, 

2951 ): 

2952 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

2953 unusable: dict[int, str] = { 

2954 Resampling.BOX: "Image.Resampling.BOX", 

2955 Resampling.HAMMING: "Image.Resampling.HAMMING", 

2956 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

2957 } 

2958 msg = unusable[resample] + f" ({resample}) cannot be used." 

2959 else: 

2960 msg = f"Unknown resampling filter ({resample})." 

2961 

2962 filters = [ 

2963 f"{filter[1]} ({filter[0]})" 

2964 for filter in ( 

2965 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

2966 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

2967 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

2968 ) 

2969 ] 

2970 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

2971 raise ValueError(msg) 

2972 

2973 image.load() 

2974 

2975 self.load() 

2976 

2977 if image.mode in ("1", "P"): 

2978 resample = Resampling.NEAREST 

2979 

2980 self.im.transform(box, image.im, method, data, resample, fill) 

2981 

2982 def transpose(self, method: Transpose) -> Image: 

2983 """ 

2984 Transpose image (flip or rotate in 90 degree steps) 

2985 

2986 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

2987 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

2988 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

2989 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

2990 :returns: Returns a flipped or rotated copy of this image. 

2991 """ 

2992 

2993 self.load() 

2994 return self._new(self.im.transpose(method)) 

2995 

2996 def effect_spread(self, distance: int) -> Image: 

2997 """ 

2998 Randomly spread pixels in an image. 

2999 

3000 :param distance: Distance to spread pixels. 

3001 """ 

3002 self.load() 

3003 return self._new(self.im.effect_spread(distance)) 

3004 

3005 def toqimage(self) -> ImageQt.ImageQt: 

3006 """Returns a QImage copy of this image""" 

3007 from . import ImageQt 

3008 

3009 if not ImageQt.qt_is_installed: 

3010 msg = "Qt bindings are not installed" 

3011 raise ImportError(msg) 

3012 return ImageQt.toqimage(self) 

3013 

3014 def toqpixmap(self) -> ImageQt.QPixmap: 

3015 """Returns a QPixmap copy of this image""" 

3016 from . import ImageQt 

3017 

3018 if not ImageQt.qt_is_installed: 

3019 msg = "Qt bindings are not installed" 

3020 raise ImportError(msg) 

3021 return ImageQt.toqpixmap(self) 

3022 

3023 

3024# -------------------------------------------------------------------- 

3025# Abstract handlers. 

3026 

3027 

3028class ImagePointHandler: 

3029 """ 

3030 Used as a mixin by point transforms 

3031 (for use with :py:meth:`~PIL.Image.Image.point`) 

3032 """ 

3033 

3034 @abc.abstractmethod 

3035 def point(self, im: Image) -> Image: 

3036 pass 

3037 

3038 

3039class ImageTransformHandler: 

3040 """ 

3041 Used as a mixin by geometry transforms 

3042 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3043 """ 

3044 

3045 @abc.abstractmethod 

3046 def transform( 

3047 self, 

3048 size: tuple[int, int], 

3049 image: Image, 

3050 **options: Any, 

3051 ) -> Image: 

3052 pass 

3053 

3054 

3055# -------------------------------------------------------------------- 

3056# Factories 

3057 

3058# 

3059# Debugging 

3060 

3061 

3062def _wedge() -> Image: 

3063 """Create grayscale wedge (for debugging only)""" 

3064 

3065 return Image()._new(core.wedge("L")) 

3066 

3067 

3068def _check_size(size: Any) -> None: 

3069 """ 

3070 Common check to enforce type and sanity check on size tuples 

3071 

3072 :param size: Should be a 2 tuple of (width, height) 

3073 :returns: None, or raises a ValueError 

3074 """ 

3075 

3076 if not isinstance(size, (list, tuple)): 

3077 msg = "Size must be a list or tuple" 

3078 raise ValueError(msg) 

3079 if len(size) != 2: 

3080 msg = "Size must be a sequence of length 2" 

3081 raise ValueError(msg) 

3082 if size[0] < 0 or size[1] < 0: 

3083 msg = "Width and height must be >= 0" 

3084 raise ValueError(msg) 

3085 

3086 

3087def new( 

3088 mode: str, 

3089 size: tuple[int, int] | list[int], 

3090 color: float | tuple[float, ...] | str | None = 0, 

3091) -> Image: 

3092 """ 

3093 Creates a new image with the given mode and size. 

3094 

3095 :param mode: The mode to use for the new image. See: 

3096 :ref:`concept-modes`. 

3097 :param size: A 2-tuple, containing (width, height) in pixels. 

3098 :param color: What color to use for the image. Default is black. 

3099 If given, this should be a single integer or floating point value 

3100 for single-band modes, and a tuple for multi-band modes (one value 

3101 per band). When creating RGB or HSV images, you can also use color 

3102 strings as supported by the ImageColor module. If the color is 

3103 None, the image is not initialised. 

3104 :returns: An :py:class:`~PIL.Image.Image` object. 

3105 """ 

3106 

3107 if mode in ("BGR;15", "BGR;16", "BGR;24"): 

3108 deprecate(mode, 12) 

3109 

3110 _check_size(size) 

3111 

3112 if color is None: 

3113 # don't initialize 

3114 return Image()._new(core.new(mode, size)) 

3115 

3116 if isinstance(color, str): 

3117 # css3-style specifier 

3118 

3119 from . import ImageColor 

3120 

3121 color = ImageColor.getcolor(color, mode) 

3122 

3123 im = Image() 

3124 if ( 

3125 mode == "P" 

3126 and isinstance(color, (list, tuple)) 

3127 and all(isinstance(i, int) for i in color) 

3128 ): 

3129 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3130 if len(color_ints) == 3 or len(color_ints) == 4: 

3131 # RGB or RGBA value for a P image 

3132 from . import ImagePalette 

3133 

3134 im.palette = ImagePalette.ImagePalette() 

3135 color = im.palette.getcolor(color_ints) 

3136 return im._new(core.fill(mode, size, color)) 

3137 

3138 

3139def frombytes( 

3140 mode: str, 

3141 size: tuple[int, int], 

3142 data: bytes | bytearray | SupportsArrayInterface, 

3143 decoder_name: str = "raw", 

3144 *args: Any, 

3145) -> Image: 

3146 """ 

3147 Creates a copy of an image memory from pixel data in a buffer. 

3148 

3149 In its simplest form, this function takes three arguments 

3150 (mode, size, and unpacked pixel data). 

3151 

3152 You can also use any pixel decoder supported by PIL. For more 

3153 information on available decoders, see the section 

3154 :ref:`Writing Your Own File Codec <file-codecs>`. 

3155 

3156 Note that this function decodes pixel data only, not entire images. 

3157 If you have an entire image in a string, wrap it in a 

3158 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3159 it. 

3160 

3161 :param mode: The image mode. See: :ref:`concept-modes`. 

3162 :param size: The image size. 

3163 :param data: A byte buffer containing raw data for the given mode. 

3164 :param decoder_name: What decoder to use. 

3165 :param args: Additional parameters for the given decoder. 

3166 :returns: An :py:class:`~PIL.Image.Image` object. 

3167 """ 

3168 

3169 _check_size(size) 

3170 

3171 im = new(mode, size) 

3172 if im.width != 0 and im.height != 0: 

3173 decoder_args: Any = args 

3174 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3175 # may pass tuple instead of argument list 

3176 decoder_args = decoder_args[0] 

3177 

3178 if decoder_name == "raw" and decoder_args == (): 

3179 decoder_args = mode 

3180 

3181 im.frombytes(data, decoder_name, decoder_args) 

3182 return im 

3183 

3184 

3185def frombuffer( 

3186 mode: str, 

3187 size: tuple[int, int], 

3188 data: bytes | SupportsArrayInterface, 

3189 decoder_name: str = "raw", 

3190 *args: Any, 

3191) -> Image: 

3192 """ 

3193 Creates an image memory referencing pixel data in a byte buffer. 

3194 

3195 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3196 in the byte buffer, where possible. This means that changes to the 

3197 original buffer object are reflected in this image). Not all modes can 

3198 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3199 

3200 Note that this function decodes pixel data only, not entire images. 

3201 If you have an entire image file in a string, wrap it in a 

3202 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3203 

3204 The default parameters used for the "raw" decoder differs from that used for 

3205 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3206 future release. The current release issues a warning if you do this; to disable 

3207 the warning, you should provide the full set of parameters. See below for details. 

3208 

3209 :param mode: The image mode. See: :ref:`concept-modes`. 

3210 :param size: The image size. 

3211 :param data: A bytes or other buffer object containing raw 

3212 data for the given mode. 

3213 :param decoder_name: What decoder to use. 

3214 :param args: Additional parameters for the given decoder. For the 

3215 default encoder ("raw"), it's recommended that you provide the 

3216 full set of parameters:: 

3217 

3218 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3219 

3220 :returns: An :py:class:`~PIL.Image.Image` object. 

3221 

3222 .. versionadded:: 1.1.4 

3223 """ 

3224 

3225 _check_size(size) 

3226 

3227 # may pass tuple instead of argument list 

3228 if len(args) == 1 and isinstance(args[0], tuple): 

3229 args = args[0] 

3230 

3231 if decoder_name == "raw": 

3232 if args == (): 

3233 args = mode, 0, 1 

3234 if args[0] in _MAPMODES: 

3235 im = new(mode, (0, 0)) 

3236 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3237 if mode == "P": 

3238 from . import ImagePalette 

3239 

3240 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3241 im.readonly = 1 

3242 return im 

3243 

3244 return frombytes(mode, size, data, decoder_name, args) 

3245 

3246 

3247class SupportsArrayInterface(Protocol): 

3248 """ 

3249 An object that has an ``__array_interface__`` dictionary. 

3250 """ 

3251 

3252 @property 

3253 def __array_interface__(self) -> dict[str, Any]: 

3254 raise NotImplementedError() 

3255 

3256 

3257def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3258 """ 

3259 Creates an image memory from an object exporting the array interface 

3260 (using the buffer protocol):: 

3261 

3262 from PIL import Image 

3263 import numpy as np 

3264 a = np.zeros((5, 5)) 

3265 im = Image.fromarray(a) 

3266 

3267 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3268 and :py:func:`~PIL.Image.frombuffer` is used. 

3269 

3270 In the case of NumPy, be aware that Pillow modes do not always correspond 

3271 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3272 32-bit signed integer pixels, and 32-bit floating point pixels. 

3273 

3274 Pillow images can also be converted to arrays:: 

3275 

3276 from PIL import Image 

3277 import numpy as np 

3278 im = Image.open("hopper.jpg") 

3279 a = np.asarray(im) 

3280 

3281 When converting Pillow images to arrays however, only pixel values are 

3282 transferred. This means that P and PA mode images will lose their palette. 

3283 

3284 :param obj: Object with array interface 

3285 :param mode: Optional mode to use when reading ``obj``. Will be determined from 

3286 type if ``None``. 

3287 

3288 This will not be used to convert the data after reading, but will be used to 

3289 change how the data is read:: 

3290 

3291 from PIL import Image 

3292 import numpy as np 

3293 a = np.full((1, 1), 300) 

3294 im = Image.fromarray(a, mode="L") 

3295 im.getpixel((0, 0)) # 44 

3296 im = Image.fromarray(a, mode="RGB") 

3297 im.getpixel((0, 0)) # (44, 1, 0) 

3298 

3299 See: :ref:`concept-modes` for general information about modes. 

3300 :returns: An image object. 

3301 

3302 .. versionadded:: 1.1.6 

3303 """ 

3304 arr = obj.__array_interface__ 

3305 shape = arr["shape"] 

3306 ndim = len(shape) 

3307 strides = arr.get("strides", None) 

3308 if mode is None: 

3309 try: 

3310 typekey = (1, 1) + shape[2:], arr["typestr"] 

3311 except KeyError as e: 

3312 msg = "Cannot handle this data type" 

3313 raise TypeError(msg) from e 

3314 try: 

3315 mode, rawmode = _fromarray_typemap[typekey] 

3316 except KeyError as e: 

3317 typekey_shape, typestr = typekey 

3318 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3319 raise TypeError(msg) from e 

3320 else: 

3321 rawmode = mode 

3322 if mode in ["1", "L", "I", "P", "F"]: 

3323 ndmax = 2 

3324 elif mode == "RGB": 

3325 ndmax = 3 

3326 else: 

3327 ndmax = 4 

3328 if ndim > ndmax: 

3329 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3330 raise ValueError(msg) 

3331 

3332 size = 1 if ndim == 1 else shape[1], shape[0] 

3333 if strides is not None: 

3334 if hasattr(obj, "tobytes"): 

3335 obj = obj.tobytes() 

3336 elif hasattr(obj, "tostring"): 

3337 obj = obj.tostring() 

3338 else: 

3339 msg = "'strides' requires either tobytes() or tostring()" 

3340 raise ValueError(msg) 

3341 

3342 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3343 

3344 

3345def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3346 """Creates an image instance from a QImage image""" 

3347 from . import ImageQt 

3348 

3349 if not ImageQt.qt_is_installed: 

3350 msg = "Qt bindings are not installed" 

3351 raise ImportError(msg) 

3352 return ImageQt.fromqimage(im) 

3353 

3354 

3355def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3356 """Creates an image instance from a QPixmap image""" 

3357 from . import ImageQt 

3358 

3359 if not ImageQt.qt_is_installed: 

3360 msg = "Qt bindings are not installed" 

3361 raise ImportError(msg) 

3362 return ImageQt.fromqpixmap(im) 

3363 

3364 

3365_fromarray_typemap = { 

3366 # (shape, typestr) => mode, rawmode 

3367 # first two members of shape are set to one 

3368 ((1, 1), "|b1"): ("1", "1;8"), 

3369 ((1, 1), "|u1"): ("L", "L"), 

3370 ((1, 1), "|i1"): ("I", "I;8"), 

3371 ((1, 1), "<u2"): ("I", "I;16"), 

3372 ((1, 1), ">u2"): ("I", "I;16B"), 

3373 ((1, 1), "<i2"): ("I", "I;16S"), 

3374 ((1, 1), ">i2"): ("I", "I;16BS"), 

3375 ((1, 1), "<u4"): ("I", "I;32"), 

3376 ((1, 1), ">u4"): ("I", "I;32B"), 

3377 ((1, 1), "<i4"): ("I", "I;32S"), 

3378 ((1, 1), ">i4"): ("I", "I;32BS"), 

3379 ((1, 1), "<f4"): ("F", "F;32F"), 

3380 ((1, 1), ">f4"): ("F", "F;32BF"), 

3381 ((1, 1), "<f8"): ("F", "F;64F"), 

3382 ((1, 1), ">f8"): ("F", "F;64BF"), 

3383 ((1, 1, 2), "|u1"): ("LA", "LA"), 

3384 ((1, 1, 3), "|u1"): ("RGB", "RGB"), 

3385 ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), 

3386 # shortcuts: 

3387 ((1, 1), f"{_ENDIAN}i4"): ("I", "I"), 

3388 ((1, 1), f"{_ENDIAN}f4"): ("F", "F"), 

3389} 

3390 

3391 

3392def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3393 if MAX_IMAGE_PIXELS is None: 

3394 return 

3395 

3396 pixels = max(1, size[0]) * max(1, size[1]) 

3397 

3398 if pixels > 2 * MAX_IMAGE_PIXELS: 

3399 msg = ( 

3400 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3401 "pixels, could be decompression bomb DOS attack." 

3402 ) 

3403 raise DecompressionBombError(msg) 

3404 

3405 if pixels > MAX_IMAGE_PIXELS: 

3406 warnings.warn( 

3407 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3408 "could be decompression bomb DOS attack.", 

3409 DecompressionBombWarning, 

3410 ) 

3411 

3412 

3413def open( 

3414 fp: StrOrBytesPath | IO[bytes], 

3415 mode: Literal["r"] = "r", 

3416 formats: list[str] | tuple[str, ...] | None = None, 

3417) -> ImageFile.ImageFile: 

3418 """ 

3419 Opens and identifies the given image file. 

3420 

3421 This is a lazy operation; this function identifies the file, but 

3422 the file remains open and the actual image data is not read from 

3423 the file until you try to process the data (or call the 

3424 :py:meth:`~PIL.Image.Image.load` method). See 

3425 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3426 

3427 :param fp: A filename (string), os.PathLike object or a file object. 

3428 The file object must implement ``file.read``, 

3429 ``file.seek``, and ``file.tell`` methods, 

3430 and be opened in binary mode. The file object will also seek to zero 

3431 before reading. 

3432 :param mode: The mode. If given, this argument must be "r". 

3433 :param formats: A list or tuple of formats to attempt to load the file in. 

3434 This can be used to restrict the set of formats checked. 

3435 Pass ``None`` to try all supported formats. You can print the set of 

3436 available formats by running ``python3 -m PIL`` or using 

3437 the :py:func:`PIL.features.pilinfo` function. 

3438 :returns: An :py:class:`~PIL.Image.Image` object. 

3439 :exception FileNotFoundError: If the file cannot be found. 

3440 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3441 identified. 

3442 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3443 instance is used for ``fp``. 

3444 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3445 """ 

3446 

3447 if mode != "r": 

3448 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3449 raise ValueError(msg) 

3450 elif isinstance(fp, io.StringIO): 

3451 msg = ( # type: ignore[unreachable] 

3452 "StringIO cannot be used to open an image. " 

3453 "Binary data must be used instead." 

3454 ) 

3455 raise ValueError(msg) 

3456 

3457 if formats is None: 

3458 formats = ID 

3459 elif not isinstance(formats, (list, tuple)): 

3460 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3461 raise TypeError(msg) 

3462 

3463 exclusive_fp = False 

3464 filename: str | bytes = "" 

3465 if is_path(fp): 

3466 filename = os.path.realpath(os.fspath(fp)) 

3467 

3468 if filename: 

3469 fp = builtins.open(filename, "rb") 

3470 exclusive_fp = True 

3471 else: 

3472 fp = cast(IO[bytes], fp) 

3473 

3474 try: 

3475 fp.seek(0) 

3476 except (AttributeError, io.UnsupportedOperation): 

3477 fp = io.BytesIO(fp.read()) 

3478 exclusive_fp = True 

3479 

3480 prefix = fp.read(16) 

3481 

3482 preinit() 

3483 

3484 warning_messages: list[str] = [] 

3485 

3486 def _open_core( 

3487 fp: IO[bytes], 

3488 filename: str | bytes, 

3489 prefix: bytes, 

3490 formats: list[str] | tuple[str, ...], 

3491 ) -> ImageFile.ImageFile | None: 

3492 for i in formats: 

3493 i = i.upper() 

3494 if i not in OPEN: 

3495 init() 

3496 try: 

3497 factory, accept = OPEN[i] 

3498 result = not accept or accept(prefix) 

3499 if isinstance(result, str): 

3500 warning_messages.append(result) 

3501 elif result: 

3502 fp.seek(0) 

3503 im = factory(fp, filename) 

3504 _decompression_bomb_check(im.size) 

3505 return im 

3506 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3507 if WARN_POSSIBLE_FORMATS: 

3508 warning_messages.append(i + " opening failed. " + str(e)) 

3509 except BaseException: 

3510 if exclusive_fp: 

3511 fp.close() 

3512 raise 

3513 return None 

3514 

3515 im = _open_core(fp, filename, prefix, formats) 

3516 

3517 if im is None and formats is ID: 

3518 checked_formats = ID.copy() 

3519 if init(): 

3520 im = _open_core( 

3521 fp, 

3522 filename, 

3523 prefix, 

3524 tuple(format for format in formats if format not in checked_formats), 

3525 ) 

3526 

3527 if im: 

3528 im._exclusive_fp = exclusive_fp 

3529 return im 

3530 

3531 if exclusive_fp: 

3532 fp.close() 

3533 for message in warning_messages: 

3534 warnings.warn(message) 

3535 msg = "cannot identify image file %r" % (filename if filename else fp) 

3536 raise UnidentifiedImageError(msg) 

3537 

3538 

3539# 

3540# Image processing. 

3541 

3542 

3543def alpha_composite(im1: Image, im2: Image) -> Image: 

3544 """ 

3545 Alpha composite im2 over im1. 

3546 

3547 :param im1: The first image. Must have mode RGBA. 

3548 :param im2: The second image. Must have mode RGBA, and the same size as 

3549 the first image. 

3550 :returns: An :py:class:`~PIL.Image.Image` object. 

3551 """ 

3552 

3553 im1.load() 

3554 im2.load() 

3555 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3556 

3557 

3558def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3559 """ 

3560 Creates a new image by interpolating between two input images, using 

3561 a constant alpha:: 

3562 

3563 out = image1 * (1.0 - alpha) + image2 * alpha 

3564 

3565 :param im1: The first image. 

3566 :param im2: The second image. Must have the same mode and size as 

3567 the first image. 

3568 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3569 copy of the first image is returned. If alpha is 1.0, a copy of 

3570 the second image is returned. There are no restrictions on the 

3571 alpha value. If necessary, the result is clipped to fit into 

3572 the allowed output range. 

3573 :returns: An :py:class:`~PIL.Image.Image` object. 

3574 """ 

3575 

3576 im1.load() 

3577 im2.load() 

3578 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3579 

3580 

3581def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3582 """ 

3583 Create composite image by blending images using a transparency mask. 

3584 

3585 :param image1: The first image. 

3586 :param image2: The second image. Must have the same mode and 

3587 size as the first image. 

3588 :param mask: A mask image. This image can have mode 

3589 "1", "L", or "RGBA", and must have the same size as the 

3590 other two images. 

3591 """ 

3592 

3593 image = image2.copy() 

3594 image.paste(image1, None, mask) 

3595 return image 

3596 

3597 

3598def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3599 """ 

3600 Applies the function (which should take one argument) to each pixel 

3601 in the given image. If the image has more than one band, the same 

3602 function is applied to each band. Note that the function is 

3603 evaluated once for each possible pixel value, so you cannot use 

3604 random components or other generators. 

3605 

3606 :param image: The input image. 

3607 :param function: A function object, taking one integer argument. 

3608 :returns: An :py:class:`~PIL.Image.Image` object. 

3609 """ 

3610 

3611 return image.point(args[0]) 

3612 

3613 

3614def merge(mode: str, bands: Sequence[Image]) -> Image: 

3615 """ 

3616 Merge a set of single band images into a new multiband image. 

3617 

3618 :param mode: The mode to use for the output image. See: 

3619 :ref:`concept-modes`. 

3620 :param bands: A sequence containing one single-band image for 

3621 each band in the output image. All bands must have the 

3622 same size. 

3623 :returns: An :py:class:`~PIL.Image.Image` object. 

3624 """ 

3625 

3626 if getmodebands(mode) != len(bands) or "*" in mode: 

3627 msg = "wrong number of bands" 

3628 raise ValueError(msg) 

3629 for band in bands[1:]: 

3630 if band.mode != getmodetype(mode): 

3631 msg = "mode mismatch" 

3632 raise ValueError(msg) 

3633 if band.size != bands[0].size: 

3634 msg = "size mismatch" 

3635 raise ValueError(msg) 

3636 for band in bands: 

3637 band.load() 

3638 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3639 

3640 

3641# -------------------------------------------------------------------- 

3642# Plugin registry 

3643 

3644 

3645def register_open( 

3646 id: str, 

3647 factory: ( 

3648 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3649 | type[ImageFile.ImageFile] 

3650 ), 

3651 accept: Callable[[bytes], bool | str] | None = None, 

3652) -> None: 

3653 """ 

3654 Register an image file plugin. This function should not be used 

3655 in application code. 

3656 

3657 :param id: An image format identifier. 

3658 :param factory: An image file factory method. 

3659 :param accept: An optional function that can be used to quickly 

3660 reject images having another format. 

3661 """ 

3662 id = id.upper() 

3663 if id not in ID: 

3664 ID.append(id) 

3665 OPEN[id] = factory, accept 

3666 

3667 

3668def register_mime(id: str, mimetype: str) -> None: 

3669 """ 

3670 Registers an image MIME type by populating ``Image.MIME``. This function 

3671 should not be used in application code. 

3672 

3673 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3674 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3675 provide a different result for specific images. 

3676 

3677 :param id: An image format identifier. 

3678 :param mimetype: The image MIME type for this format. 

3679 """ 

3680 MIME[id.upper()] = mimetype 

3681 

3682 

3683def register_save( 

3684 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3685) -> None: 

3686 """ 

3687 Registers an image save function. This function should not be 

3688 used in application code. 

3689 

3690 :param id: An image format identifier. 

3691 :param driver: A function to save images in this format. 

3692 """ 

3693 SAVE[id.upper()] = driver 

3694 

3695 

3696def register_save_all( 

3697 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3698) -> None: 

3699 """ 

3700 Registers an image function to save all the frames 

3701 of a multiframe format. This function should not be 

3702 used in application code. 

3703 

3704 :param id: An image format identifier. 

3705 :param driver: A function to save images in this format. 

3706 """ 

3707 SAVE_ALL[id.upper()] = driver 

3708 

3709 

3710def register_extension(id: str, extension: str) -> None: 

3711 """ 

3712 Registers an image extension. This function should not be 

3713 used in application code. 

3714 

3715 :param id: An image format identifier. 

3716 :param extension: An extension used for this format. 

3717 """ 

3718 EXTENSION[extension.lower()] = id.upper() 

3719 

3720 

3721def register_extensions(id: str, extensions: list[str]) -> None: 

3722 """ 

3723 Registers image extensions. This function should not be 

3724 used in application code. 

3725 

3726 :param id: An image format identifier. 

3727 :param extensions: A list of extensions used for this format. 

3728 """ 

3729 for extension in extensions: 

3730 register_extension(id, extension) 

3731 

3732 

3733def registered_extensions() -> dict[str, str]: 

3734 """ 

3735 Returns a dictionary containing all file extensions belonging 

3736 to registered plugins 

3737 """ 

3738 init() 

3739 return EXTENSION 

3740 

3741 

3742def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3743 """ 

3744 Registers an image decoder. This function should not be 

3745 used in application code. 

3746 

3747 :param name: The name of the decoder 

3748 :param decoder: An ImageFile.PyDecoder object 

3749 

3750 .. versionadded:: 4.1.0 

3751 """ 

3752 DECODERS[name] = decoder 

3753 

3754 

3755def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3756 """ 

3757 Registers an image encoder. This function should not be 

3758 used in application code. 

3759 

3760 :param name: The name of the encoder 

3761 :param encoder: An ImageFile.PyEncoder object 

3762 

3763 .. versionadded:: 4.1.0 

3764 """ 

3765 ENCODERS[name] = encoder 

3766 

3767 

3768# -------------------------------------------------------------------- 

3769# Simple display support. 

3770 

3771 

3772def _show(image: Image, **options: Any) -> None: 

3773 from . import ImageShow 

3774 

3775 ImageShow.show(image, **options) 

3776 

3777 

3778# -------------------------------------------------------------------- 

3779# Effects 

3780 

3781 

3782def effect_mandelbrot( 

3783 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3784) -> Image: 

3785 """ 

3786 Generate a Mandelbrot set covering the given extent. 

3787 

3788 :param size: The requested size in pixels, as a 2-tuple: 

3789 (width, height). 

3790 :param extent: The extent to cover, as a 4-tuple: 

3791 (x0, y0, x1, y1). 

3792 :param quality: Quality. 

3793 """ 

3794 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3795 

3796 

3797def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3798 """ 

3799 Generate Gaussian noise centered around 128. 

3800 

3801 :param size: The requested size in pixels, as a 2-tuple: 

3802 (width, height). 

3803 :param sigma: Standard deviation of noise. 

3804 """ 

3805 return Image()._new(core.effect_noise(size, sigma)) 

3806 

3807 

3808def linear_gradient(mode: str) -> Image: 

3809 """ 

3810 Generate 256x256 linear gradient from black to white, top to bottom. 

3811 

3812 :param mode: Input mode. 

3813 """ 

3814 return Image()._new(core.linear_gradient(mode)) 

3815 

3816 

3817def radial_gradient(mode: str) -> Image: 

3818 """ 

3819 Generate 256x256 radial gradient from black to white, centre to edge. 

3820 

3821 :param mode: Input mode. 

3822 """ 

3823 return Image()._new(core.radial_gradient(mode)) 

3824 

3825 

3826# -------------------------------------------------------------------- 

3827# Resources 

3828 

3829 

3830def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

3831 env_dict = env if env is not None else os.environ 

3832 

3833 for var_name, setter in [ 

3834 ("PILLOW_ALIGNMENT", core.set_alignment), 

3835 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

3836 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

3837 ]: 

3838 if var_name not in env_dict: 

3839 continue 

3840 

3841 var = env_dict[var_name].lower() 

3842 

3843 units = 1 

3844 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

3845 if var.endswith(postfix): 

3846 units = mul 

3847 var = var[: -len(postfix)] 

3848 

3849 try: 

3850 var_int = int(var) * units 

3851 except ValueError: 

3852 warnings.warn(f"{var_name} is not int") 

3853 continue 

3854 

3855 try: 

3856 setter(var_int) 

3857 except ValueError as e: 

3858 warnings.warn(f"{var_name}: {e}") 

3859 

3860 

3861_apply_env_variables() 

3862atexit.register(core.clear_cache) 

3863 

3864 

3865if TYPE_CHECKING: 

3866 _ExifBase = MutableMapping[int, Any] 

3867else: 

3868 _ExifBase = MutableMapping 

3869 

3870 

3871class Exif(_ExifBase): 

3872 """ 

3873 This class provides read and write access to EXIF image data:: 

3874 

3875 from PIL import Image 

3876 im = Image.open("exif.png") 

3877 exif = im.getexif() # Returns an instance of this class 

3878 

3879 Information can be read and written, iterated over or deleted:: 

3880 

3881 print(exif[274]) # 1 

3882 exif[274] = 2 

3883 for k, v in exif.items(): 

3884 print("Tag", k, "Value", v) # Tag 274 Value 2 

3885 del exif[274] 

3886 

3887 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

3888 returns a dictionary:: 

3889 

3890 from PIL import ExifTags 

3891 im = Image.open("exif_gps.jpg") 

3892 exif = im.getexif() 

3893 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

3894 print(gps_ifd) 

3895 

3896 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.Makernote``, 

3897 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

3898 

3899 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

3900 

3901 print(exif[ExifTags.Base.Software]) # PIL 

3902 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

3903 """ 

3904 

3905 endian: str | None = None 

3906 bigtiff = False 

3907 _loaded = False 

3908 

3909 def __init__(self) -> None: 

3910 self._data: dict[int, Any] = {} 

3911 self._hidden_data: dict[int, Any] = {} 

3912 self._ifds: dict[int, dict[int, Any]] = {} 

3913 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

3914 self._loaded_exif: bytes | None = None 

3915 

3916 def _fixup(self, value: Any) -> Any: 

3917 try: 

3918 if len(value) == 1 and isinstance(value, tuple): 

3919 return value[0] 

3920 except Exception: 

3921 pass 

3922 return value 

3923 

3924 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

3925 # Helper function 

3926 # returns a dict with any single item tuples/lists as individual values 

3927 return {k: self._fixup(v) for k, v in src_dict.items()} 

3928 

3929 def _get_ifd_dict( 

3930 self, offset: int, group: int | None = None 

3931 ) -> dict[int, Any] | None: 

3932 try: 

3933 # an offset pointer to the location of the nested embedded IFD. 

3934 # It should be a long, but may be corrupted. 

3935 self.fp.seek(offset) 

3936 except (KeyError, TypeError): 

3937 return None 

3938 else: 

3939 from . import TiffImagePlugin 

3940 

3941 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

3942 info.load(self.fp) 

3943 return self._fixup_dict(dict(info)) 

3944 

3945 def _get_head(self) -> bytes: 

3946 version = b"\x2B" if self.bigtiff else b"\x2A" 

3947 if self.endian == "<": 

3948 head = b"II" + version + b"\x00" + o32le(8) 

3949 else: 

3950 head = b"MM\x00" + version + o32be(8) 

3951 if self.bigtiff: 

3952 head += o32le(8) if self.endian == "<" else o32be(8) 

3953 head += b"\x00\x00\x00\x00" 

3954 return head 

3955 

3956 def load(self, data: bytes) -> None: 

3957 # Extract EXIF information. This is highly experimental, 

3958 # and is likely to be replaced with something better in a future 

3959 # version. 

3960 

3961 # The EXIF record consists of a TIFF file embedded in a JPEG 

3962 # application marker (!). 

3963 if data == self._loaded_exif: 

3964 return 

3965 self._loaded_exif = data 

3966 self._data.clear() 

3967 self._hidden_data.clear() 

3968 self._ifds.clear() 

3969 while data and data.startswith(b"Exif\x00\x00"): 

3970 data = data[6:] 

3971 if not data: 

3972 self._info = None 

3973 return 

3974 

3975 self.fp: IO[bytes] = io.BytesIO(data) 

3976 self.head = self.fp.read(8) 

3977 # process dictionary 

3978 from . import TiffImagePlugin 

3979 

3980 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

3981 self.endian = self._info._endian 

3982 self.fp.seek(self._info.next) 

3983 self._info.load(self.fp) 

3984 

3985 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

3986 self._loaded_exif = None 

3987 self._data.clear() 

3988 self._hidden_data.clear() 

3989 self._ifds.clear() 

3990 

3991 # process dictionary 

3992 from . import TiffImagePlugin 

3993 

3994 self.fp = fp 

3995 if offset is not None: 

3996 self.head = self._get_head() 

3997 else: 

3998 self.head = self.fp.read(8) 

3999 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4000 if self.endian is None: 

4001 self.endian = self._info._endian 

4002 if offset is None: 

4003 offset = self._info.next 

4004 self.fp.tell() 

4005 self.fp.seek(offset) 

4006 self._info.load(self.fp) 

4007 

4008 def _get_merged_dict(self) -> dict[int, Any]: 

4009 merged_dict = dict(self) 

4010 

4011 # get EXIF extension 

4012 if ExifTags.IFD.Exif in self: 

4013 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4014 if ifd: 

4015 merged_dict.update(ifd) 

4016 

4017 # GPS 

4018 if ExifTags.IFD.GPSInfo in self: 

4019 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4020 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4021 ) 

4022 

4023 return merged_dict 

4024 

4025 def tobytes(self, offset: int = 8) -> bytes: 

4026 from . import TiffImagePlugin 

4027 

4028 head = self._get_head() 

4029 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4030 for tag, value in self.items(): 

4031 if tag in [ 

4032 ExifTags.IFD.Exif, 

4033 ExifTags.IFD.GPSInfo, 

4034 ] and not isinstance(value, dict): 

4035 value = self.get_ifd(tag) 

4036 if ( 

4037 tag == ExifTags.IFD.Exif 

4038 and ExifTags.IFD.Interop in value 

4039 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4040 ): 

4041 value = value.copy() 

4042 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4043 ifd[tag] = value 

4044 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4045 

4046 def get_ifd(self, tag: int) -> dict[int, Any]: 

4047 if tag not in self._ifds: 

4048 if tag == ExifTags.IFD.IFD1: 

4049 if self._info is not None and self._info.next != 0: 

4050 ifd = self._get_ifd_dict(self._info.next) 

4051 if ifd is not None: 

4052 self._ifds[tag] = ifd 

4053 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4054 offset = self._hidden_data.get(tag, self.get(tag)) 

4055 if offset is not None: 

4056 ifd = self._get_ifd_dict(offset, tag) 

4057 if ifd is not None: 

4058 self._ifds[tag] = ifd 

4059 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.Makernote]: 

4060 if ExifTags.IFD.Exif not in self._ifds: 

4061 self.get_ifd(ExifTags.IFD.Exif) 

4062 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4063 if tag == ExifTags.IFD.Makernote: 

4064 from .TiffImagePlugin import ImageFileDirectory_v2 

4065 

4066 if tag_data[:8] == b"FUJIFILM": 

4067 ifd_offset = i32le(tag_data, 8) 

4068 ifd_data = tag_data[ifd_offset:] 

4069 

4070 makernote = {} 

4071 for i in range(0, struct.unpack("<H", ifd_data[:2])[0]): 

4072 ifd_tag, typ, count, data = struct.unpack( 

4073 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4074 ) 

4075 try: 

4076 ( 

4077 unit_size, 

4078 handler, 

4079 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4080 except KeyError: 

4081 continue 

4082 size = count * unit_size 

4083 if size > 4: 

4084 (offset,) = struct.unpack("<L", data) 

4085 data = ifd_data[offset - 12 : offset + size - 12] 

4086 else: 

4087 data = data[:size] 

4088 

4089 if len(data) != size: 

4090 warnings.warn( 

4091 "Possibly corrupt EXIF MakerNote data. " 

4092 f"Expecting to read {size} bytes but only got " 

4093 f"{len(data)}. Skipping tag {ifd_tag}" 

4094 ) 

4095 continue 

4096 

4097 if not data: 

4098 continue 

4099 

4100 makernote[ifd_tag] = handler( 

4101 ImageFileDirectory_v2(), data, False 

4102 ) 

4103 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4104 elif self.get(0x010F) == "Nintendo": 

4105 makernote = {} 

4106 for i in range(0, struct.unpack(">H", tag_data[:2])[0]): 

4107 ifd_tag, typ, count, data = struct.unpack( 

4108 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4109 ) 

4110 if ifd_tag == 0x1101: 

4111 # CameraInfo 

4112 (offset,) = struct.unpack(">L", data) 

4113 self.fp.seek(offset) 

4114 

4115 camerainfo: dict[str, int | bytes] = { 

4116 "ModelID": self.fp.read(4) 

4117 } 

4118 

4119 self.fp.read(4) 

4120 # Seconds since 2000 

4121 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4122 

4123 self.fp.read(4) 

4124 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4125 

4126 self.fp.read(12) 

4127 parallax = self.fp.read(4) 

4128 handler = ImageFileDirectory_v2._load_dispatch[ 

4129 TiffTags.FLOAT 

4130 ][1] 

4131 camerainfo["Parallax"] = handler( 

4132 ImageFileDirectory_v2(), parallax, False 

4133 )[0] 

4134 

4135 self.fp.read(4) 

4136 camerainfo["Category"] = self.fp.read(2) 

4137 

4138 makernote = {0x1101: camerainfo} 

4139 self._ifds[tag] = makernote 

4140 else: 

4141 # Interop 

4142 ifd = self._get_ifd_dict(tag_data, tag) 

4143 if ifd is not None: 

4144 self._ifds[tag] = ifd 

4145 ifd = self._ifds.setdefault(tag, {}) 

4146 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4147 ifd = { 

4148 k: v 

4149 for (k, v) in ifd.items() 

4150 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.Makernote) 

4151 } 

4152 return ifd 

4153 

4154 def hide_offsets(self) -> None: 

4155 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4156 if tag in self: 

4157 self._hidden_data[tag] = self[tag] 

4158 del self[tag] 

4159 

4160 def __str__(self) -> str: 

4161 if self._info is not None: 

4162 # Load all keys into self._data 

4163 for tag in self._info: 

4164 self[tag] 

4165 

4166 return str(self._data) 

4167 

4168 def __len__(self) -> int: 

4169 keys = set(self._data) 

4170 if self._info is not None: 

4171 keys.update(self._info) 

4172 return len(keys) 

4173 

4174 def __getitem__(self, tag: int) -> Any: 

4175 if self._info is not None and tag not in self._data and tag in self._info: 

4176 self._data[tag] = self._fixup(self._info[tag]) 

4177 del self._info[tag] 

4178 return self._data[tag] 

4179 

4180 def __contains__(self, tag: object) -> bool: 

4181 return tag in self._data or (self._info is not None and tag in self._info) 

4182 

4183 def __setitem__(self, tag: int, value: Any) -> None: 

4184 if self._info is not None and tag in self._info: 

4185 del self._info[tag] 

4186 self._data[tag] = value 

4187 

4188 def __delitem__(self, tag: int) -> None: 

4189 if self._info is not None and tag in self._info: 

4190 del self._info[tag] 

4191 else: 

4192 del self._data[tag] 

4193 

4194 def __iter__(self) -> Iterator[int]: 

4195 keys = set(self._data) 

4196 if self._info is not None: 

4197 keys.update(self._info) 

4198 return iter(keys)