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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1763 statements  

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# the Image class wrapper 

6# 

7# partial release history: 

8# 1995-09-09 fl Created 

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

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

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

12# 2000-06-07 fl PIL release 1.1 

13# 2000-10-20 fl PIL release 1.1.1 

14# 2001-05-07 fl PIL release 1.1.2 

15# 2002-03-15 fl PIL release 1.1.3 

16# 2003-05-10 fl PIL release 1.1.4 

17# 2005-03-28 fl PIL release 1.1.5 

18# 2006-12-02 fl PIL release 1.1.6 

19# 2009-11-15 fl PIL release 1.1.7 

20# 

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

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

23# 

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

25# 

26 

27from __future__ import annotations 

28 

29import abc 

30import atexit 

31import builtins 

32import io 

33import logging 

34import math 

35import os 

36import re 

37import struct 

38import sys 

39import tempfile 

40import warnings 

41from collections.abc import MutableMapping 

42from enum import IntEnum 

43from typing import IO, Protocol, cast 

44 

45# VERSION was removed in Pillow 6.0.0. 

46# PILLOW_VERSION was removed in Pillow 9.0.0. 

47# Use __version__ instead. 

48from . import ( 

49 ExifTags, 

50 ImageMode, 

51 TiffTags, 

52 UnidentifiedImageError, 

53 __version__, 

54 _plugins, 

55) 

56from ._binary import i32le, o32be, o32le 

57from ._deprecate import deprecate 

58from ._util import DeferredError, is_path 

59 

60ElementTree: ModuleType | None 

61try: 

62 from defusedxml import ElementTree 

63except ImportError: 

64 ElementTree = None 

65 

66TYPE_CHECKING = False 

67if TYPE_CHECKING: 

68 from collections.abc import Callable, Iterator, Sequence 

69 from types import ModuleType 

70 from typing import Any, Literal 

71 

72logger = logging.getLogger(__name__) 

73 

74 

75class DecompressionBombWarning(RuntimeWarning): 

76 pass 

77 

78 

79class DecompressionBombError(Exception): 

80 pass 

81 

82 

83WARN_POSSIBLE_FORMATS: bool = False 

84 

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

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

87 

88 

89try: 

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

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

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

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

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

95 from . import _imaging as core 

96 

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

98 msg = ( 

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

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

101 f"Pillow version: {__version__}" 

102 ) 

103 raise ImportError(msg) 

104 

105except ImportError as v: 

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

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

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

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

110 # possible. 

111 warnings.warn( 

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

113 RuntimeWarning, 

114 ) 

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

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

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

118 # see docs/porting.rst 

119 raise 

120 

121 

122# 

123# Constants 

124 

125 

126# transpose 

127class Transpose(IntEnum): 

128 FLIP_LEFT_RIGHT = 0 

129 FLIP_TOP_BOTTOM = 1 

130 ROTATE_90 = 2 

131 ROTATE_180 = 3 

132 ROTATE_270 = 4 

133 TRANSPOSE = 5 

134 TRANSVERSE = 6 

135 

136 

137# transforms (also defined in Imaging.h) 

138class Transform(IntEnum): 

139 AFFINE = 0 

140 EXTENT = 1 

141 PERSPECTIVE = 2 

142 QUAD = 3 

143 MESH = 4 

144 

145 

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

147class Resampling(IntEnum): 

148 NEAREST = 0 

149 BOX = 4 

150 BILINEAR = 2 

151 HAMMING = 5 

152 BICUBIC = 3 

153 LANCZOS = 1 

154 

155 

156_filters_support = { 

157 Resampling.BOX: 0.5, 

158 Resampling.BILINEAR: 1.0, 

159 Resampling.HAMMING: 1.0, 

160 Resampling.BICUBIC: 2.0, 

161 Resampling.LANCZOS: 3.0, 

162} 

163 

164 

165# dithers 

166class Dither(IntEnum): 

167 NONE = 0 

168 ORDERED = 1 # Not yet implemented 

169 RASTERIZE = 2 # Not yet implemented 

170 FLOYDSTEINBERG = 3 # default 

171 

172 

173# palettes/quantizers 

174class Palette(IntEnum): 

175 WEB = 0 

176 ADAPTIVE = 1 

177 

178 

179class Quantize(IntEnum): 

180 MEDIANCUT = 0 

181 MAXCOVERAGE = 1 

182 FASTOCTREE = 2 

183 LIBIMAGEQUANT = 3 

184 

185 

186module = sys.modules[__name__] 

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

188 for item in enum: 

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

190 

191 

192if hasattr(core, "DEFAULT_STRATEGY"): 

193 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

194 FILTERED = core.FILTERED 

195 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

196 RLE = core.RLE 

197 FIXED = core.FIXED 

198 

199 

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

201# Registries 

202 

203TYPE_CHECKING = False 

204if TYPE_CHECKING: 

205 import mmap 

206 from xml.etree.ElementTree import Element 

207 

208 from IPython.lib.pretty import PrettyPrinter 

209 

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

211 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath 

212ID: list[str] = [] 

213OPEN: dict[ 

214 str, 

215 tuple[ 

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

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

218 ], 

219] = {} 

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

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

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

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

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

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

226 

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

228# Modes 

229 

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

231 

232 

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

234 m = ImageMode.getmode(im.mode) 

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

236 extra = len(m.bands) 

237 if extra != 1: 

238 shape += (extra,) 

239 return shape, m.typestr 

240 

241 

242MODES = [ 

243 "1", 

244 "CMYK", 

245 "F", 

246 "HSV", 

247 "I", 

248 "I;16", 

249 "I;16B", 

250 "I;16L", 

251 "I;16N", 

252 "L", 

253 "LA", 

254 "La", 

255 "LAB", 

256 "P", 

257 "PA", 

258 "RGB", 

259 "RGBA", 

260 "RGBa", 

261 "RGBX", 

262 "YCbCr", 

263] 

264 

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

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

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

268 

269 

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

271 """ 

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

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

274 contain color data. 

275 

276 :param mode: Input mode. 

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

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

279 """ 

280 return ImageMode.getmode(mode).basemode 

281 

282 

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

284 """ 

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

286 single-layer mode suitable for storing individual bands. 

287 

288 :param mode: Input mode. 

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

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

291 """ 

292 return ImageMode.getmode(mode).basetype 

293 

294 

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

296 """ 

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

298 a tuple containing the names of individual bands (use 

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

300 individual band. 

301 

302 :param mode: Input mode. 

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

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

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

306 """ 

307 return ImageMode.getmode(mode).bands 

308 

309 

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

311 """ 

312 Gets the number of individual bands for this mode. 

313 

314 :param mode: Input mode. 

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

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

317 """ 

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

319 

320 

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

322# Helpers 

323 

324_initialized = 0 

325 

326# Mapping from file extension to plugin module name for lazy importing 

327_EXTENSION_PLUGIN: dict[str, str] = { 

328 # Common formats (preinit) 

329 ".bmp": "BmpImagePlugin", 

330 ".dib": "BmpImagePlugin", 

331 ".gif": "GifImagePlugin", 

332 ".jfif": "JpegImagePlugin", 

333 ".jpe": "JpegImagePlugin", 

334 ".jpg": "JpegImagePlugin", 

335 ".jpeg": "JpegImagePlugin", 

336 ".pbm": "PpmImagePlugin", 

337 ".pgm": "PpmImagePlugin", 

338 ".pnm": "PpmImagePlugin", 

339 ".ppm": "PpmImagePlugin", 

340 ".pfm": "PpmImagePlugin", 

341 ".png": "PngImagePlugin", 

342 ".apng": "PngImagePlugin", 

343 # Less common formats (init) 

344 ".avif": "AvifImagePlugin", 

345 ".avifs": "AvifImagePlugin", 

346 ".blp": "BlpImagePlugin", 

347 ".bufr": "BufrStubImagePlugin", 

348 ".cur": "CurImagePlugin", 

349 ".dcx": "DcxImagePlugin", 

350 ".dds": "DdsImagePlugin", 

351 ".ps": "EpsImagePlugin", 

352 ".eps": "EpsImagePlugin", 

353 ".fit": "FitsImagePlugin", 

354 ".fits": "FitsImagePlugin", 

355 ".fli": "FliImagePlugin", 

356 ".flc": "FliImagePlugin", 

357 ".fpx": "FpxImagePlugin", 

358 ".ftc": "FtexImagePlugin", 

359 ".ftu": "FtexImagePlugin", 

360 ".gbr": "GbrImagePlugin", 

361 ".grib": "GribStubImagePlugin", 

362 ".h5": "Hdf5StubImagePlugin", 

363 ".hdf": "Hdf5StubImagePlugin", 

364 ".icns": "IcnsImagePlugin", 

365 ".ico": "IcoImagePlugin", 

366 ".im": "ImImagePlugin", 

367 ".iim": "IptcImagePlugin", 

368 ".jp2": "Jpeg2KImagePlugin", 

369 ".j2k": "Jpeg2KImagePlugin", 

370 ".jpc": "Jpeg2KImagePlugin", 

371 ".jpf": "Jpeg2KImagePlugin", 

372 ".jpx": "Jpeg2KImagePlugin", 

373 ".j2c": "Jpeg2KImagePlugin", 

374 ".mic": "MicImagePlugin", 

375 ".mpg": "MpegImagePlugin", 

376 ".mpeg": "MpegImagePlugin", 

377 ".mpo": "MpoImagePlugin", 

378 ".msp": "MspImagePlugin", 

379 ".palm": "PalmImagePlugin", 

380 ".pcd": "PcdImagePlugin", 

381 ".pcx": "PcxImagePlugin", 

382 ".pdf": "PdfImagePlugin", 

383 ".pxr": "PixarImagePlugin", 

384 ".psd": "PsdImagePlugin", 

385 ".qoi": "QoiImagePlugin", 

386 ".bw": "SgiImagePlugin", 

387 ".rgb": "SgiImagePlugin", 

388 ".rgba": "SgiImagePlugin", 

389 ".sgi": "SgiImagePlugin", 

390 ".ras": "SunImagePlugin", 

391 ".tga": "TgaImagePlugin", 

392 ".icb": "TgaImagePlugin", 

393 ".vda": "TgaImagePlugin", 

394 ".vst": "TgaImagePlugin", 

395 ".tif": "TiffImagePlugin", 

396 ".tiff": "TiffImagePlugin", 

397 ".webp": "WebPImagePlugin", 

398 ".wmf": "WmfImagePlugin", 

399 ".emf": "WmfImagePlugin", 

400 ".xbm": "XbmImagePlugin", 

401 ".xpm": "XpmImagePlugin", 

402} 

403 

404 

405def _import_plugin_for_extension(ext: str | bytes) -> bool: 

406 """Import only the plugin needed for a specific file extension.""" 

407 if not ext: 

408 return False 

409 

410 if isinstance(ext, bytes): 

411 ext = ext.decode() 

412 ext = ext.lower() 

413 if ext in EXTENSION: 

414 return True 

415 

416 plugin = _EXTENSION_PLUGIN.get(ext) 

417 if plugin is None: 

418 return False 

419 

420 try: 

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

422 __import__(f"{__spec__.parent}.{plugin}", globals(), locals(), []) 

423 return True 

424 except ImportError as e: 

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

426 return False 

427 

428 

429def preinit() -> None: 

430 """ 

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

432 

433 It is called when opening or saving images. 

434 """ 

435 

436 global _initialized 

437 if _initialized >= 1: 

438 return 

439 

440 try: 

441 from . import BmpImagePlugin 

442 

443 assert BmpImagePlugin 

444 except ImportError: 

445 pass 

446 try: 

447 from . import GifImagePlugin 

448 

449 assert GifImagePlugin 

450 except ImportError: 

451 pass 

452 try: 

453 from . import JpegImagePlugin 

454 

455 assert JpegImagePlugin 

456 except ImportError: 

457 pass 

458 try: 

459 from . import PpmImagePlugin 

460 

461 assert PpmImagePlugin 

462 except ImportError: 

463 pass 

464 try: 

465 from . import PngImagePlugin 

466 

467 assert PngImagePlugin 

468 except ImportError: 

469 pass 

470 

471 _initialized = 1 

472 

473 

474def init() -> bool: 

475 """ 

476 Explicitly initializes the Python Imaging Library. This function 

477 loads all available file format drivers. 

478 

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

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

481 """ 

482 

483 global _initialized 

484 if _initialized >= 2: 

485 return False 

486 

487 for plugin in _plugins: 

488 try: 

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

490 __import__(f"{__spec__.parent}.{plugin}", globals(), locals(), []) 

491 except ImportError as e: # noqa: PERF203 

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

493 

494 if OPEN or SAVE: 

495 _initialized = 2 

496 return True 

497 return False 

498 

499 

500# -------------------------------------------------------------------- 

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

502 

503 

504def _getdecoder( 

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

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

507 # tweak arguments 

508 if args is None: 

509 args = () 

510 elif not isinstance(args, tuple): 

511 args = (args,) 

512 

513 try: 

514 decoder = DECODERS[decoder_name] 

515 except KeyError: 

516 pass 

517 else: 

518 return decoder(mode, *args + extra) 

519 

520 try: 

521 # get decoder 

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

523 except AttributeError as e: 

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

525 raise OSError(msg) from e 

526 return decoder(mode, *args + extra) 

527 

528 

529def _getencoder( 

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

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

532 # tweak arguments 

533 if args is None: 

534 args = () 

535 elif not isinstance(args, tuple): 

536 args = (args,) 

537 

538 try: 

539 encoder = ENCODERS[encoder_name] 

540 except KeyError: 

541 pass 

542 else: 

543 return encoder(mode, *args + extra) 

544 

545 try: 

546 # get encoder 

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

548 except AttributeError as e: 

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

550 raise OSError(msg) from e 

551 return encoder(mode, *args + extra) 

552 

553 

554# -------------------------------------------------------------------- 

555# Simple expression analyzer 

556 

557 

558class ImagePointTransform: 

559 """ 

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

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

562 ``scale`` and ``offset`` is added. 

563 """ 

564 

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

566 self.scale = scale 

567 self.offset = offset 

568 

569 def __neg__(self) -> ImagePointTransform: 

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

571 

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

573 if isinstance(other, ImagePointTransform): 

574 return ImagePointTransform( 

575 self.scale + other.scale, self.offset + other.offset 

576 ) 

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

578 

579 __radd__ = __add__ 

580 

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

582 return self + -other 

583 

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

585 return other + -self 

586 

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

588 if isinstance(other, ImagePointTransform): 

589 return NotImplemented 

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

591 

592 __rmul__ = __mul__ 

593 

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

595 if isinstance(other, ImagePointTransform): 

596 return NotImplemented 

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

598 

599 

600def _getscaleoffset( 

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

602) -> tuple[float, float]: 

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

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

605 

606 

607# -------------------------------------------------------------------- 

608# Implementation wrapper 

609 

610 

611class SupportsGetData(Protocol): 

612 def getdata( 

613 self, 

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

615 

616 

617class Image: 

618 """ 

619 This class represents an image object. To create 

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

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

622 directly. 

623 

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

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

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

627 """ 

628 

629 format: str | None = None 

630 format_description: str | None = None 

631 _close_exclusive_fp_after_loading = True 

632 

633 def __init__(self) -> None: 

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

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

636 self._mode = "" 

637 self._size = (0, 0) 

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

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

640 self.readonly = 0 

641 self._exif: Exif | None = None 

642 

643 @property 

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

645 if isinstance(self._im, DeferredError): 

646 raise self._im.ex 

647 assert self._im is not None 

648 return self._im 

649 

650 @im.setter 

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

652 self._im = im 

653 

654 @property 

655 def width(self) -> int: 

656 return self.size[0] 

657 

658 @property 

659 def height(self) -> int: 

660 return self.size[1] 

661 

662 @property 

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

664 return self._size 

665 

666 @property 

667 def mode(self) -> str: 

668 return self._mode 

669 

670 @property 

671 def readonly(self) -> int: 

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

673 

674 @readonly.setter 

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

676 self._readonly = readonly 

677 

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

679 new = Image() 

680 new.im = im 

681 new._mode = im.mode 

682 new._size = im.size 

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

684 if self.palette: 

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

686 else: 

687 from . import ImagePalette 

688 

689 new.palette = ImagePalette.ImagePalette() 

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

691 return new 

692 

693 # Context manager support 

694 def __enter__(self) -> Image: 

695 return self 

696 

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

698 pass 

699 

700 def close(self) -> None: 

701 """ 

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

703 The image data will be unusable afterward. 

704 

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

706 have not had their file read and closed by the 

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

708 more information. 

709 """ 

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

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

712 self.map.close() 

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

714 

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

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

717 # object is gone. 

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

719 

720 def _copy(self) -> None: 

721 self.load() 

722 self.im = self.im.copy() 

723 self.readonly = 0 

724 

725 def _ensure_mutable(self) -> None: 

726 if self.readonly: 

727 self._copy() 

728 else: 

729 self.load() 

730 

731 def _dump( 

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

733 ) -> str: 

734 suffix = "" 

735 if format: 

736 suffix = f".{format}" 

737 

738 if not file: 

739 f, filename = tempfile.mkstemp(suffix) 

740 os.close(f) 

741 else: 

742 filename = file 

743 if not filename.endswith(suffix): 

744 filename = filename + suffix 

745 

746 self.load() 

747 

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

749 self.im.save_ppm(filename) 

750 else: 

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

752 

753 return filename 

754 

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

756 if self.__class__ is not other.__class__: 

757 return False 

758 assert isinstance(other, Image) 

759 return ( 

760 self.mode == other.mode 

761 and self.size == other.size 

762 and self.info == other.info 

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

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

765 ) 

766 

767 def __repr__(self) -> str: 

768 return ( 

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

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

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

772 ) 

773 

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

775 """IPython plain text display support""" 

776 

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

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

779 p.text( 

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

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

782 ) 

783 

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

785 """Helper function for iPython display hook. 

786 

787 :param image_format: Image format. 

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

789 """ 

790 b = io.BytesIO() 

791 try: 

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

793 except Exception: 

794 return None 

795 return b.getvalue() 

796 

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

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

799 

800 :returns: PNG version of the image as bytes 

801 """ 

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

803 

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

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

806 

807 :returns: JPEG version of the image as bytes 

808 """ 

809 return self._repr_image("JPEG") 

810 

811 @property 

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

813 # numpy array interface support 

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

815 if self.mode == "1": 

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

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

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

819 else: 

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

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

822 return new 

823 

824 def __arrow_c_schema__(self) -> object: 

825 self.load() 

826 return self.im.__arrow_c_schema__() 

827 

828 def __arrow_c_array__( 

829 self, requested_schema: object | None = None 

830 ) -> tuple[object, object]: 

831 self.load() 

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

833 

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

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

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

837 

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

839 Image.__init__(self) 

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

841 self.info = info 

842 self._mode = mode 

843 self._size = size 

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

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

846 self.putpalette(palette) 

847 self.frombytes(data) 

848 

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

850 """ 

851 Return image as a bytes object. 

852 

853 .. warning:: 

854 

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

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

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

858 

859 :param encoder_name: What encoder to use. 

860 

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

862 To see how this packs pixel data into the returned 

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

864 

865 A list of C encoders can be seen under codecs 

866 section of the function array in 

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

868 within the relevant plugins. 

869 :param args: Extra arguments to the encoder. 

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

871 """ 

872 

873 encoder_args: Any = args 

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

875 # may pass tuple instead of argument list 

876 encoder_args = encoder_args[0] 

877 

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

879 encoder_args = self.mode 

880 

881 self.load() 

882 

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

884 return b"" 

885 

886 # unpack data 

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

888 e.setimage(self.im, (0, 0) + self.size) 

889 

890 from . import ImageFile 

891 

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

893 

894 output = [] 

895 while True: 

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

897 output.append(data) 

898 if errcode: 

899 break 

900 if errcode < 0: 

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

902 raise RuntimeError(msg) 

903 

904 return b"".join(output) 

905 

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

907 """ 

908 Returns the image converted to an X11 bitmap. 

909 

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

911 

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

913 :returns: A string containing an X11 bitmap. 

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

915 """ 

916 

917 self.load() 

918 if self.mode != "1": 

919 msg = "not a bitmap" 

920 raise ValueError(msg) 

921 data = self.tobytes("xbm") 

922 return b"".join( 

923 [ 

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

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

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

927 data, 

928 b"};", 

929 ] 

930 ) 

931 

932 def frombytes( 

933 self, 

934 data: bytes | bytearray | SupportsArrayInterface, 

935 decoder_name: str = "raw", 

936 *args: Any, 

937 ) -> None: 

938 """ 

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

940 

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

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

943 """ 

944 

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

946 return 

947 

948 decoder_args: Any = args 

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

950 # may pass tuple instead of argument list 

951 decoder_args = decoder_args[0] 

952 

953 # default format 

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

955 decoder_args = self.mode 

956 

957 # unpack data 

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

959 d.setimage(self.im, (0, 0) + self.size) 

960 s = d.decode(data) 

961 

962 if s[0] >= 0: 

963 msg = "not enough image data" 

964 raise ValueError(msg) 

965 if s[1] != 0: 

966 msg = "cannot decode image data" 

967 raise ValueError(msg) 

968 

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

970 """ 

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

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

973 Image class automatically loads an opened image when it is 

974 accessed for the first time. 

975 

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

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

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

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

980 

981 :returns: An image access object. 

982 :rtype: :py:class:`.PixelAccess` 

983 """ 

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

985 # realize palette 

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

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

988 self.palette.dirty = 0 

989 self.palette.rawmode = None 

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

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

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

993 else: 

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

995 self.palette.mode = "RGBA" 

996 elif self.palette.mode != mode: 

997 # If the palette rawmode is different to the mode, 

998 # then update the Python palette data 

999 self.palette.palette = self.im.getpalette( 

1000 self.palette.mode, self.palette.mode 

1001 ) 

1002 

1003 if self._im is not None: 

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

1005 return None 

1006 

1007 def verify(self) -> None: 

1008 """ 

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

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

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

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

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

1014 file. 

1015 """ 

1016 pass 

1017 

1018 def convert( 

1019 self, 

1020 mode: str | None = None, 

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

1022 dither: Dither | None = None, 

1023 palette: Palette = Palette.WEB, 

1024 colors: int = 256, 

1025 ) -> Image: 

1026 """ 

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

1028 method translates pixels through the palette. If mode is 

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

1030 and the palette can be represented without a palette. 

1031 

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

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

1034 

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

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

1037 

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

1039 

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

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

1042 dither to approximate the original image luminosity levels. If 

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

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

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

1046 

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

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

1049 and ``dither`` and ``palette`` are ignored. 

1050 

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

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

1053 

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

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

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

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

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

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

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

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

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

1063 :data:`Palette.ADAPTIVE`. 

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

1065 palette. Defaults to 256. 

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

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

1068 """ 

1069 

1070 self.load() 

1071 

1072 has_transparency = "transparency" in self.info 

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

1074 # determine default mode 

1075 if self.palette: 

1076 mode = self.palette.mode 

1077 else: 

1078 mode = "RGB" 

1079 if mode == "RGB" and has_transparency: 

1080 mode = "RGBA" 

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

1082 return self.copy() 

1083 

1084 if matrix: 

1085 # matrix conversion 

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

1087 msg = "illegal conversion" 

1088 raise ValueError(msg) 

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

1090 new_im = self._new(im) 

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

1092 transparency = new_im.info["transparency"] 

1093 

1094 def convert_transparency( 

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

1096 ) -> int: 

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

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

1099 

1100 if mode == "L": 

1101 transparency = convert_transparency(matrix, transparency) 

1102 elif len(mode) == 3: 

1103 transparency = tuple( 

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

1105 for i in range(len(transparency)) 

1106 ) 

1107 new_im.info["transparency"] = transparency 

1108 return new_im 

1109 

1110 if self.mode == "RGBA": 

1111 if mode == "P": 

1112 return self.quantize(colors) 

1113 elif mode == "PA": 

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

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

1116 p = rgb.quantize(colors) 

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

1118 

1119 trns = None 

1120 delete_trns = False 

1121 # transparency handling 

1122 if has_transparency: 

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

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

1125 ): 

1126 # Use transparent conversion to promote from transparent 

1127 # color to an alpha channel. 

1128 new_im = self._new( 

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

1130 ) 

1131 del new_im.info["transparency"] 

1132 return new_im 

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

1134 t = self.info["transparency"] 

1135 if isinstance(t, bytes): 

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

1137 warnings.warn( 

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

1139 "converted to RGBA images" 

1140 ) 

1141 delete_trns = True 

1142 else: 

1143 # get the new transparency color. 

1144 # use existing conversions 

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

1146 if self.mode == "P": 

1147 assert self.palette is not None 

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

1149 if isinstance(t, tuple): 

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

1151 assert trns_im.palette is not None 

1152 try: 

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

1154 except ValueError as e: 

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

1156 # If all 256 colors are in use, 

1157 # then there is no need for transparency 

1158 t = None 

1159 else: 

1160 raise ValueError(err) from e 

1161 if t is None: 

1162 trns = None 

1163 else: 

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

1165 

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

1167 trns_im = trns_im.convert(mode) 

1168 else: 

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

1170 # after quantization. 

1171 trns_im = trns_im.convert("RGB") 

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

1173 

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

1175 t = self.info["transparency"] 

1176 delete_trns = True 

1177 

1178 if isinstance(t, bytes): 

1179 self.im.putpalettealphas(t) 

1180 elif isinstance(t, int): 

1181 self.im.putpalettealpha(t, 0) 

1182 else: 

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

1184 raise ValueError(msg) 

1185 

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

1187 im = self.im.quantize(colors) 

1188 new_im = self._new(im) 

1189 from . import ImagePalette 

1190 

1191 new_im.palette = ImagePalette.ImagePalette( 

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

1193 ) 

1194 if delete_trns: 

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

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

1197 del new_im.info["transparency"] 

1198 if trns is not None: 

1199 try: 

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

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

1202 new_im, 

1203 ) 

1204 except Exception: 

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

1206 # transparency hanging around to mess us up. 

1207 del new_im.info["transparency"] 

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

1209 return new_im 

1210 

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

1212 im = self 

1213 if mode == "LAB": 

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

1215 im = im.convert("RGBA") 

1216 other_mode = im.mode 

1217 else: 

1218 other_mode = mode 

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

1220 from . import ImageCms 

1221 

1222 srgb = ImageCms.createProfile("sRGB") 

1223 lab = ImageCms.createProfile("LAB") 

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

1225 transform = ImageCms.buildTransform( 

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

1227 ) 

1228 return transform.apply(im) 

1229 

1230 # colorspace conversion 

1231 if dither is None: 

1232 dither = Dither.FLOYDSTEINBERG 

1233 

1234 try: 

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

1236 except ValueError: 

1237 try: 

1238 # normalize source image and try again 

1239 modebase = getmodebase(self.mode) 

1240 if modebase == self.mode: 

1241 raise 

1242 im = self.im.convert(modebase) 

1243 im = im.convert(mode, dither) 

1244 except KeyError as e: 

1245 msg = "illegal conversion" 

1246 raise ValueError(msg) from e 

1247 

1248 new_im = self._new(im) 

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

1250 from . import ImagePalette 

1251 

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

1253 if delete_trns: 

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

1255 del new_im.info["transparency"] 

1256 if trns is not None: 

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

1258 try: 

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

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

1261 ) 

1262 except ValueError as e: 

1263 del new_im.info["transparency"] 

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

1265 # If all 256 colors are in use, 

1266 # then there is no need for transparency 

1267 warnings.warn( 

1268 "Couldn't allocate palette entry for transparency" 

1269 ) 

1270 else: 

1271 new_im.info["transparency"] = trns 

1272 return new_im 

1273 

1274 def quantize( 

1275 self, 

1276 colors: int = 256, 

1277 method: int | None = None, 

1278 kmeans: int = 0, 

1279 palette: Image | None = None, 

1280 dither: Dither = Dither.FLOYDSTEINBERG, 

1281 ) -> Image: 

1282 """ 

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

1284 of colors. 

1285 

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

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

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

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

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

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

1292 ``feature="libimagequant"``). 

1293 

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

1295 

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

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

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

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

1300 :param palette: Quantize to the palette of given 

1301 :py:class:`PIL.Image.Image`. 

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

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

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

1305 (default). 

1306 :returns: A new image 

1307 """ 

1308 

1309 self.load() 

1310 

1311 if method is None: 

1312 # defaults: 

1313 method = Quantize.MEDIANCUT 

1314 if self.mode == "RGBA": 

1315 method = Quantize.FASTOCTREE 

1316 

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

1318 Quantize.FASTOCTREE, 

1319 Quantize.LIBIMAGEQUANT, 

1320 ): 

1321 # Caller specified an invalid mode. 

1322 msg = ( 

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

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

1325 ) 

1326 raise ValueError(msg) 

1327 

1328 if palette: 

1329 # use palette from reference image 

1330 palette.load() 

1331 if palette.mode != "P": 

1332 msg = "bad mode for palette image" 

1333 raise ValueError(msg) 

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

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

1336 raise ValueError(msg) 

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

1338 new_im = self._new(im) 

1339 assert palette.palette is not None 

1340 new_im.palette = palette.palette.copy() 

1341 return new_im 

1342 

1343 if kmeans < 0: 

1344 msg = "kmeans must not be negative" 

1345 raise ValueError(msg) 

1346 

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

1348 

1349 from . import ImagePalette 

1350 

1351 mode = im.im.getpalettemode() 

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

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

1354 

1355 return im 

1356 

1357 def copy(self) -> Image: 

1358 """ 

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

1360 into an image, but still retain the original. 

1361 

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

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

1364 """ 

1365 self.load() 

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

1367 

1368 __copy__ = copy 

1369 

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

1371 """ 

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

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

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

1375 

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

1377 

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

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

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

1381 """ 

1382 

1383 if box is None: 

1384 return self.copy() 

1385 

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

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

1388 raise ValueError(msg) 

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

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

1391 raise ValueError(msg) 

1392 

1393 self.load() 

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

1395 

1396 def _crop( 

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

1398 ) -> core.ImagingCore: 

1399 """ 

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

1401 

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

1403 includes additional sanity checks. 

1404 

1405 :param im: a core image object 

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

1407 :returns: A core image object. 

1408 """ 

1409 

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

1411 

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

1413 

1414 _decompression_bomb_check(absolute_values) 

1415 

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

1417 

1418 def draft( 

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

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

1421 """ 

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

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

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

1425 JPEG to grayscale while loading it. 

1426 

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

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

1429 

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

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

1432 effect. 

1433 

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

1435 currently implemented only for JPEG and MPO images. 

1436 

1437 :param mode: The requested mode. 

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

1439 (width, height). 

1440 """ 

1441 pass 

1442 

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

1444 """ 

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

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

1447 

1448 :param filter: Filter kernel. 

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

1450 

1451 from . import ImageFilter 

1452 

1453 self.load() 

1454 

1455 if callable(filter): 

1456 filter = filter() 

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

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

1459 raise TypeError(msg) 

1460 

1461 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1464 

1465 ims = [ 

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

1467 ] 

1468 return merge(self.mode, ims) 

1469 

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

1471 """ 

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

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

1474 

1475 :returns: A tuple containing band names. 

1476 :rtype: tuple 

1477 """ 

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

1479 

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

1481 """ 

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

1483 image. 

1484 

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

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

1487 Otherwise, trim pixels when all channels are zero. 

1488 Keyword-only argument. 

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

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

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

1492 method returns None. 

1493 

1494 """ 

1495 

1496 self.load() 

1497 return self.im.getbbox(alpha_only) 

1498 

1499 def getcolors( 

1500 self, maxcolors: int = 256 

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

1502 """ 

1503 Returns a list of colors used in this image. 

1504 

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

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

1507 return the index of the color in the palette. 

1508 

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

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

1511 256 colors. 

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

1513 """ 

1514 

1515 self.load() 

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

1517 h = self.im.histogram() 

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

1519 if len(out) > maxcolors: 

1520 return None 

1521 return out 

1522 return self.im.getcolors(maxcolors) 

1523 

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

1525 """ 

1526 Returns the contents of this image as a sequence object 

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

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

1529 line zero, and so on. 

1530 

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

1532 internal PIL data type, which only supports certain sequence 

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

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

1535 

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

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

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

1539 :returns: A sequence-like object. 

1540 """ 

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

1542 

1543 self.load() 

1544 if band is not None: 

1545 return self.im.getband(band) 

1546 return self.im # could be abused 

1547 

1548 def get_flattened_data( 

1549 self, band: int | None = None 

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

1551 """ 

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

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

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

1555 

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

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

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

1559 :returns: A tuple containing pixel values. 

1560 """ 

1561 self.load() 

1562 if band is not None: 

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

1564 return tuple(self.im) 

1565 

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

1567 """ 

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

1569 the image. 

1570 

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

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

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

1574 """ 

1575 

1576 self.load() 

1577 if self.im.bands > 1: 

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

1579 return self.im.getextrema() 

1580 

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

1582 """ 

1583 Returns a dictionary containing the XMP tags. 

1584 Requires defusedxml to be installed. 

1585 

1586 :returns: XMP tags in a dictionary. 

1587 """ 

1588 

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

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

1591 

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

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

1594 children = list(element) 

1595 if children: 

1596 for child in children: 

1597 name = get_name(child.tag) 

1598 child_value = get_value(child) 

1599 if name in value: 

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

1601 value[name] = [value[name]] 

1602 value[name].append(child_value) 

1603 else: 

1604 value[name] = child_value 

1605 elif value: 

1606 if element.text: 

1607 value["text"] = element.text 

1608 else: 

1609 return element.text 

1610 return value 

1611 

1612 if ElementTree is None: 

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

1614 return {} 

1615 if "xmp" not in self.info: 

1616 return {} 

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

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

1619 

1620 def getexif(self) -> Exif: 

1621 """ 

1622 Gets EXIF data from the image. 

1623 

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

1625 """ 

1626 if self._exif is None: 

1627 self._exif = Exif() 

1628 elif self._exif._loaded: 

1629 return self._exif 

1630 self._exif._loaded = True 

1631 

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

1633 if exif_info is None: 

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

1635 exif_info = bytes.fromhex( 

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

1637 ) 

1638 elif hasattr(self, "tag_v2"): 

1639 from . import TiffImagePlugin 

1640 

1641 assert isinstance(self, TiffImagePlugin.TiffImageFile) 

1642 self._exif.bigtiff = self.tag_v2._bigtiff 

1643 self._exif.endian = self.tag_v2._endian 

1644 

1645 assert self.fp is not None 

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

1647 if exif_info is not None: 

1648 self._exif.load(exif_info) 

1649 

1650 # XMP tags 

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

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

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

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

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

1656 if xmp_tags: 

1657 match = re.search(pattern, xmp_tags) 

1658 if match: 

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

1660 

1661 return self._exif 

1662 

1663 def _reload_exif(self) -> None: 

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

1665 return 

1666 self._exif._loaded = False 

1667 self.getexif() 

1668 

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

1670 from . import ImageFile 

1671 

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

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

1674 

1675 def getim(self) -> CapsuleType: 

1676 """ 

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

1678 

1679 :returns: A capsule object. 

1680 """ 

1681 

1682 self.load() 

1683 return self.im.ptr 

1684 

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

1686 """ 

1687 Returns the image palette as a list. 

1688 

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

1690 return the palette in its current mode. 

1691 

1692 .. versionadded:: 9.1.0 

1693 

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

1695 image has no palette. 

1696 """ 

1697 

1698 self.load() 

1699 try: 

1700 mode = self.im.getpalettemode() 

1701 except ValueError: 

1702 return None # no palette 

1703 if rawmode is None: 

1704 rawmode = mode 

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

1706 

1707 @property 

1708 def has_transparency_data(self) -> bool: 

1709 """ 

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

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

1712 in the info dictionary. 

1713 

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

1715 within are opaque. 

1716 

1717 :returns: A boolean. 

1718 """ 

1719 if ( 

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

1721 or "transparency" in self.info 

1722 ): 

1723 return True 

1724 if self.mode == "P": 

1725 assert self.palette is not None 

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

1727 return False 

1728 

1729 def apply_transparency(self) -> None: 

1730 """ 

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

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

1733 Otherwise, the image is unchanged. 

1734 """ 

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

1736 return 

1737 

1738 from . import ImagePalette 

1739 

1740 palette = self.getpalette("RGBA") 

1741 assert palette is not None 

1742 transparency = self.info["transparency"] 

1743 if isinstance(transparency, bytes): 

1744 for i, alpha in enumerate(transparency): 

1745 palette[i * 4 + 3] = alpha 

1746 else: 

1747 palette[transparency * 4 + 3] = 0 

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

1749 self.palette.dirty = 1 

1750 

1751 del self.info["transparency"] 

1752 

1753 def getpixel( 

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

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

1756 """ 

1757 Returns the pixel value at a given position. 

1758 

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

1760 :ref:`coordinate-system`. 

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

1762 this method returns a tuple. 

1763 """ 

1764 

1765 self.load() 

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

1767 

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

1769 """ 

1770 Get projection to x and y axes 

1771 

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

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

1774 """ 

1775 

1776 self.load() 

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

1778 return list(x), list(y) 

1779 

1780 def histogram( 

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

1782 ) -> list[int]: 

1783 """ 

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

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

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

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

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

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

1790 

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

1792 by this method. 

1793 

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

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

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

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

1798 

1799 :param mask: An optional mask. 

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

1801 :returns: A list containing pixel counts. 

1802 """ 

1803 self.load() 

1804 if mask: 

1805 mask.load() 

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

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

1808 return self.im.histogram( 

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

1810 ) 

1811 return self.im.histogram() 

1812 

1813 def entropy( 

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

1815 ) -> float: 

1816 """ 

1817 Calculates and returns the entropy for the image. 

1818 

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

1820 image by this method. 

1821 

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

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

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

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

1826 

1827 :param mask: An optional mask. 

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

1829 :returns: A float value representing the image entropy 

1830 """ 

1831 self.load() 

1832 if mask: 

1833 mask.load() 

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

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

1836 return self.im.entropy( 

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

1838 ) 

1839 return self.im.entropy() 

1840 

1841 def paste( 

1842 self, 

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

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

1845 mask: Image | None = None, 

1846 ) -> None: 

1847 """ 

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

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

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

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

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

1853 

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

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

1856 details). 

1857 

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

1859 containing pixel values. The method then fills the region 

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

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

1862 :ref:`colors` for more information. 

1863 

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

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

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

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

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

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

1870 channels if they have them. 

1871 

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

1873 combine images with respect to their alpha channels. 

1874 

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

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

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

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

1879 upper left corner. 

1880 

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

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

1883 is interpreted as a mask image. 

1884 :param mask: An optional mask image. 

1885 """ 

1886 

1887 if isinstance(box, Image): 

1888 if mask is not None: 

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

1890 raise ValueError(msg) 

1891 # abbreviated paste(im, mask) syntax 

1892 mask = box 

1893 box = None 

1894 

1895 if box is None: 

1896 box = (0, 0) 

1897 

1898 if len(box) == 2: 

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

1900 if isinstance(im, Image): 

1901 size = im.size 

1902 elif isinstance(mask, Image): 

1903 size = mask.size 

1904 else: 

1905 # FIXME: use self.size here? 

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

1907 raise ValueError(msg) 

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

1909 

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

1911 if isinstance(im, str): 

1912 from . import ImageColor 

1913 

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

1915 elif isinstance(im, Image): 

1916 im.load() 

1917 if self.mode != im.mode: 

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

1919 # should use an adapter for this! 

1920 im = im.convert(self.mode) 

1921 source = im.im 

1922 else: 

1923 source = im 

1924 

1925 self._ensure_mutable() 

1926 

1927 if mask: 

1928 mask.load() 

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

1930 else: 

1931 self.im.paste(source, box) 

1932 

1933 def alpha_composite( 

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

1935 ) -> None: 

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

1937 onto this image. 

1938 

1939 :param im: image to composite over this one 

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

1941 left corner in this (destination) image. 

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

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

1944 bottom) for the bounds of the source rectangle 

1945 

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

1947 """ 

1948 

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

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

1951 raise ValueError(msg) 

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

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

1954 raise ValueError(msg) 

1955 

1956 if len(source) == 4: 

1957 overlay_crop_box = tuple(source) 

1958 elif len(source) == 2: 

1959 overlay_crop_box = tuple(source) + im.size 

1960 else: 

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

1962 raise ValueError(msg) 

1963 

1964 if not len(dest) == 2: 

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

1966 raise ValueError(msg) 

1967 if min(source) < 0: 

1968 msg = "Source must be non-negative" 

1969 raise ValueError(msg) 

1970 

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

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

1973 overlay = im 

1974 else: 

1975 overlay = im.crop(overlay_crop_box) 

1976 

1977 # target for the paste 

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

1979 

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

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

1982 background = self 

1983 else: 

1984 background = self.crop(box) 

1985 

1986 result = alpha_composite(background, overlay) 

1987 self.paste(result, box) 

1988 

1989 def point( 

1990 self, 

1991 lut: ( 

1992 Sequence[float] 

1993 | NumpyArray 

1994 | Callable[[int], float] 

1995 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1996 | ImagePointHandler 

1997 ), 

1998 mode: str | None = None, 

1999 ) -> Image: 

2000 """ 

2001 Maps this image through a lookup table or function. 

2002 

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

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

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

2006 single argument. The function is called once for each 

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

2008 all bands of the image. 

2009 

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

2011 object:: 

2012 

2013 class Example(Image.ImagePointHandler): 

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

2015 # Return result 

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

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

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

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

2020 """ 

2021 

2022 self.load() 

2023 

2024 if isinstance(lut, ImagePointHandler): 

2025 return lut.point(self) 

2026 

2027 if callable(lut): 

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

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

2030 # check if the function can be used with point_transform 

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

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

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

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

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

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

2037 else: 

2038 flatLut = lut 

2039 

2040 if self.mode == "F": 

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

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

2043 raise ValueError(msg) 

2044 

2045 if mode != "F": 

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

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

2048 

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

2050 """ 

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

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

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

2054 

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

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

2057 """ 

2058 

2059 self._ensure_mutable() 

2060 

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

2062 # attempt to promote self to a matching alpha mode 

2063 try: 

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

2065 try: 

2066 self.im.setmode(mode) 

2067 except (AttributeError, ValueError) as e: 

2068 # do things the hard way 

2069 im = self.im.convert(mode) 

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

2071 msg = "alpha channel could not be added" 

2072 raise ValueError(msg) from e # sanity check 

2073 self.im = im 

2074 self._mode = self.im.mode 

2075 except KeyError as e: 

2076 msg = "illegal image mode" 

2077 raise ValueError(msg) from e 

2078 

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

2080 band = 1 

2081 else: 

2082 band = 3 

2083 

2084 if isinstance(alpha, Image): 

2085 # alpha layer 

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

2087 msg = "illegal image mode" 

2088 raise ValueError(msg) 

2089 alpha.load() 

2090 if alpha.mode == "1": 

2091 alpha = alpha.convert("L") 

2092 else: 

2093 # constant alpha 

2094 try: 

2095 self.im.fillband(band, alpha) 

2096 except (AttributeError, ValueError): 

2097 # do things the hard way 

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

2099 else: 

2100 return 

2101 

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

2103 

2104 def putdata( 

2105 self, 

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

2107 scale: float = 1.0, 

2108 offset: float = 0.0, 

2109 ) -> None: 

2110 """ 

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

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

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

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

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

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

2117 

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

2119 information about values. 

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

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

2122 """ 

2123 

2124 self._ensure_mutable() 

2125 

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

2127 

2128 def putpalette( 

2129 self, 

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

2131 rawmode: str = "RGB", 

2132 ) -> None: 

2133 """ 

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

2135 or "LA" image. 

2136 

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

2138 integer value for each channel in the raw mode. 

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

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

2141 index in the 256 colors. 

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

2143 containing red, green, blue and alpha values. 

2144 

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

2146 

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

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

2149 mode that can be transformed to one of those modes (e.g. "R", "RGBA;L"). 

2150 """ 

2151 from . import ImagePalette 

2152 

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

2154 msg = "illegal image mode" 

2155 raise ValueError(msg) 

2156 if isinstance(data, ImagePalette.ImagePalette): 

2157 if data.rawmode is not None: 

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

2159 else: 

2160 palette = ImagePalette.ImagePalette(palette=data.palette) 

2161 palette.dirty = 1 

2162 else: 

2163 if not isinstance(data, bytes): 

2164 data = bytes(data) 

2165 palette = ImagePalette.raw(rawmode, data) 

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

2167 self.palette = palette 

2168 if rawmode.startswith("CMYK"): 

2169 self.palette.mode = "CMYK" 

2170 elif "A" in rawmode: 

2171 self.palette.mode = "RGBA" 

2172 else: 

2173 self.palette.mode = "RGB" 

2174 self.load() # install new palette 

2175 

2176 def putpixel( 

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

2178 ) -> None: 

2179 """ 

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

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

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

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

2184 

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

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

2187 module instead. 

2188 

2189 See: 

2190 

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

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

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

2194 

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

2196 :ref:`coordinate-system`. 

2197 :param value: The pixel value. 

2198 """ 

2199 

2200 self._ensure_mutable() 

2201 

2202 if ( 

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

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

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

2206 ): 

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

2208 if self.mode == "PA": 

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

2210 value = value[:3] 

2211 assert self.palette is not None 

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

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

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

2215 

2216 def remap_palette( 

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

2218 ) -> Image: 

2219 """ 

2220 Rewrites the image to reorder the palette. 

2221 

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

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

2224 is the identity transform. 

2225 :param source_palette: Bytes or None. 

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

2227 

2228 """ 

2229 from . import ImagePalette 

2230 

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

2232 msg = "illegal image mode" 

2233 raise ValueError(msg) 

2234 

2235 bands = 3 

2236 palette_mode = "RGB" 

2237 if source_palette is None: 

2238 if self.mode == "P": 

2239 self.load() 

2240 palette_mode = self.im.getpalettemode() 

2241 if palette_mode == "RGBA": 

2242 bands = 4 

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

2244 else: # L-mode 

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

2246 elif len(source_palette) > 768: 

2247 bands = 4 

2248 palette_mode = "RGBA" 

2249 

2250 palette_bytes = b"" 

2251 new_positions = [0] * 256 

2252 

2253 # pick only the used colors from the palette 

2254 for i, oldPosition in enumerate(dest_map): 

2255 palette_bytes += source_palette[ 

2256 oldPosition * bands : oldPosition * bands + bands 

2257 ] 

2258 new_positions[oldPosition] = i 

2259 

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

2261 

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

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

2264 # from palette 1 to palette 2. New_positions is 

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

2266 # palette 1 with any holes removed. 

2267 

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

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

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

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

2272 # sans palette thus converting the image bytes, then 

2273 # assigning the optimized RGB palette. 

2274 

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

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

2277 

2278 mapping_palette = bytearray(new_positions) 

2279 

2280 m_im = self.copy() 

2281 m_im._mode = "P" 

2282 

2283 m_im.palette = ImagePalette.ImagePalette( 

2284 palette_mode, palette=mapping_palette * bands 

2285 ) 

2286 # possibly set palette dirty, then 

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

2288 # or just force it. 

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

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

2291 

2292 m_im = m_im.convert("L") 

2293 

2294 m_im.putpalette(palette_bytes, palette_mode) 

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

2296 

2297 if "transparency" in self.info: 

2298 try: 

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

2300 except ValueError: 

2301 if "transparency" in m_im.info: 

2302 del m_im.info["transparency"] 

2303 

2304 return m_im 

2305 

2306 def _get_safe_box( 

2307 self, 

2308 size: tuple[int, int], 

2309 resample: Resampling, 

2310 box: tuple[float, float, float, float], 

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

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

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

2314 """ 

2315 filter_support = _filters_support[resample] - 0.5 

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

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

2318 support_x = filter_support * scale_x 

2319 support_y = filter_support * scale_y 

2320 

2321 return ( 

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

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

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

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

2326 ) 

2327 

2328 def resize( 

2329 self, 

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

2331 resample: int | None = None, 

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

2333 reducing_gap: float | None = None, 

2334 ) -> Image: 

2335 """ 

2336 Returns a resized copy of this image. 

2337 

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

2339 (width, height). 

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

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

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

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

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

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

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

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

2348 the source image region to be scaled. 

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

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

2351 :param reducing_gap: Apply optimization by resizing the image 

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

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

2354 Second, resizing using regular resampling. The last step 

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

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

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

2358 the closer the result to the fair resampling. 

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

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

2361 indistinguishable from fair resampling in most cases. 

2362 The default value is None (no optimization). 

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

2364 """ 

2365 

2366 if resample is None: 

2367 resample = Resampling.BICUBIC 

2368 elif resample not in ( 

2369 Resampling.NEAREST, 

2370 Resampling.BILINEAR, 

2371 Resampling.BICUBIC, 

2372 Resampling.LANCZOS, 

2373 Resampling.BOX, 

2374 Resampling.HAMMING, 

2375 ): 

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

2377 

2378 filters = [ 

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

2380 for filter in ( 

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

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

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

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

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

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

2387 ) 

2388 ] 

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

2390 raise ValueError(msg) 

2391 

2392 if reducing_gap is not None and reducing_gap < 1.0: 

2393 msg = "reducing_gap must be 1.0 or greater" 

2394 raise ValueError(msg) 

2395 

2396 if box is None: 

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

2398 

2399 size = tuple(size) 

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

2401 return self.copy() 

2402 

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

2404 resample = Resampling.NEAREST 

2405 

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

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

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

2409 return im.convert(self.mode) 

2410 

2411 self.load() 

2412 

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

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

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

2416 if factor_x > 1 or factor_y > 1: 

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

2418 factor = (factor_x, factor_y) 

2419 self = ( 

2420 self.reduce(factor, box=reduce_box) 

2421 if callable(self.reduce) 

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

2423 ) 

2424 box = ( 

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

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

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

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

2429 ) 

2430 

2431 if self.size[1] > self.size[0] * 100 and size[1] < self.size[1]: 

2432 im = self.im.resize( 

2433 (self.size[0], size[1]), resample, (0, box[1], self.size[0], box[3]) 

2434 ) 

2435 im = im.resize(size, resample, (box[0], 0, box[2], size[1])) 

2436 else: 

2437 im = self.im.resize(size, resample, box) 

2438 return self._new(im) 

2439 

2440 def reduce( 

2441 self, 

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

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

2444 ) -> Image: 

2445 """ 

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

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

2448 the resulting size will be rounded up. 

2449 

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

2451 for width and height separately. 

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

2453 the source image region to be reduced. 

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

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

2456 """ 

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

2458 factor = (factor, factor) 

2459 

2460 if box is None: 

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

2462 

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

2464 return self.copy() 

2465 

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

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

2468 im = im.reduce(factor, box) 

2469 return im.convert(self.mode) 

2470 

2471 self.load() 

2472 

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

2474 

2475 def rotate( 

2476 self, 

2477 angle: float, 

2478 resample: Resampling = Resampling.NEAREST, 

2479 expand: int | bool = False, 

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

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

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

2483 ) -> Image: 

2484 """ 

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

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

2487 clockwise around its centre. 

2488 

2489 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2496 See :ref:`concept-filters`. 

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

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

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

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

2501 the center and no translation. 

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

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

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

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

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

2507 """ 

2508 

2509 angle = angle % 360.0 

2510 

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

2512 # translating or changing the center. 

2513 if not (center or translate): 

2514 if angle == 0: 

2515 return self.copy() 

2516 if angle == 180: 

2517 return self.transpose(Transpose.ROTATE_180) 

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

2519 return self.transpose( 

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

2521 ) 

2522 

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

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

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

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

2527 

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

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

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

2531 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2532 

2533 # The reverse matrix is thus: 

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

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

2536 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2537 

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

2539 # compensate for the expand flag. 

2540 

2541 w, h = self.size 

2542 

2543 if translate is None: 

2544 post_trans = (0, 0) 

2545 else: 

2546 post_trans = translate 

2547 if center is None: 

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

2549 

2550 angle = -math.radians(angle) 

2551 matrix = [ 

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

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

2554 0.0, 

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

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

2557 0.0, 

2558 ] 

2559 

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

2561 a, b, c, d, e, f = matrix 

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

2563 

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

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

2566 ) 

2567 matrix[2] += center[0] 

2568 matrix[5] += center[1] 

2569 

2570 if expand: 

2571 # calculate output size 

2572 xx = [] 

2573 yy = [] 

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

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

2576 xx.append(transformed_x) 

2577 yy.append(transformed_y) 

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

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

2580 

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

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

2583 # translation vector as new translation vector. 

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

2585 w, h = nw, nh 

2586 

2587 return self.transform( 

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

2589 ) 

2590 

2591 def save( 

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

2593 ) -> None: 

2594 """ 

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

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

2597 extension, if possible. 

2598 

2599 Keyword options can be used to provide additional instructions 

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

2601 silently ignored. The available options are described in the 

2602 :doc:`image format documentation 

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

2604 

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

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

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

2608 methods, and be opened in binary mode. 

2609 

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

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

2612 format to use is determined from the filename extension. 

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

2614 parameter should always be used. 

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

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

2617 saving multiple images:: 

2618 

2619 # Saving XMP data to a single image 

2620 from PIL import Image 

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

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

2623 

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

2625 from PIL import Image 

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

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

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

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

2630 :returns: None 

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

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

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

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

2635 """ 

2636 

2637 filename: str | bytes = "" 

2638 open_fp = False 

2639 if is_path(fp): 

2640 filename = os.fspath(fp) 

2641 open_fp = True 

2642 elif fp == sys.stdout and isinstance(sys.stdout, io.TextIOWrapper): 

2643 fp = sys.stdout.buffer 

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

2645 # only set the name for metadata purposes 

2646 filename = os.fspath(fp.name) 

2647 

2648 if format: 

2649 preinit() 

2650 else: 

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

2652 ext = ( 

2653 filename_ext.decode() 

2654 if isinstance(filename_ext, bytes) 

2655 else filename_ext 

2656 ) 

2657 

2658 # Try importing only the plugin for this extension first 

2659 if not _import_plugin_for_extension(ext): 

2660 preinit() 

2661 

2662 if ext not in EXTENSION: 

2663 init() 

2664 try: 

2665 format = EXTENSION[ext] 

2666 except KeyError as e: 

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

2668 raise ValueError(msg) from e 

2669 

2670 from . import ImageFile 

2671 

2672 # may mutate self! 

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

2674 filename 

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

2676 self._ensure_mutable() 

2677 else: 

2678 self.load() 

2679 

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

2681 self._default_encoderinfo = params 

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

2683 self._attach_default_encoderinfo(self) 

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

2685 

2686 if format.upper() not in SAVE: 

2687 init() 

2688 if save_all or ( 

2689 save_all is None 

2690 and params.get("append_images") 

2691 and format.upper() in SAVE_ALL 

2692 ): 

2693 save_handler = SAVE_ALL[format.upper()] 

2694 else: 

2695 save_handler = SAVE[format.upper()] 

2696 

2697 created = False 

2698 if open_fp: 

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

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

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

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

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

2704 else: 

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

2706 else: 

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

2708 

2709 try: 

2710 save_handler(self, fp, filename) 

2711 except Exception: 

2712 if open_fp: 

2713 fp.close() 

2714 if created: 

2715 try: 

2716 os.remove(filename) 

2717 except PermissionError: 

2718 pass 

2719 raise 

2720 finally: 

2721 self.encoderinfo = encoderinfo 

2722 if open_fp: 

2723 fp.close() 

2724 

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

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

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

2728 return encoderinfo 

2729 

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

2731 """ 

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

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

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

2735 library automatically seeks to frame 0. 

2736 

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

2738 

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

2740 number of available frames. 

2741 

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

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

2744 of the sequence. 

2745 """ 

2746 

2747 # overridden by file handlers 

2748 if frame != 0: 

2749 msg = "no more images in file" 

2750 raise EOFError(msg) 

2751 

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

2753 """ 

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

2755 

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

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

2758 

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

2760 PNG format. 

2761 

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

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

2764 

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

2766 

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

2768 

2769 :param title: Optional title to use for the image window, where possible. 

2770 """ 

2771 

2772 from . import ImageShow 

2773 

2774 ImageShow.show(self, title) 

2775 

2776 def split(self) -> tuple[Image, ...]: 

2777 """ 

2778 Split this image into individual bands. This method returns a 

2779 tuple of individual image bands from an image. For example, 

2780 splitting an "RGB" image creates three new images each 

2781 containing a copy of one of the original bands (red, green, 

2782 blue). 

2783 

2784 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel` 

2785 method can be more convenient and faster. 

2786 

2787 :returns: A tuple containing bands. 

2788 """ 

2789 

2790 self.load() 

2791 if self.im.bands == 1: 

2792 return (self.copy(),) 

2793 return tuple(map(self._new, self.im.split())) 

2794 

2795 def getchannel(self, channel: int | str) -> Image: 

2796 """ 

2797 Returns an image containing a single channel of the source image. 

2798 

2799 :param channel: What channel to return. Could be index 

2800 (0 for "R" channel of "RGB") or channel name 

2801 ("A" for alpha channel of "RGBA"). 

2802 :returns: An image in "L" mode. 

2803 

2804 .. versionadded:: 4.3.0 

2805 """ 

2806 self.load() 

2807 

2808 if isinstance(channel, str): 

2809 try: 

2810 channel = self.getbands().index(channel) 

2811 except ValueError as e: 

2812 msg = f'The image has no channel "{channel}"' 

2813 raise ValueError(msg) from e 

2814 

2815 return self._new(self.im.getband(channel)) 

2816 

2817 def tell(self) -> int: 

2818 """ 

2819 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. 

2820 

2821 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the 

2822 number of available frames. 

2823 

2824 :returns: Frame number, starting with 0. 

2825 """ 

2826 return 0 

2827 

2828 def thumbnail( 

2829 self, 

2830 size: tuple[float, float], 

2831 resample: Resampling = Resampling.BICUBIC, 

2832 reducing_gap: float | None = 2.0, 

2833 ) -> None: 

2834 """ 

2835 Make this image into a thumbnail. This method modifies the 

2836 image to contain a thumbnail version of itself, no larger than 

2837 the given size. This method calculates an appropriate thumbnail 

2838 size to preserve the aspect of the image, calls the 

2839 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader 

2840 (where applicable), and finally resizes the image. 

2841 

2842 Note that this function modifies the :py:class:`~PIL.Image.Image` 

2843 object in place. If you need to use the full resolution image as well, 

2844 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original 

2845 image. 

2846 

2847 :param size: The requested size in pixels, as a 2-tuple: 

2848 (width, height). 

2849 :param resample: Optional resampling filter. This can be one 

2850 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, 

2851 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, 

2852 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. 

2853 If omitted, it defaults to :py:data:`Resampling.BICUBIC`. 

2854 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0). 

2855 See: :ref:`concept-filters`. 

2856 :param reducing_gap: Apply optimization by resizing the image 

2857 in two steps. First, reducing the image by integer times 

2858 using :py:meth:`~PIL.Image.Image.reduce` or 

2859 :py:meth:`~PIL.Image.Image.draft` for JPEG images. 

2860 Second, resizing using regular resampling. The last step 

2861 changes size no less than by ``reducing_gap`` times. 

2862 ``reducing_gap`` may be None (no first step is performed) 

2863 or should be greater than 1.0. The bigger ``reducing_gap``, 

2864 the closer the result to the fair resampling. 

2865 The smaller ``reducing_gap``, the faster resizing. 

2866 With ``reducing_gap`` greater or equal to 3.0, the result is 

2867 indistinguishable from fair resampling in most cases. 

2868 The default value is 2.0 (very close to fair resampling 

2869 while still being faster in many cases). 

2870 :returns: None 

2871 """ 

2872 

2873 provided_size = tuple(map(math.floor, size)) 

2874 

2875 def preserve_aspect_ratio() -> tuple[int, int] | None: 

2876 def round_aspect(number: float, key: Callable[[int], float]) -> int: 

2877 return max(min(math.floor(number), math.ceil(number), key=key), 1) 

2878 

2879 x, y = provided_size 

2880 if x >= self.width and y >= self.height: 

2881 return None 

2882 

2883 aspect = self.width / self.height 

2884 if x / y >= aspect: 

2885 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) 

2886 else: 

2887 y = round_aspect( 

2888 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n) 

2889 ) 

2890 return x, y 

2891 

2892 preserved_size = preserve_aspect_ratio() 

2893 if preserved_size is None: 

2894 return 

2895 final_size = preserved_size 

2896 

2897 box = None 

2898 if reducing_gap is not None: 

2899 res = self.draft( 

2900 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) 

2901 ) 

2902 if res is not None: 

2903 box = res[1] 

2904 

2905 if self.size != final_size: 

2906 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) 

2907 

2908 self.im = im.im 

2909 self._size = final_size 

2910 self._mode = self.im.mode 

2911 

2912 self.readonly = 0 

2913 

2914 # FIXME: the different transform methods need further explanation 

2915 # instead of bloating the method docs, add a separate chapter. 

2916 def transform( 

2917 self, 

2918 size: tuple[int, int], 

2919 method: Transform | ImageTransformHandler | SupportsGetData, 

2920 data: Sequence[Any] | None = None, 

2921 resample: int = Resampling.NEAREST, 

2922 fill: int = 1, 

2923 fillcolor: float | tuple[float, ...] | str | None = None, 

2924 ) -> Image: 

2925 """ 

2926 Transforms this image. This method creates a new image with the 

2927 given size, and the same mode as the original, and copies data 

2928 to the new image using the given transform. 

2929 

2930 :param size: The output size in pixels, as a 2-tuple: 

2931 (width, height). 

2932 :param method: The transformation method. This is one of 

2933 :py:data:`Transform.EXTENT` (cut out a rectangular subregion), 

2934 :py:data:`Transform.AFFINE` (affine transform), 

2935 :py:data:`Transform.PERSPECTIVE` (perspective transform), 

2936 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or 

2937 :py:data:`Transform.MESH` (map a number of source quadrilaterals 

2938 in one operation). 

2939 

2940 It may also be an :py:class:`~PIL.Image.ImageTransformHandler` 

2941 object:: 

2942 

2943 class Example(Image.ImageTransformHandler): 

2944 def transform(self, size, data, resample, fill=1): 

2945 # Return result 

2946 

2947 Implementations of :py:class:`~PIL.Image.ImageTransformHandler` 

2948 for some of the :py:class:`Transform` methods are provided 

2949 in :py:mod:`~PIL.ImageTransform`. 

2950 

2951 It may also be an object with a ``method.getdata`` method 

2952 that returns a tuple supplying new ``method`` and ``data`` values:: 

2953 

2954 class Example: 

2955 def getdata(self): 

2956 method = Image.Transform.EXTENT 

2957 data = (0, 0, 100, 100) 

2958 return method, data 

2959 :param data: Extra data to the transformation method. 

2960 :param resample: Optional resampling filter. It can be one of 

2961 :py:data:`Resampling.NEAREST` (use nearest neighbour), 

2962 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 

2963 environment), or :py:data:`Resampling.BICUBIC` (cubic spline 

2964 interpolation in a 4x4 environment). If omitted, or if the image 

2965 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. 

2966 See: :ref:`concept-filters`. 

2967 :param fill: If ``method`` is an 

2968 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of 

2969 the arguments passed to it. Otherwise, it is unused. 

2970 :param fillcolor: Optional fill color for the area outside the 

2971 transform in the output image. 

2972 :returns: An :py:class:`~PIL.Image.Image` object. 

2973 """ 

2974 

2975 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: 

2976 return ( 

2977 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2978 .transform(size, method, data, resample, fill, fillcolor) 

2979 .convert(self.mode) 

2980 ) 

2981 

2982 if isinstance(method, ImageTransformHandler): 

2983 return method.transform(size, self, resample=resample, fill=fill) 

2984 

2985 if hasattr(method, "getdata"): 

2986 # compatibility w. old-style transform objects 

2987 method, data = method.getdata() 

2988 

2989 if data is None: 

2990 msg = "missing method data" 

2991 raise ValueError(msg) 

2992 

2993 im = new(self.mode, size, fillcolor) 

2994 if self.mode == "P" and self.palette: 

2995 im.palette = self.palette.copy() 

2996 im.info = self.info.copy() 

2997 if method == Transform.MESH: 

2998 # list of quads 

2999 for box, quad in data: 

3000 im.__transformer( 

3001 box, self, Transform.QUAD, quad, resample, fillcolor is None 

3002 ) 

3003 else: 

3004 im.__transformer( 

3005 (0, 0) + size, self, method, data, resample, fillcolor is None 

3006 ) 

3007 

3008 return im 

3009 

3010 def __transformer( 

3011 self, 

3012 box: tuple[int, int, int, int], 

3013 image: Image, 

3014 method: Transform, 

3015 data: Sequence[float], 

3016 resample: int = Resampling.NEAREST, 

3017 fill: bool = True, 

3018 ) -> None: 

3019 w = box[2] - box[0] 

3020 h = box[3] - box[1] 

3021 

3022 if method == Transform.AFFINE: 

3023 data = data[:6] 

3024 

3025 elif method == Transform.EXTENT: 

3026 # convert extent to an affine transform 

3027 x0, y0, x1, y1 = data 

3028 xs = (x1 - x0) / w 

3029 ys = (y1 - y0) / h 

3030 method = Transform.AFFINE 

3031 data = (xs, 0, x0, 0, ys, y0) 

3032 

3033 elif method == Transform.PERSPECTIVE: 

3034 data = data[:8] 

3035 

3036 elif method == Transform.QUAD: 

3037 # quadrilateral warp. data specifies the four corners 

3038 # given as NW, SW, SE, and NE. 

3039 nw = data[:2] 

3040 sw = data[2:4] 

3041 se = data[4:6] 

3042 ne = data[6:8] 

3043 x0, y0 = nw 

3044 As = 1.0 / w 

3045 At = 1.0 / h 

3046 data = ( 

3047 x0, 

3048 (ne[0] - x0) * As, 

3049 (sw[0] - x0) * At, 

3050 (se[0] - sw[0] - ne[0] + x0) * As * At, 

3051 y0, 

3052 (ne[1] - y0) * As, 

3053 (sw[1] - y0) * At, 

3054 (se[1] - sw[1] - ne[1] + y0) * As * At, 

3055 ) 

3056 

3057 else: 

3058 msg = "unknown transformation method" 

3059 raise ValueError(msg) 

3060 

3061 if resample not in ( 

3062 Resampling.NEAREST, 

3063 Resampling.BILINEAR, 

3064 Resampling.BICUBIC, 

3065 ): 

3066 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

3067 unusable: dict[int, str] = { 

3068 Resampling.BOX: "Image.Resampling.BOX", 

3069 Resampling.HAMMING: "Image.Resampling.HAMMING", 

3070 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

3071 } 

3072 msg = unusable[resample] + f" ({resample}) cannot be used." 

3073 else: 

3074 msg = f"Unknown resampling filter ({resample})." 

3075 

3076 filters = [ 

3077 f"{filter[1]} ({filter[0]})" 

3078 for filter in ( 

3079 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

3080 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

3081 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

3082 ) 

3083 ] 

3084 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

3085 raise ValueError(msg) 

3086 

3087 image.load() 

3088 

3089 self.load() 

3090 

3091 if image.mode in ("1", "P"): 

3092 resample = Resampling.NEAREST 

3093 

3094 self.im.transform(box, image.im, method, data, resample, fill) 

3095 

3096 def transpose(self, method: Transpose) -> Image: 

3097 """ 

3098 Transpose image (flip or rotate in 90 degree steps) 

3099 

3100 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

3101 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

3102 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

3103 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

3104 :returns: Returns a flipped or rotated copy of this image. 

3105 """ 

3106 

3107 self.load() 

3108 return self._new(self.im.transpose(method)) 

3109 

3110 def effect_spread(self, distance: int) -> Image: 

3111 """ 

3112 Randomly spread pixels in an image. 

3113 

3114 :param distance: Distance to spread pixels. 

3115 """ 

3116 self.load() 

3117 return self._new(self.im.effect_spread(distance)) 

3118 

3119 def toqimage(self) -> ImageQt.ImageQt: 

3120 """Returns a QImage copy of this image""" 

3121 from . import ImageQt 

3122 

3123 if not ImageQt.qt_is_installed: 

3124 msg = "Qt bindings are not installed" 

3125 raise ImportError(msg) 

3126 return ImageQt.toqimage(self) 

3127 

3128 def toqpixmap(self) -> ImageQt.QPixmap: 

3129 """Returns a QPixmap copy of this image""" 

3130 from . import ImageQt 

3131 

3132 if not ImageQt.qt_is_installed: 

3133 msg = "Qt bindings are not installed" 

3134 raise ImportError(msg) 

3135 return ImageQt.toqpixmap(self) 

3136 

3137 

3138# -------------------------------------------------------------------- 

3139# Abstract handlers. 

3140 

3141 

3142class ImagePointHandler(abc.ABC): 

3143 """ 

3144 Used as a mixin by point transforms 

3145 (for use with :py:meth:`~PIL.Image.Image.point`) 

3146 """ 

3147 

3148 @abc.abstractmethod 

3149 def point(self, im: Image) -> Image: 

3150 pass 

3151 

3152 

3153class ImageTransformHandler(abc.ABC): 

3154 """ 

3155 Used as a mixin by geometry transforms 

3156 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3157 """ 

3158 

3159 @abc.abstractmethod 

3160 def transform( 

3161 self, 

3162 size: tuple[int, int], 

3163 image: Image, 

3164 **options: Any, 

3165 ) -> Image: 

3166 pass 

3167 

3168 

3169# -------------------------------------------------------------------- 

3170# Factories 

3171 

3172 

3173def _check_size(size: Any) -> None: 

3174 """ 

3175 Common check to enforce type and sanity check on size tuples 

3176 

3177 :param size: Should be a 2 tuple of (width, height) 

3178 :returns: None, or raises a ValueError 

3179 """ 

3180 

3181 if not isinstance(size, (list, tuple)): 

3182 msg = "Size must be a list or tuple" 

3183 raise ValueError(msg) 

3184 if len(size) != 2: 

3185 msg = "Size must be a sequence of length 2" 

3186 raise ValueError(msg) 

3187 if size[0] < 0 or size[1] < 0: 

3188 msg = "Width and height must be >= 0" 

3189 raise ValueError(msg) 

3190 

3191 

3192def new( 

3193 mode: str, 

3194 size: tuple[int, int] | list[int], 

3195 color: float | tuple[float, ...] | str | None = 0, 

3196) -> Image: 

3197 """ 

3198 Creates a new image with the given mode and size. 

3199 

3200 :param mode: The mode to use for the new image. See: 

3201 :ref:`concept-modes`. 

3202 :param size: A 2-tuple, containing (width, height) in pixels. 

3203 :param color: What color to use for the image. Default is black. If given, 

3204 this should be a single integer or floating point value for single-band 

3205 modes, and a tuple for multi-band modes (one value per band). When 

3206 creating RGB or HSV images, you can also use color strings as supported 

3207 by the ImageColor module. See :ref:`colors` for more information. If the 

3208 color is None, the image is not initialised. 

3209 :returns: An :py:class:`~PIL.Image.Image` object. 

3210 """ 

3211 

3212 _check_size(size) 

3213 

3214 if color is None: 

3215 # don't initialize 

3216 return Image()._new(core.new(mode, size)) 

3217 

3218 if isinstance(color, str): 

3219 # css3-style specifier 

3220 

3221 from . import ImageColor 

3222 

3223 color = ImageColor.getcolor(color, mode) 

3224 

3225 im = Image() 

3226 if ( 

3227 mode == "P" 

3228 and isinstance(color, (list, tuple)) 

3229 and all(isinstance(i, int) for i in color) 

3230 ): 

3231 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3232 if len(color_ints) == 3 or len(color_ints) == 4: 

3233 # RGB or RGBA value for a P image 

3234 from . import ImagePalette 

3235 

3236 im.palette = ImagePalette.ImagePalette() 

3237 color = im.palette.getcolor(color_ints) 

3238 return im._new(core.fill(mode, size, color)) 

3239 

3240 

3241def frombytes( 

3242 mode: str, 

3243 size: tuple[int, int], 

3244 data: bytes | bytearray | SupportsArrayInterface, 

3245 decoder_name: str = "raw", 

3246 *args: Any, 

3247) -> Image: 

3248 """ 

3249 Creates a copy of an image memory from pixel data in a buffer. 

3250 

3251 In its simplest form, this function takes three arguments 

3252 (mode, size, and unpacked pixel data). 

3253 

3254 You can also use any pixel decoder supported by PIL. For more 

3255 information on available decoders, see the section 

3256 :ref:`Writing Your Own File Codec <file-codecs>`. 

3257 

3258 Note that this function decodes pixel data only, not entire images. 

3259 If you have an entire image in a string, wrap it in a 

3260 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3261 it. 

3262 

3263 :param mode: The image mode. See: :ref:`concept-modes`. 

3264 :param size: The image size. 

3265 :param data: A byte buffer containing raw data for the given mode. 

3266 :param decoder_name: What decoder to use. 

3267 :param args: Additional parameters for the given decoder. 

3268 :returns: An :py:class:`~PIL.Image.Image` object. 

3269 """ 

3270 

3271 _check_size(size) 

3272 

3273 im = new(mode, size) 

3274 if im.width != 0 and im.height != 0: 

3275 decoder_args: Any = args 

3276 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3277 # may pass tuple instead of argument list 

3278 decoder_args = decoder_args[0] 

3279 

3280 if decoder_name == "raw" and decoder_args == (): 

3281 decoder_args = mode 

3282 

3283 im.frombytes(data, decoder_name, decoder_args) 

3284 return im 

3285 

3286 

3287def frombuffer( 

3288 mode: str, 

3289 size: tuple[int, int], 

3290 data: bytes | SupportsArrayInterface, 

3291 decoder_name: str = "raw", 

3292 *args: Any, 

3293) -> Image: 

3294 """ 

3295 Creates an image memory referencing pixel data in a byte buffer. 

3296 

3297 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3298 in the byte buffer, where possible. This means that changes to the 

3299 original buffer object are reflected in this image). Not all modes can 

3300 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3301 

3302 Note that this function decodes pixel data only, not entire images. 

3303 If you have an entire image file in a string, wrap it in a 

3304 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3305 

3306 The default parameters used for the "raw" decoder differs from that used for 

3307 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3308 future release. The current release issues a warning if you do this; to disable 

3309 the warning, you should provide the full set of parameters. See below for details. 

3310 

3311 :param mode: The image mode. See: :ref:`concept-modes`. 

3312 :param size: The image size. 

3313 :param data: A bytes or other buffer object containing raw 

3314 data for the given mode. 

3315 :param decoder_name: What decoder to use. 

3316 :param args: Additional parameters for the given decoder. For the 

3317 default encoder ("raw"), it's recommended that you provide the 

3318 full set of parameters:: 

3319 

3320 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3321 

3322 :returns: An :py:class:`~PIL.Image.Image` object. 

3323 

3324 .. versionadded:: 1.1.4 

3325 """ 

3326 

3327 _check_size(size) 

3328 

3329 # may pass tuple instead of argument list 

3330 if len(args) == 1 and isinstance(args[0], tuple): 

3331 args = args[0] 

3332 

3333 if decoder_name == "raw": 

3334 if args == (): 

3335 args = mode, 0, 1 

3336 if args[0] in _MAPMODES: 

3337 im = new(mode, (0, 0)) 

3338 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3339 if mode == "P": 

3340 from . import ImagePalette 

3341 

3342 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3343 im.readonly = 1 

3344 return im 

3345 

3346 return frombytes(mode, size, data, decoder_name, args) 

3347 

3348 

3349class SupportsArrayInterface(Protocol): 

3350 """ 

3351 An object that has an ``__array_interface__`` dictionary. 

3352 """ 

3353 

3354 @property 

3355 def __array_interface__(self) -> dict[str, Any]: 

3356 raise NotImplementedError() 

3357 

3358 

3359class SupportsArrowArrayInterface(Protocol): 

3360 """ 

3361 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3362 data interface. 

3363 """ 

3364 

3365 def __arrow_c_array__( 

3366 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3367 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3368 raise NotImplementedError() 

3369 

3370 

3371def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3372 """ 

3373 Creates an image memory from an object exporting the array interface 

3374 (using the buffer protocol):: 

3375 

3376 from PIL import Image 

3377 import numpy as np 

3378 a = np.zeros((5, 5)) 

3379 im = Image.fromarray(a) 

3380 

3381 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3382 and :py:func:`~PIL.Image.frombuffer` is used. 

3383 

3384 In the case of NumPy, be aware that Pillow modes do not always correspond 

3385 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3386 32-bit signed integer pixels, and 32-bit floating point pixels. 

3387 

3388 Pillow images can also be converted to arrays:: 

3389 

3390 from PIL import Image 

3391 import numpy as np 

3392 im = Image.open("hopper.jpg") 

3393 a = np.asarray(im) 

3394 

3395 When converting Pillow images to arrays however, only pixel values are 

3396 transferred. This means that P and PA mode images will lose their palette. 

3397 

3398 :param obj: Object with array interface 

3399 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not 

3400 contain information about palettes or color spaces, this can be used to place 

3401 grayscale L mode data within a P mode image, or read RGB data as YCbCr for 

3402 example. 

3403 

3404 See: :ref:`concept-modes` for general information about modes. 

3405 :returns: An image object. 

3406 

3407 .. versionadded:: 1.1.6 

3408 """ 

3409 arr = obj.__array_interface__ 

3410 shape = arr["shape"] 

3411 ndim = len(shape) 

3412 strides = arr.get("strides", None) 

3413 try: 

3414 typekey = (1, 1) + shape[2:], arr["typestr"] 

3415 except KeyError as e: 

3416 if mode is not None: 

3417 typekey = None 

3418 color_modes: list[str] = [] 

3419 else: 

3420 msg = "Cannot handle this data type" 

3421 raise TypeError(msg) from e 

3422 if typekey is not None: 

3423 try: 

3424 typemode, rawmode, color_modes = _fromarray_typemap[typekey] 

3425 except KeyError as e: 

3426 typekey_shape, typestr = typekey 

3427 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3428 raise TypeError(msg) from e 

3429 if mode is not None: 

3430 if mode != typemode and mode not in color_modes: 

3431 deprecate("'mode' parameter for changing data types", 13) 

3432 rawmode = mode 

3433 else: 

3434 mode = typemode 

3435 if mode in ["1", "L", "I", "P", "F"]: 

3436 ndmax = 2 

3437 elif mode == "RGB": 

3438 ndmax = 3 

3439 else: 

3440 ndmax = 4 

3441 if ndim > ndmax: 

3442 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3443 raise ValueError(msg) 

3444 

3445 size = 1 if ndim == 1 else shape[1], shape[0] 

3446 if strides is not None: 

3447 if hasattr(obj, "tobytes"): 

3448 obj = obj.tobytes() 

3449 elif hasattr(obj, "tostring"): 

3450 obj = obj.tostring() 

3451 else: 

3452 msg = "'strides' requires either tobytes() or tostring()" 

3453 raise ValueError(msg) 

3454 

3455 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3456 

3457 

3458def fromarrow( 

3459 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3460) -> Image: 

3461 """Creates an image with zero-copy shared memory from an object exporting 

3462 the arrow_c_array interface protocol:: 

3463 

3464 from PIL import Image 

3465 import pyarrow as pa 

3466 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3467 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3468 

3469 If the data representation of the ``obj`` is not compatible with 

3470 Pillow internal storage, a ValueError is raised. 

3471 

3472 Pillow images can also be converted to Arrow objects:: 

3473 

3474 from PIL import Image 

3475 import pyarrow as pa 

3476 im = Image.open('hopper.jpg') 

3477 arr = pa.array(im) 

3478 

3479 As with array support, when converting Pillow images to arrays, 

3480 only pixel values are transferred. This means that P and PA mode 

3481 images will lose their palette. 

3482 

3483 :param obj: Object with an arrow_c_array interface 

3484 :param mode: Image mode. 

3485 :param size: Image size. This must match the storage of the arrow object. 

3486 :returns: An Image object 

3487 

3488 Note that according to the Arrow spec, both the producer and the 

3489 consumer should consider the exported array to be immutable, as 

3490 unsynchronized updates will potentially cause inconsistent data. 

3491 

3492 See: :ref:`arrow-support` for more detailed information 

3493 

3494 .. versionadded:: 11.2.1 

3495 

3496 """ 

3497 if not hasattr(obj, "__arrow_c_array__"): 

3498 msg = "arrow_c_array interface not found" 

3499 raise ValueError(msg) 

3500 

3501 schema_capsule, array_capsule = obj.__arrow_c_array__() 

3502 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3503 if _im: 

3504 return Image()._new(_im) 

3505 

3506 msg = "new_arrow returned None without an exception" 

3507 raise ValueError(msg) 

3508 

3509 

3510def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3511 """Creates an image instance from a QImage image""" 

3512 from . import ImageQt 

3513 

3514 if not ImageQt.qt_is_installed: 

3515 msg = "Qt bindings are not installed" 

3516 raise ImportError(msg) 

3517 return ImageQt.fromqimage(im) 

3518 

3519 

3520def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3521 """Creates an image instance from a QPixmap image""" 

3522 from . import ImageQt 

3523 

3524 if not ImageQt.qt_is_installed: 

3525 msg = "Qt bindings are not installed" 

3526 raise ImportError(msg) 

3527 return ImageQt.fromqpixmap(im) 

3528 

3529 

3530_fromarray_typemap = { 

3531 # (shape, typestr) => mode, rawmode, color modes 

3532 # first two members of shape are set to one 

3533 ((1, 1), "|b1"): ("1", "1;8", []), 

3534 ((1, 1), "|u1"): ("L", "L", ["P"]), 

3535 ((1, 1), "|i1"): ("I", "I;8", []), 

3536 ((1, 1), "<u2"): ("I", "I;16", []), 

3537 ((1, 1), ">u2"): ("I", "I;16B", []), 

3538 ((1, 1), "<i2"): ("I", "I;16S", []), 

3539 ((1, 1), ">i2"): ("I", "I;16BS", []), 

3540 ((1, 1), "<u4"): ("I", "I;32", []), 

3541 ((1, 1), ">u4"): ("I", "I;32B", []), 

3542 ((1, 1), "<i4"): ("I", "I;32S", []), 

3543 ((1, 1), ">i4"): ("I", "I;32BS", []), 

3544 ((1, 1), "<f4"): ("F", "F;32F", []), 

3545 ((1, 1), ">f4"): ("F", "F;32BF", []), 

3546 ((1, 1), "<f8"): ("F", "F;64F", []), 

3547 ((1, 1), ">f8"): ("F", "F;64BF", []), 

3548 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]), 

3549 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), 

3550 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), 

3551 # shortcuts: 

3552 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []), 

3553 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []), 

3554} 

3555 

3556 

3557def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3558 if MAX_IMAGE_PIXELS is None: 

3559 return 

3560 

3561 pixels = max(1, size[0]) * max(1, size[1]) 

3562 

3563 if pixels > 2 * MAX_IMAGE_PIXELS: 

3564 msg = ( 

3565 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3566 "pixels, could be decompression bomb DOS attack." 

3567 ) 

3568 raise DecompressionBombError(msg) 

3569 

3570 if pixels > MAX_IMAGE_PIXELS: 

3571 warnings.warn( 

3572 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3573 "could be decompression bomb DOS attack.", 

3574 DecompressionBombWarning, 

3575 ) 

3576 

3577 

3578def open( 

3579 fp: StrOrBytesPath | IO[bytes], 

3580 mode: Literal["r"] = "r", 

3581 formats: list[str] | tuple[str, ...] | None = None, 

3582) -> ImageFile.ImageFile: 

3583 """ 

3584 Opens and identifies the given image file. 

3585 

3586 This is a lazy operation; this function identifies the file, but 

3587 the file remains open and the actual image data is not read from 

3588 the file until you try to process the data (or call the 

3589 :py:meth:`~PIL.Image.Image.load` method). See 

3590 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3591 

3592 :param fp: A filename (string), os.PathLike object or a file object. 

3593 The file object must implement ``file.read``, 

3594 ``file.seek``, and ``file.tell`` methods, 

3595 and be opened in binary mode. The file object will also seek to zero 

3596 before reading. 

3597 :param mode: The mode. If given, this argument must be "r". 

3598 :param formats: A list or tuple of formats to attempt to load the file in. 

3599 This can be used to restrict the set of formats checked. 

3600 Pass ``None`` to try all supported formats. You can print the set of 

3601 available formats by running ``python3 -m PIL`` or using 

3602 the :py:func:`PIL.features.pilinfo` function. 

3603 :returns: An :py:class:`~PIL.Image.Image` object. 

3604 :exception FileNotFoundError: If the file cannot be found. 

3605 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3606 identified. 

3607 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3608 instance is used for ``fp``. 

3609 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3610 """ 

3611 

3612 if mode != "r": 

3613 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3614 raise ValueError(msg) 

3615 elif isinstance(fp, io.StringIO): 

3616 msg = ( # type: ignore[unreachable] 

3617 "StringIO cannot be used to open an image. " 

3618 "Binary data must be used instead." 

3619 ) 

3620 raise ValueError(msg) 

3621 

3622 if formats is None: 

3623 formats = ID 

3624 elif not isinstance(formats, (list, tuple)): 

3625 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3626 raise TypeError(msg) 

3627 

3628 exclusive_fp = False 

3629 filename: str | bytes = "" 

3630 if is_path(fp): 

3631 filename = os.fspath(fp) 

3632 fp = builtins.open(filename, "rb") 

3633 exclusive_fp = True 

3634 else: 

3635 fp = cast(IO[bytes], fp) 

3636 

3637 try: 

3638 fp.seek(0) 

3639 except (AttributeError, io.UnsupportedOperation): 

3640 fp = io.BytesIO(fp.read()) 

3641 exclusive_fp = True 

3642 

3643 prefix = fp.read(16) 

3644 

3645 # Try to import just the plugin needed for this file extension 

3646 # before falling back to preinit() which imports common plugins 

3647 ext = os.path.splitext(filename)[1] if filename else "" 

3648 if not _import_plugin_for_extension(ext): 

3649 preinit() 

3650 

3651 warning_messages: list[str] = [] 

3652 

3653 def _open_core( 

3654 fp: IO[bytes], 

3655 filename: str | bytes, 

3656 prefix: bytes, 

3657 formats: list[str] | tuple[str, ...], 

3658 ) -> ImageFile.ImageFile | None: 

3659 for i in formats: 

3660 i = i.upper() 

3661 if i not in OPEN: 

3662 init() 

3663 try: 

3664 factory, accept = OPEN[i] 

3665 result = not accept or accept(prefix) 

3666 if isinstance(result, str): 

3667 warning_messages.append(result) 

3668 elif result: 

3669 fp.seek(0) 

3670 im = factory(fp, filename) 

3671 _decompression_bomb_check(im.size) 

3672 return im 

3673 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3674 if WARN_POSSIBLE_FORMATS: 

3675 warning_messages.append(i + " opening failed. " + str(e)) 

3676 except BaseException: 

3677 if exclusive_fp: 

3678 fp.close() 

3679 raise 

3680 return None 

3681 

3682 im = _open_core(fp, filename, prefix, formats) 

3683 

3684 if im is None and formats is ID: 

3685 # Try preinit (few common plugins) then init (all plugins) 

3686 for loader in (preinit, init): 

3687 checked_formats = ID.copy() 

3688 loader() 

3689 if formats != checked_formats: 

3690 im = _open_core( 

3691 fp, 

3692 filename, 

3693 prefix, 

3694 tuple(f for f in formats if f not in checked_formats), 

3695 ) 

3696 if im is not None: 

3697 break 

3698 

3699 if im: 

3700 im._exclusive_fp = exclusive_fp 

3701 return im 

3702 

3703 if exclusive_fp: 

3704 fp.close() 

3705 for message in warning_messages: 

3706 warnings.warn(message) 

3707 msg = "cannot identify image file %r" % (filename if filename else fp) 

3708 raise UnidentifiedImageError(msg) 

3709 

3710 

3711# 

3712# Image processing. 

3713 

3714 

3715def alpha_composite(im1: Image, im2: Image) -> Image: 

3716 """ 

3717 Alpha composite im2 over im1. 

3718 

3719 :param im1: The first image. Must have mode RGBA or LA. 

3720 :param im2: The second image. Must have the same mode and size as the first image. 

3721 :returns: An :py:class:`~PIL.Image.Image` object. 

3722 """ 

3723 

3724 im1.load() 

3725 im2.load() 

3726 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3727 

3728 

3729def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3730 """ 

3731 Creates a new image by interpolating between two input images, using 

3732 a constant alpha:: 

3733 

3734 out = image1 * (1.0 - alpha) + image2 * alpha 

3735 

3736 :param im1: The first image. 

3737 :param im2: The second image. Must have the same mode and size as 

3738 the first image. 

3739 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3740 copy of the first image is returned. If alpha is 1.0, a copy of 

3741 the second image is returned. There are no restrictions on the 

3742 alpha value. If necessary, the result is clipped to fit into 

3743 the allowed output range. 

3744 :returns: An :py:class:`~PIL.Image.Image` object. 

3745 """ 

3746 

3747 im1.load() 

3748 im2.load() 

3749 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3750 

3751 

3752def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3753 """ 

3754 Create composite image by blending images using a transparency mask. 

3755 

3756 :param image1: The first image. 

3757 :param image2: The second image. Must have the same mode and 

3758 size as the first image. 

3759 :param mask: A mask image. This image can have mode 

3760 "1", "L", or "RGBA", and must have the same size as the 

3761 other two images. 

3762 """ 

3763 

3764 image = image2.copy() 

3765 image.paste(image1, None, mask) 

3766 return image 

3767 

3768 

3769def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3770 """ 

3771 Applies the function (which should take one argument) to each pixel 

3772 in the given image. If the image has more than one band, the same 

3773 function is applied to each band. Note that the function is 

3774 evaluated once for each possible pixel value, so you cannot use 

3775 random components or other generators. 

3776 

3777 :param image: The input image. 

3778 :param function: A function object, taking one integer argument. 

3779 :returns: An :py:class:`~PIL.Image.Image` object. 

3780 """ 

3781 

3782 return image.point(args[0]) 

3783 

3784 

3785def merge(mode: str, bands: Sequence[Image]) -> Image: 

3786 """ 

3787 Merge a set of single band images into a new multiband image. 

3788 

3789 :param mode: The mode to use for the output image. See: 

3790 :ref:`concept-modes`. 

3791 :param bands: A sequence containing one single-band image for 

3792 each band in the output image. All bands must have the 

3793 same size. 

3794 :returns: An :py:class:`~PIL.Image.Image` object. 

3795 """ 

3796 

3797 if getmodebands(mode) != len(bands) or "*" in mode: 

3798 msg = "wrong number of bands" 

3799 raise ValueError(msg) 

3800 for band in bands[1:]: 

3801 if band.mode != getmodetype(mode): 

3802 msg = "mode mismatch" 

3803 raise ValueError(msg) 

3804 if band.size != bands[0].size: 

3805 msg = "size mismatch" 

3806 raise ValueError(msg) 

3807 for band in bands: 

3808 band.load() 

3809 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3810 

3811 

3812# -------------------------------------------------------------------- 

3813# Plugin registry 

3814 

3815 

3816def register_open( 

3817 id: str, 

3818 factory: ( 

3819 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3820 | type[ImageFile.ImageFile] 

3821 ), 

3822 accept: Callable[[bytes], bool | str] | None = None, 

3823) -> None: 

3824 """ 

3825 Register an image file plugin. This function should not be used 

3826 in application code. 

3827 

3828 :param id: An image format identifier. 

3829 :param factory: An image file factory method. 

3830 :param accept: An optional function that can be used to quickly 

3831 reject images having another format. 

3832 """ 

3833 id = id.upper() 

3834 if id not in ID: 

3835 ID.append(id) 

3836 OPEN[id] = factory, accept 

3837 

3838 

3839def register_mime(id: str, mimetype: str) -> None: 

3840 """ 

3841 Registers an image MIME type by populating ``Image.MIME``. This function 

3842 should not be used in application code. 

3843 

3844 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3845 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3846 provide a different result for specific images. 

3847 

3848 :param id: An image format identifier. 

3849 :param mimetype: The image MIME type for this format. 

3850 """ 

3851 MIME[id.upper()] = mimetype 

3852 

3853 

3854def register_save( 

3855 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3856) -> None: 

3857 """ 

3858 Registers an image save function. This function should not be 

3859 used in application code. 

3860 

3861 :param id: An image format identifier. 

3862 :param driver: A function to save images in this format. 

3863 """ 

3864 SAVE[id.upper()] = driver 

3865 

3866 

3867def register_save_all( 

3868 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3869) -> None: 

3870 """ 

3871 Registers an image function to save all the frames 

3872 of a multiframe format. This function should not be 

3873 used in application code. 

3874 

3875 :param id: An image format identifier. 

3876 :param driver: A function to save images in this format. 

3877 """ 

3878 SAVE_ALL[id.upper()] = driver 

3879 

3880 

3881def register_extension(id: str, extension: str) -> None: 

3882 """ 

3883 Registers an image extension. This function should not be 

3884 used in application code. 

3885 

3886 :param id: An image format identifier. 

3887 :param extension: An extension used for this format. 

3888 """ 

3889 EXTENSION[extension.lower()] = id.upper() 

3890 

3891 

3892def register_extensions(id: str, extensions: list[str]) -> None: 

3893 """ 

3894 Registers image extensions. This function should not be 

3895 used in application code. 

3896 

3897 :param id: An image format identifier. 

3898 :param extensions: A list of extensions used for this format. 

3899 """ 

3900 for extension in extensions: 

3901 register_extension(id, extension) 

3902 

3903 

3904def registered_extensions() -> dict[str, str]: 

3905 """ 

3906 Returns a dictionary containing all file extensions belonging 

3907 to registered plugins 

3908 """ 

3909 init() 

3910 return EXTENSION 

3911 

3912 

3913def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3914 """ 

3915 Registers an image decoder. This function should not be 

3916 used in application code. 

3917 

3918 :param name: The name of the decoder 

3919 :param decoder: An ImageFile.PyDecoder object 

3920 

3921 .. versionadded:: 4.1.0 

3922 """ 

3923 DECODERS[name] = decoder 

3924 

3925 

3926def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3927 """ 

3928 Registers an image encoder. This function should not be 

3929 used in application code. 

3930 

3931 :param name: The name of the encoder 

3932 :param encoder: An ImageFile.PyEncoder object 

3933 

3934 .. versionadded:: 4.1.0 

3935 """ 

3936 ENCODERS[name] = encoder 

3937 

3938 

3939# -------------------------------------------------------------------- 

3940# Simple display support. 

3941 

3942 

3943def _show(image: Image, **options: Any) -> None: 

3944 from . import ImageShow 

3945 

3946 deprecate("Image._show", 13, "ImageShow.show") 

3947 ImageShow.show(image, **options) 

3948 

3949 

3950# -------------------------------------------------------------------- 

3951# Effects 

3952 

3953 

3954def effect_mandelbrot( 

3955 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3956) -> Image: 

3957 """ 

3958 Generate a Mandelbrot set covering the given extent. 

3959 

3960 :param size: The requested size in pixels, as a 2-tuple: 

3961 (width, height). 

3962 :param extent: The extent to cover, as a 4-tuple: 

3963 (x0, y0, x1, y1). 

3964 :param quality: Quality. 

3965 """ 

3966 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3967 

3968 

3969def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3970 """ 

3971 Generate Gaussian noise centered around 128. 

3972 

3973 :param size: The requested size in pixels, as a 2-tuple: 

3974 (width, height). 

3975 :param sigma: Standard deviation of noise. 

3976 """ 

3977 return Image()._new(core.effect_noise(size, sigma)) 

3978 

3979 

3980def linear_gradient(mode: str) -> Image: 

3981 """ 

3982 Generate 256x256 linear gradient from black to white, top to bottom. 

3983 

3984 :param mode: Input mode. 

3985 """ 

3986 return Image()._new(core.linear_gradient(mode)) 

3987 

3988 

3989def radial_gradient(mode: str) -> Image: 

3990 """ 

3991 Generate 256x256 radial gradient from black to white, centre to edge. 

3992 

3993 :param mode: Input mode. 

3994 """ 

3995 return Image()._new(core.radial_gradient(mode)) 

3996 

3997 

3998# -------------------------------------------------------------------- 

3999# Resources 

4000 

4001 

4002def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

4003 env_dict = env if env is not None else os.environ 

4004 

4005 for var_name, setter in [ 

4006 ("PILLOW_ALIGNMENT", core.set_alignment), 

4007 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

4008 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

4009 ]: 

4010 if var_name not in env_dict: 

4011 continue 

4012 

4013 var = env_dict[var_name].lower() 

4014 

4015 units = 1 

4016 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

4017 if var.endswith(postfix): 

4018 units = mul 

4019 var = var[: -len(postfix)] 

4020 

4021 try: 

4022 var_int = int(var) * units 

4023 except ValueError: 

4024 warnings.warn(f"{var_name} is not int") 

4025 continue 

4026 

4027 try: 

4028 setter(var_int) 

4029 except ValueError as e: 

4030 warnings.warn(f"{var_name}: {e}") 

4031 

4032 

4033_apply_env_variables() 

4034atexit.register(core.clear_cache) 

4035 

4036 

4037if TYPE_CHECKING: 

4038 _ExifBase = MutableMapping[int, Any] 

4039else: 

4040 _ExifBase = MutableMapping 

4041 

4042 

4043class Exif(_ExifBase): 

4044 """ 

4045 This class provides read and write access to EXIF image data:: 

4046 

4047 from PIL import Image 

4048 im = Image.open("exif.png") 

4049 exif = im.getexif() # Returns an instance of this class 

4050 

4051 Information can be read and written, iterated over or deleted:: 

4052 

4053 print(exif[274]) # 1 

4054 exif[274] = 2 

4055 for k, v in exif.items(): 

4056 print("Tag", k, "Value", v) # Tag 274 Value 2 

4057 del exif[274] 

4058 

4059 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

4060 returns a dictionary:: 

4061 

4062 from PIL import ExifTags 

4063 im = Image.open("exif_gps.jpg") 

4064 exif = im.getexif() 

4065 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

4066 print(gps_ifd) 

4067 

4068 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

4069 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

4070 

4071 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

4072 

4073 print(exif[ExifTags.Base.Software]) # PIL 

4074 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

4075 """ 

4076 

4077 endian: str | None = None 

4078 bigtiff = False 

4079 _loaded = False 

4080 

4081 def __init__(self) -> None: 

4082 self._data: dict[int, Any] = {} 

4083 self._hidden_data: dict[int, Any] = {} 

4084 self._ifds: dict[int, dict[int, Any]] = {} 

4085 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

4086 self._loaded_exif: bytes | None = None 

4087 

4088 def _fixup(self, value: Any) -> Any: 

4089 try: 

4090 if len(value) == 1 and isinstance(value, tuple): 

4091 return value[0] 

4092 except Exception: 

4093 pass 

4094 return value 

4095 

4096 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

4097 # Helper function 

4098 # returns a dict with any single item tuples/lists as individual values 

4099 return {k: self._fixup(v) for k, v in src_dict.items()} 

4100 

4101 def _get_ifd_dict( 

4102 self, offset: int, group: int | None = None 

4103 ) -> dict[int, Any] | None: 

4104 try: 

4105 # an offset pointer to the location of the nested embedded IFD. 

4106 # It should be a long, but may be corrupted. 

4107 self.fp.seek(offset) 

4108 except (KeyError, TypeError): 

4109 return None 

4110 else: 

4111 from . import TiffImagePlugin 

4112 

4113 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

4114 info.load(self.fp) 

4115 return self._fixup_dict(dict(info)) 

4116 

4117 def _get_head(self) -> bytes: 

4118 version = b"\x2b" if self.bigtiff else b"\x2a" 

4119 if self.endian == "<": 

4120 head = b"II" + version + b"\x00" + o32le(8) 

4121 else: 

4122 head = b"MM\x00" + version + o32be(8) 

4123 if self.bigtiff: 

4124 head += o32le(8) if self.endian == "<" else o32be(8) 

4125 head += b"\x00\x00\x00\x00" 

4126 return head 

4127 

4128 def load(self, data: bytes) -> None: 

4129 # Extract EXIF information. This is highly experimental, 

4130 # and is likely to be replaced with something better in a future 

4131 # version. 

4132 

4133 # The EXIF record consists of a TIFF file embedded in a JPEG 

4134 # application marker (!). 

4135 if data == self._loaded_exif: 

4136 return 

4137 self._loaded_exif = data 

4138 self._data.clear() 

4139 self._hidden_data.clear() 

4140 self._ifds.clear() 

4141 while data and data.startswith(b"Exif\x00\x00"): 

4142 data = data[6:] 

4143 if not data: 

4144 self._info = None 

4145 return 

4146 

4147 self.fp: IO[bytes] = io.BytesIO(data) 

4148 self.head = self.fp.read(8) 

4149 # process dictionary 

4150 from . import TiffImagePlugin 

4151 

4152 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4153 self.endian = self._info._endian 

4154 self.fp.seek(self._info.next) 

4155 self._info.load(self.fp) 

4156 

4157 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4158 self._loaded_exif = None 

4159 self._data.clear() 

4160 self._hidden_data.clear() 

4161 self._ifds.clear() 

4162 

4163 # process dictionary 

4164 from . import TiffImagePlugin 

4165 

4166 self.fp = fp 

4167 if offset is not None: 

4168 self.head = self._get_head() 

4169 else: 

4170 self.head = self.fp.read(8) 

4171 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4172 if self.endian is None: 

4173 self.endian = self._info._endian 

4174 if offset is None: 

4175 offset = self._info.next 

4176 self.fp.tell() 

4177 self.fp.seek(offset) 

4178 self._info.load(self.fp) 

4179 

4180 def _get_merged_dict(self) -> dict[int, Any]: 

4181 merged_dict = dict(self) 

4182 

4183 # get EXIF extension 

4184 if ExifTags.IFD.Exif in self: 

4185 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4186 if ifd: 

4187 merged_dict.update(ifd) 

4188 

4189 # GPS 

4190 if ExifTags.IFD.GPSInfo in self: 

4191 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4192 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4193 ) 

4194 

4195 return merged_dict 

4196 

4197 def tobytes(self, offset: int = 8) -> bytes: 

4198 from . import TiffImagePlugin 

4199 

4200 head = self._get_head() 

4201 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4202 for tag, ifd_dict in self._ifds.items(): 

4203 if tag not in self: 

4204 ifd[tag] = ifd_dict 

4205 for tag, value in self.items(): 

4206 if tag in [ 

4207 ExifTags.IFD.Exif, 

4208 ExifTags.IFD.GPSInfo, 

4209 ] and not isinstance(value, dict): 

4210 value = self.get_ifd(tag) 

4211 if ( 

4212 tag == ExifTags.IFD.Exif 

4213 and ExifTags.IFD.Interop in value 

4214 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4215 ): 

4216 value = value.copy() 

4217 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4218 ifd[tag] = value 

4219 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4220 

4221 def get_ifd(self, tag: int) -> dict[int, Any]: 

4222 if tag not in self._ifds: 

4223 if tag == ExifTags.IFD.IFD1: 

4224 if self._info is not None and self._info.next != 0: 

4225 ifd = self._get_ifd_dict(self._info.next) 

4226 if ifd is not None: 

4227 self._ifds[tag] = ifd 

4228 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4229 offset = self._hidden_data.get(tag, self.get(tag)) 

4230 if offset is not None: 

4231 ifd = self._get_ifd_dict(offset, tag) 

4232 if ifd is not None: 

4233 self._ifds[tag] = ifd 

4234 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4235 if ExifTags.IFD.Exif not in self._ifds: 

4236 self.get_ifd(ExifTags.IFD.Exif) 

4237 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4238 if tag == ExifTags.IFD.MakerNote: 

4239 from .TiffImagePlugin import ImageFileDirectory_v2 

4240 

4241 try: 

4242 if tag_data.startswith(b"FUJIFILM"): 

4243 ifd_offset = i32le(tag_data, 8) 

4244 ifd_data = tag_data[ifd_offset:] 

4245 

4246 makernote = {} 

4247 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4248 ifd_tag, typ, count, data = struct.unpack( 

4249 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4250 ) 

4251 try: 

4252 ( 

4253 unit_size, 

4254 handler, 

4255 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4256 except KeyError: 

4257 continue 

4258 size = count * unit_size 

4259 if size > 4: 

4260 (offset,) = struct.unpack("<L", data) 

4261 data = ifd_data[offset - 12 : offset + size - 12] 

4262 else: 

4263 data = data[:size] 

4264 

4265 if len(data) != size: 

4266 warnings.warn( 

4267 "Possibly corrupt EXIF MakerNote data. " 

4268 f"Expecting to read {size} bytes but only got " 

4269 f"{len(data)}. Skipping tag {ifd_tag}" 

4270 ) 

4271 continue 

4272 

4273 if not data: 

4274 continue 

4275 

4276 makernote[ifd_tag] = handler( 

4277 ImageFileDirectory_v2(), data, False 

4278 ) 

4279 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4280 elif self.get(0x010F) == "Nintendo": 

4281 makernote = {} 

4282 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4283 ifd_tag, typ, count, data = struct.unpack( 

4284 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4285 ) 

4286 if ifd_tag == 0x1101: 

4287 # CameraInfo 

4288 (offset,) = struct.unpack(">L", data) 

4289 self.fp.seek(offset) 

4290 

4291 camerainfo: dict[str, int | bytes] = { 

4292 "ModelID": self.fp.read(4) 

4293 } 

4294 

4295 self.fp.read(4) 

4296 # Seconds since 2000 

4297 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4298 

4299 self.fp.read(4) 

4300 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4301 

4302 self.fp.read(12) 

4303 parallax = self.fp.read(4) 

4304 handler = ImageFileDirectory_v2._load_dispatch[ 

4305 TiffTags.FLOAT 

4306 ][1] 

4307 camerainfo["Parallax"] = handler( 

4308 ImageFileDirectory_v2(), parallax, False 

4309 )[0] 

4310 

4311 self.fp.read(4) 

4312 camerainfo["Category"] = self.fp.read(2) 

4313 

4314 makernote = {0x1101: camerainfo} 

4315 self._ifds[tag] = makernote 

4316 except struct.error: 

4317 pass 

4318 else: 

4319 # Interop 

4320 ifd = self._get_ifd_dict(tag_data, tag) 

4321 if ifd is not None: 

4322 self._ifds[tag] = ifd 

4323 ifd = self._ifds.setdefault(tag, {}) 

4324 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4325 ifd = { 

4326 k: v 

4327 for (k, v) in ifd.items() 

4328 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4329 } 

4330 return ifd 

4331 

4332 def hide_offsets(self) -> None: 

4333 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4334 if tag in self: 

4335 self._hidden_data[tag] = self[tag] 

4336 del self[tag] 

4337 

4338 def __str__(self) -> str: 

4339 if self._info is not None: 

4340 # Load all keys into self._data 

4341 for tag in self._info: 

4342 self[tag] 

4343 

4344 return str(self._data) 

4345 

4346 def __len__(self) -> int: 

4347 keys = set(self._data) 

4348 if self._info is not None: 

4349 keys.update(self._info) 

4350 return len(keys) 

4351 

4352 def __getitem__(self, tag: int) -> Any: 

4353 if self._info is not None and tag not in self._data and tag in self._info: 

4354 self._data[tag] = self._fixup(self._info[tag]) 

4355 del self._info[tag] 

4356 return self._data[tag] 

4357 

4358 def __contains__(self, tag: object) -> bool: 

4359 return tag in self._data or (self._info is not None and tag in self._info) 

4360 

4361 def __setitem__(self, tag: int, value: Any) -> None: 

4362 if self._info is not None and tag in self._info: 

4363 del self._info[tag] 

4364 self._data[tag] = value 

4365 

4366 def __delitem__(self, tag: int) -> None: 

4367 if self._info is not None and tag in self._info: 

4368 del self._info[tag] 

4369 else: 

4370 del self._data[tag] 

4371 if tag in self._ifds: 

4372 del self._ifds[tag] 

4373 

4374 def __iter__(self) -> Iterator[int]: 

4375 keys = set(self._data) 

4376 if self._info is not None: 

4377 keys.update(self._info) 

4378 return iter(keys)