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

1759 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, Self 

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: 

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) -> Self: 

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 = f".{format}" if format else "" 

735 

736 if file: 

737 filename = file 

738 if not filename.endswith(suffix): 

739 filename += suffix 

740 else: 

741 f, filename = tempfile.mkstemp(suffix) 

742 os.close(f) 

743 

744 self.save(filename, format or "PPM", **options) 

745 

746 return filename 

747 

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

749 if self.__class__ is not other.__class__: 

750 return False 

751 assert isinstance(other, Image) 

752 return ( 

753 self.mode == other.mode 

754 and self.size == other.size 

755 and self.info == other.info 

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

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

758 ) 

759 

760 def __repr__(self) -> str: 

761 return ( 

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

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

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

765 ) 

766 

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

768 """IPython plain text display support""" 

769 

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

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

772 p.text( 

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

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

775 ) 

776 

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

778 """Helper function for iPython display hook. 

779 

780 :param image_format: Image format. 

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

782 """ 

783 b = io.BytesIO() 

784 try: 

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

786 except Exception: 

787 return None 

788 return b.getvalue() 

789 

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

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

792 

793 :returns: PNG version of the image as bytes 

794 """ 

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

796 

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

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

799 

800 :returns: JPEG version of the image as bytes 

801 """ 

802 return self._repr_image("JPEG") 

803 

804 @property 

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

806 # numpy array interface support 

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

808 if self.mode == "1": 

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

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

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

812 else: 

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

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

815 return new 

816 

817 def __arrow_c_schema__(self) -> object: 

818 self.load() 

819 return self.im.__arrow_c_schema__() 

820 

821 def __arrow_c_array__( 

822 self, requested_schema: object | None = None 

823 ) -> tuple[object, object]: 

824 self.load() 

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

826 

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

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

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

830 

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

832 Image.__init__(self) 

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

834 self.info = info 

835 self._mode = mode 

836 self._size = size 

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

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

839 self.putpalette(palette) 

840 self.frombytes(data) 

841 

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

843 """ 

844 Return image as a bytes object. 

845 

846 .. warning:: 

847 

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

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

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

851 

852 :param encoder_name: What encoder to use. 

853 

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

855 To see how this packs pixel data into the returned 

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

857 

858 A list of C encoders can be seen under codecs 

859 section of the function array in 

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

861 within the relevant plugins. 

862 :param args: Extra arguments to the encoder. 

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

864 """ 

865 

866 encoder_args: Any = args 

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

868 # may pass tuple instead of argument list 

869 encoder_args = encoder_args[0] 

870 

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

872 encoder_args = self.mode 

873 

874 self.load() 

875 

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

877 return b"" 

878 

879 # unpack data 

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

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

882 

883 from . import ImageFile 

884 

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

886 

887 output = [] 

888 while True: 

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

890 output.append(data) 

891 if errcode: 

892 break 

893 if errcode < 0: 

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

895 raise RuntimeError(msg) 

896 

897 return b"".join(output) 

898 

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

900 """ 

901 Returns the image converted to an X11 bitmap. 

902 

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

904 

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

906 :returns: A string containing an X11 bitmap. 

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

908 """ 

909 

910 self.load() 

911 if self.mode != "1": 

912 msg = "not a bitmap" 

913 raise ValueError(msg) 

914 data = self.tobytes("xbm") 

915 return b"".join( 

916 [ 

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

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

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

920 data, 

921 b"};", 

922 ] 

923 ) 

924 

925 def frombytes( 

926 self, 

927 data: DecoderInput, 

928 decoder_name: str = "raw", 

929 *args: Any, 

930 ) -> None: 

931 """ 

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

933 

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

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

936 """ 

937 

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

939 return 

940 

941 decoder_args: Any = args 

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

943 # may pass tuple instead of argument list 

944 decoder_args = decoder_args[0] 

945 

946 if decoder_args and decoder_args[0] in {"P;2L", "P;4L"}: 

947 multiple = 4 if decoder_args[0] == "P;2L" else 8 

948 if len(data) % multiple: 

949 msg = "not enough image data" 

950 raise ValueError(msg) 

951 

952 # default format 

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

954 decoder_args = self.mode 

955 

956 # unpack data 

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

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

959 s = d.decode(data) 

960 

961 if s[0] >= 0: 

962 msg = "not enough image data" 

963 raise ValueError(msg) 

964 if s[1] != 0: 

965 msg = "cannot decode image data" 

966 raise ValueError(msg) 

967 

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

969 """ 

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

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

972 Image class automatically loads an opened image when it is 

973 accessed for the first time. 

974 

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

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

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

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

979 

980 :returns: An image access object. 

981 """ 

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

983 # realize palette 

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

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

986 self.palette.dirty = 0 

987 self.palette.rawmode = None 

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

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

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

991 else: 

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

993 self.palette.mode = "RGBA" 

994 elif self.palette.mode != mode: 

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

996 # then update the Python palette data 

997 self.palette.palette = self.im.getpalette(self.palette.mode) 

998 

999 if self._im is not None: 

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

1001 return None 

1002 

1003 def verify(self) -> None: 

1004 """ 

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

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

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

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

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

1010 file. 

1011 """ 

1012 pass 

1013 

1014 def convert( 

1015 self, 

1016 mode: str | None = None, 

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

1018 dither: Dither | None = None, 

1019 palette: Palette = Palette.WEB, 

1020 colors: int = 256, 

1021 ) -> Image: 

1022 """ 

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

1024 method translates pixels through the palette. If mode is 

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

1026 and the palette can be represented without a palette. 

1027 

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

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

1030 

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

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

1033 

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

1035 

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

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

1038 dither to approximate the original image luminosity levels. If 

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

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

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

1042 

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

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

1045 and ``dither`` and ``palette`` are ignored. 

1046 

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

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

1049 

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

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

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

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

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

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

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

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

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

1059 :data:`Palette.ADAPTIVE`. 

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

1061 palette. Defaults to 256. 

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

1063 """ 

1064 

1065 self.load() 

1066 

1067 has_transparency = "transparency" in self.info 

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

1069 # determine default mode 

1070 if self.palette: 

1071 mode = self.palette.mode 

1072 else: 

1073 mode = "RGB" 

1074 if mode == "RGB" and has_transparency: 

1075 mode = "RGBA" 

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

1077 return self.copy() 

1078 

1079 if matrix: 

1080 # matrix conversion 

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

1082 msg = "illegal conversion" 

1083 raise ValueError(msg) 

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

1085 new_im = self._new(im) 

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

1087 transparency = new_im.info["transparency"] 

1088 

1089 def convert_transparency( 

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

1091 ) -> int: 

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

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

1094 

1095 if mode == "L": 

1096 transparency = convert_transparency(matrix, transparency) 

1097 elif len(mode) == 3: 

1098 transparency = tuple( 

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

1100 for i in range(len(transparency)) 

1101 ) 

1102 new_im.info["transparency"] = transparency 

1103 return new_im 

1104 

1105 if self.mode == "RGBA": 

1106 if mode == "P": 

1107 return self.quantize(colors) 

1108 elif mode == "PA": 

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

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

1111 p = rgb.quantize(colors) 

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

1113 

1114 trns = None 

1115 delete_trns = False 

1116 # transparency handling 

1117 if has_transparency: 

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

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

1120 ): 

1121 # Use transparent conversion to promote from transparent 

1122 # color to an alpha channel. 

1123 new_im = self._new( 

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

1125 ) 

1126 del new_im.info["transparency"] 

1127 return new_im 

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

1129 t = self.info["transparency"] 

1130 if isinstance(t, bytes): 

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

1132 warnings.warn( 

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

1134 "converted to RGBA images" 

1135 ) 

1136 delete_trns = True 

1137 else: 

1138 # get the new transparency color. 

1139 # use existing conversions 

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

1141 if self.mode == "P": 

1142 assert self.palette is not None 

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

1144 if isinstance(t, tuple): 

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

1146 assert trns_im.palette is not None 

1147 try: 

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

1149 except ValueError as e: 

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

1151 # If all 256 colors are in use, 

1152 # then there is no need for transparency 

1153 t = None 

1154 else: 

1155 raise ValueError(err) from e 

1156 if t is None: 

1157 trns = None 

1158 else: 

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

1160 

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

1162 trns_im = trns_im.convert(mode) 

1163 else: 

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

1165 # after quantization. 

1166 trns_im = trns_im.convert("RGB") 

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

1168 

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

1170 t = self.info["transparency"] 

1171 delete_trns = True 

1172 

1173 if isinstance(t, bytes): 

1174 self.im.putpalettealphas(t) 

1175 elif isinstance(t, int): 

1176 self.im.putpalettealpha(t, 0) 

1177 else: 

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

1179 raise ValueError(msg) 

1180 

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

1182 im = self.im.quantize(colors) 

1183 new_im = self._new(im) 

1184 from . import ImagePalette 

1185 

1186 new_im.palette = ImagePalette.ImagePalette( 

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

1188 ) 

1189 if delete_trns: 

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

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

1192 del new_im.info["transparency"] 

1193 if trns is not None: 

1194 try: 

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

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

1197 new_im, 

1198 ) 

1199 except Exception: 

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

1201 # transparency hanging around to mess us up. 

1202 del new_im.info["transparency"] 

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

1204 return new_im 

1205 

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

1207 im = self 

1208 if mode == "LAB": 

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

1210 im = im.convert("RGBA") 

1211 other_mode = im.mode 

1212 else: 

1213 other_mode = mode 

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

1215 from . import ImageCms 

1216 

1217 srgb = ImageCms.createProfile("sRGB") 

1218 lab = ImageCms.createProfile("LAB") 

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

1220 transform = ImageCms.buildTransform( 

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

1222 ) 

1223 return transform.apply(im) 

1224 

1225 # colorspace conversion 

1226 if dither is None: 

1227 dither = Dither.FLOYDSTEINBERG 

1228 

1229 try: 

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

1231 except ValueError: 

1232 try: 

1233 # normalize source image and try again 

1234 modebase = getmodebase(self.mode) 

1235 if modebase == self.mode: 

1236 raise 

1237 im = self.im.convert(modebase) 

1238 im = im.convert(mode, dither) 

1239 except KeyError as e: 

1240 msg = "illegal conversion" 

1241 raise ValueError(msg) from e 

1242 

1243 new_im = self._new(im) 

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

1245 from . import ImagePalette 

1246 

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

1248 if delete_trns: 

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

1250 del new_im.info["transparency"] 

1251 if trns is not None: 

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

1253 try: 

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

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

1256 ) 

1257 except ValueError as e: 

1258 del new_im.info["transparency"] 

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

1260 # If all 256 colors are in use, 

1261 # then there is no need for transparency 

1262 warnings.warn( 

1263 "Couldn't allocate palette entry for transparency" 

1264 ) 

1265 else: 

1266 new_im.info["transparency"] = trns 

1267 return new_im 

1268 

1269 def quantize( 

1270 self, 

1271 colors: int = 256, 

1272 method: int | None = None, 

1273 kmeans: int = 0, 

1274 palette: Image | None = None, 

1275 dither: Dither = Dither.FLOYDSTEINBERG, 

1276 ) -> Image: 

1277 """ 

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

1279 of colors. 

1280 

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

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

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

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

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

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

1287 ``feature="libimagequant"``). 

1288 

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

1290 

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

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

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

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

1295 :param palette: Quantize to the palette of given 

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

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

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

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

1300 (default). 

1301 :returns: A new image 

1302 """ 

1303 

1304 self.load() 

1305 

1306 if method is None: 

1307 # defaults: 

1308 method = Quantize.MEDIANCUT 

1309 if self.mode == "RGBA": 

1310 method = Quantize.FASTOCTREE 

1311 

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

1313 Quantize.FASTOCTREE, 

1314 Quantize.LIBIMAGEQUANT, 

1315 ): 

1316 # Caller specified an invalid mode. 

1317 msg = ( 

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

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

1320 ) 

1321 raise ValueError(msg) 

1322 

1323 if palette: 

1324 # use palette from reference image 

1325 palette.load() 

1326 if palette.mode != "P": 

1327 msg = "bad mode for palette image" 

1328 raise ValueError(msg) 

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

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

1331 raise ValueError(msg) 

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

1333 new_im = self._new(im) 

1334 assert palette.palette is not None 

1335 new_im.palette = palette.palette.copy() 

1336 return new_im 

1337 

1338 if kmeans < 0: 

1339 msg = "kmeans must not be negative" 

1340 raise ValueError(msg) 

1341 

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

1343 

1344 from . import ImagePalette 

1345 

1346 mode = im.im.getpalettemode() 

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

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

1349 

1350 return im 

1351 

1352 def copy(self) -> Image: 

1353 """ 

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

1355 into an image, but still retain the original. 

1356 

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

1358 """ 

1359 self.load() 

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

1361 

1362 __copy__ = copy 

1363 

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

1365 """ 

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

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

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

1369 

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

1371 

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

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

1374 """ 

1375 

1376 if box is None: 

1377 return self.copy() 

1378 

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

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

1381 raise ValueError(msg) 

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

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

1384 raise ValueError(msg) 

1385 

1386 self.load() 

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

1388 

1389 def _crop( 

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

1391 ) -> core.ImagingCore: 

1392 """ 

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

1394 

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

1396 includes additional sanity checks. 

1397 

1398 :param im: a core image object 

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

1400 :returns: A core image object. 

1401 """ 

1402 

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

1404 

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

1406 

1407 _decompression_bomb_check(absolute_values) 

1408 

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

1410 

1411 def draft( 

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

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

1414 """ 

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

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

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

1418 JPEG to grayscale while loading it. 

1419 

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

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

1422 

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

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

1425 effect. 

1426 

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

1428 currently implemented only for JPEG and MPO images. 

1429 

1430 :param mode: The requested mode. 

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

1432 (width, height). 

1433 """ 

1434 pass 

1435 

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

1437 """ 

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

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

1440 

1441 :param filter: Filter kernel. 

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

1443 

1444 from . import ImageFilter 

1445 

1446 self.load() 

1447 

1448 if callable(filter): 

1449 filter = filter() 

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

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

1452 raise TypeError(msg) 

1453 

1454 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1457 

1458 ims = [ 

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

1460 ] 

1461 return merge(self.mode, ims) 

1462 

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

1464 """ 

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

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

1467 

1468 :returns: A tuple containing band names. 

1469 """ 

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

1471 

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

1473 """ 

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

1475 image. 

1476 

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

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

1479 Otherwise, trim pixels when all channels are zero. 

1480 Keyword-only argument. 

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

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

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

1484 method returns None. 

1485 

1486 """ 

1487 

1488 self.load() 

1489 return self.im.getbbox(alpha_only) 

1490 

1491 def getcolors( 

1492 self, maxcolors: int = 256 

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

1494 """ 

1495 Returns a list of colors used in this image. 

1496 

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

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

1499 return the index of the color in the palette. 

1500 

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

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

1503 256 colors. 

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

1505 """ 

1506 

1507 self.load() 

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

1509 h = self.im.histogram() 

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

1511 if len(out) > maxcolors: 

1512 return None 

1513 return out 

1514 return self.im.getcolors(maxcolors) 

1515 

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

1517 """ 

1518 Returns the contents of this image as a sequence object 

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

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

1521 line zero, and so on. 

1522 

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

1524 internal PIL data type, which only supports certain sequence 

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

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

1527 

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

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

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

1531 :returns: A sequence-like object. 

1532 """ 

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

1534 

1535 self.load() 

1536 if band is not None: 

1537 return self.im.getband(band) 

1538 return self.im # could be abused 

1539 

1540 def get_flattened_data( 

1541 self, band: int | None = None 

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

1543 """ 

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

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

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

1547 

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

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

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

1551 :returns: A tuple containing pixel values. 

1552 """ 

1553 self.load() 

1554 if band is not None: 

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

1556 return tuple(self.im) 

1557 

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

1559 """ 

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

1561 the image. 

1562 

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

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

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

1566 """ 

1567 

1568 self.load() 

1569 if self.im.bands > 1: 

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

1571 return self.im.getextrema() 

1572 

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

1574 """ 

1575 Returns a dictionary containing the XMP tags. 

1576 Requires defusedxml to be installed. 

1577 

1578 :returns: XMP tags in a dictionary. 

1579 """ 

1580 

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

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

1583 

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

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

1586 children = list(element) 

1587 if children: 

1588 for child in children: 

1589 name = get_name(child.tag) 

1590 child_value = get_value(child) 

1591 if name in value: 

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

1593 value[name] = [value[name]] 

1594 value[name].append(child_value) 

1595 else: 

1596 value[name] = child_value 

1597 elif value: 

1598 if element.text: 

1599 value["text"] = element.text 

1600 else: 

1601 return element.text 

1602 return value 

1603 

1604 if ElementTree is None: 

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

1606 return {} 

1607 if "xmp" not in self.info: 

1608 return {} 

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

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

1611 

1612 def getexif(self) -> Exif: 

1613 """ 

1614 Gets EXIF data from the image. 

1615 

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

1617 """ 

1618 if self._exif is None: 

1619 self._exif = Exif() 

1620 elif self._exif._loaded: 

1621 return self._exif 

1622 self._exif._loaded = True 

1623 

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

1625 if exif_info is None: 

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

1627 exif_info = bytes.fromhex( 

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

1629 ) 

1630 elif hasattr(self, "tag_v2"): 

1631 from . import TiffImagePlugin 

1632 

1633 assert isinstance(self, TiffImagePlugin.TiffImageFile) 

1634 self._exif.bigtiff = self.tag_v2._bigtiff 

1635 self._exif.endian = self.tag_v2._endian 

1636 

1637 assert self.fp is not None 

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

1639 if exif_info is not None: 

1640 self._exif.load(exif_info) 

1641 

1642 # XMP tags 

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

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

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

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

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

1648 if xmp_tags: 

1649 match = re.search(pattern, xmp_tags) 

1650 if match: 

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

1652 

1653 return self._exif 

1654 

1655 def _reload_exif(self) -> None: 

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

1657 return 

1658 self._exif._loaded = False 

1659 self.getexif() 

1660 

1661 def getim(self) -> CapsuleType: 

1662 """ 

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

1664 

1665 :returns: A capsule object. 

1666 """ 

1667 

1668 self.load() 

1669 return self.im.ptr 

1670 

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

1672 """ 

1673 Returns the image palette as a list. 

1674 

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

1676 return the palette in its current mode. 

1677 

1678 .. versionadded:: 9.1.0 

1679 

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

1681 image has no palette. 

1682 """ 

1683 

1684 self.load() 

1685 try: 

1686 mode = self.im.getpalettemode() 

1687 except ValueError: 

1688 return None # no palette 

1689 if rawmode is None: 

1690 rawmode = mode 

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

1692 

1693 @property 

1694 def has_transparency_data(self) -> bool: 

1695 """ 

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

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

1698 in the info dictionary. 

1699 

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

1701 within are opaque. 

1702 

1703 :returns: A boolean. 

1704 """ 

1705 if ( 

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

1707 or "transparency" in self.info 

1708 ): 

1709 return True 

1710 if self.mode == "P": 

1711 assert self.palette is not None 

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

1713 return False 

1714 

1715 def apply_transparency(self) -> None: 

1716 """ 

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

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

1719 Otherwise, the image is unchanged. 

1720 """ 

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

1722 return 

1723 

1724 from . import ImagePalette 

1725 

1726 palette = self.getpalette("RGBA") 

1727 assert palette is not None 

1728 transparency = self.info["transparency"] 

1729 if isinstance(transparency, bytes): 

1730 for i, alpha in enumerate(transparency): 

1731 palette[i * 4 + 3] = alpha 

1732 else: 

1733 palette[transparency * 4 + 3] = 0 

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

1735 self.palette.dirty = 1 

1736 

1737 del self.info["transparency"] 

1738 

1739 def getpixel( 

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

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

1742 """ 

1743 Returns the pixel value at a given position. 

1744 

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

1746 :ref:`coordinate-system`. 

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

1748 this method returns a tuple. 

1749 """ 

1750 

1751 self.load() 

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

1753 

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

1755 """ 

1756 Get projection to x and y axes 

1757 

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

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

1760 """ 

1761 

1762 self.load() 

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

1764 return list(x), list(y) 

1765 

1766 def histogram( 

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

1768 ) -> list[int]: 

1769 """ 

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

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

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

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

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

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

1776 

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

1778 by this method. 

1779 

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

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

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

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

1784 

1785 :param mask: An optional mask. 

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

1787 :returns: A list containing pixel counts. 

1788 """ 

1789 self.load() 

1790 if mask: 

1791 mask.load() 

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

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

1794 return self.im.histogram( 

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

1796 ) 

1797 return self.im.histogram() 

1798 

1799 def entropy( 

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

1801 ) -> float: 

1802 """ 

1803 Calculates and returns the entropy for the image. 

1804 

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

1806 image by this method. 

1807 

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

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

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

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

1812 

1813 :param mask: An optional mask. 

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

1815 :returns: A float value representing the image entropy 

1816 """ 

1817 self.load() 

1818 if mask: 

1819 mask.load() 

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

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

1822 return self.im.entropy( 

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

1824 ) 

1825 return self.im.entropy() 

1826 

1827 def paste( 

1828 self, 

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

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

1831 mask: Image | None = None, 

1832 ) -> None: 

1833 """ 

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

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

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

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

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

1839 

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

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

1842 details). 

1843 

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

1845 containing pixel values. The method then fills the region 

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

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

1848 :ref:`colors` for more information. 

1849 

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

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

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

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

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

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

1856 channels if they have them. 

1857 

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

1859 combine images with respect to their alpha channels. 

1860 

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

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

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

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

1865 upper left corner. 

1866 

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

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

1869 is interpreted as a mask image. 

1870 :param mask: An optional mask image. 

1871 """ 

1872 

1873 if isinstance(box, Image): 

1874 if mask is not None: 

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

1876 raise ValueError(msg) 

1877 # abbreviated paste(im, mask) syntax 

1878 mask = box 

1879 box = None 

1880 

1881 if box is None: 

1882 box = (0, 0) 

1883 

1884 if len(box) == 2: 

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

1886 if isinstance(im, Image): 

1887 size = im.size 

1888 elif isinstance(mask, Image): 

1889 size = mask.size 

1890 else: 

1891 # FIXME: use self.size here? 

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

1893 raise ValueError(msg) 

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

1895 

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

1897 if isinstance(im, str): 

1898 from . import ImageColor 

1899 

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

1901 elif isinstance(im, Image): 

1902 im.load() 

1903 if self.mode != im.mode: 

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

1905 # should use an adapter for this! 

1906 im = im.convert(self.mode) 

1907 source = im.im 

1908 else: 

1909 source = im 

1910 

1911 self._ensure_mutable() 

1912 

1913 if mask: 

1914 mask.load() 

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

1916 else: 

1917 self.im.paste(source, box) 

1918 

1919 def alpha_composite( 

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

1921 ) -> None: 

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

1923 onto this image. 

1924 

1925 :param im: image to composite over this one 

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

1927 left corner in this (destination) image. 

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

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

1930 bottom) for the bounds of the source rectangle 

1931 

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

1933 """ 

1934 

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

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

1937 raise ValueError(msg) 

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

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

1940 raise ValueError(msg) 

1941 

1942 if len(source) == 4: 

1943 overlay_crop_box = tuple(source) 

1944 elif len(source) == 2: 

1945 overlay_crop_box = tuple(source) + im.size 

1946 else: 

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

1948 raise ValueError(msg) 

1949 

1950 if not len(dest) == 2: 

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

1952 raise ValueError(msg) 

1953 if min(source) < 0: 

1954 msg = "Source must be non-negative" 

1955 raise ValueError(msg) 

1956 

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

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

1959 overlay = im 

1960 else: 

1961 overlay = im.crop(overlay_crop_box) 

1962 

1963 # target for the paste 

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

1965 

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

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

1968 background = self 

1969 else: 

1970 background = self.crop(box) 

1971 

1972 result = alpha_composite(background, overlay) 

1973 self.paste(result, box) 

1974 

1975 def point( 

1976 self, 

1977 lut: ( 

1978 Sequence[float] 

1979 | NumpyArray 

1980 | Callable[[int], float] 

1981 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1982 | ImagePointHandler 

1983 ), 

1984 mode: str | None = None, 

1985 ) -> Image: 

1986 """ 

1987 Maps this image through a lookup table or function. 

1988 

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

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

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

1992 single argument. The function is called once for each 

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

1994 all bands of the image. 

1995 

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

1997 object:: 

1998 

1999 class Example(Image.ImagePointHandler): 

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

2001 # Return result 

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

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

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

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

2006 """ 

2007 

2008 self.load() 

2009 

2010 if isinstance(lut, ImagePointHandler): 

2011 return lut.point(self) 

2012 

2013 if callable(lut): 

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

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

2016 # check if the function can be used with point_transform 

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

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

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

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

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

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

2023 else: 

2024 flatLut = lut 

2025 

2026 if self.mode == "F": 

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

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

2029 raise ValueError(msg) 

2030 

2031 if mode != "F": 

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

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

2034 

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

2036 """ 

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

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

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

2040 

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

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

2043 """ 

2044 

2045 self._ensure_mutable() 

2046 

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

2048 # attempt to promote self to a matching alpha mode 

2049 try: 

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

2051 try: 

2052 self.im.setmode(mode) 

2053 except (AttributeError, ValueError) as e: 

2054 # do things the hard way 

2055 im = self.im.convert(mode) 

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

2057 msg = "alpha channel could not be added" 

2058 raise ValueError(msg) from e # sanity check 

2059 self.im = im 

2060 self._mode = self.im.mode 

2061 except KeyError as e: 

2062 msg = "illegal image mode" 

2063 raise ValueError(msg) from e 

2064 

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

2066 band = 1 

2067 else: 

2068 band = 3 

2069 

2070 if isinstance(alpha, Image): 

2071 # alpha layer 

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

2073 msg = "illegal image mode" 

2074 raise ValueError(msg) 

2075 alpha.load() 

2076 if alpha.mode == "1": 

2077 alpha = alpha.convert("L") 

2078 else: 

2079 # constant alpha 

2080 try: 

2081 self.im.fillband(band, alpha) 

2082 except (AttributeError, ValueError): 

2083 # do things the hard way 

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

2085 else: 

2086 return 

2087 

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

2089 

2090 def putdata( 

2091 self, 

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

2093 scale: float = 1.0, 

2094 offset: float = 0.0, 

2095 ) -> None: 

2096 """ 

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

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

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

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

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

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

2103 

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

2105 information about values. 

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

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

2108 """ 

2109 

2110 self._ensure_mutable() 

2111 

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

2113 

2114 def putpalette( 

2115 self, 

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

2117 rawmode: str = "RGB", 

2118 ) -> None: 

2119 """ 

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

2121 or "LA" image. 

2122 

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

2124 integer value for each channel in the raw mode. 

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

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

2127 index in the 256 colors. 

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

2129 containing red, green, blue and alpha values. 

2130 

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

2132 

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

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

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

2136 """ 

2137 from . import ImagePalette 

2138 

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

2140 msg = "illegal image mode" 

2141 raise ValueError(msg) 

2142 if isinstance(data, ImagePalette.ImagePalette): 

2143 if data.rawmode is not None: 

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

2145 else: 

2146 palette = ImagePalette.ImagePalette(palette=data.palette) 

2147 palette.dirty = 1 

2148 else: 

2149 if not isinstance(data, bytes): 

2150 data = bytes(data) 

2151 palette = ImagePalette.raw(rawmode, data) 

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

2153 self.palette = palette 

2154 if rawmode.startswith("CMYK"): 

2155 self.palette.mode = "CMYK" 

2156 elif "A" in rawmode: 

2157 self.palette.mode = "RGBA" 

2158 else: 

2159 self.palette.mode = "RGB" 

2160 self.load() # install new palette 

2161 

2162 def putpixel( 

2163 self, 

2164 xy: tuple[int, int] | list[int], 

2165 value: float | tuple[int, ...] | list[int], 

2166 ) -> None: 

2167 """ 

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

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

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

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

2172 

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

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

2175 module instead. 

2176 

2177 See: 

2178 

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

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

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

2182 

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

2184 :ref:`coordinate-system`. 

2185 :param value: The pixel value. 

2186 """ 

2187 

2188 self._ensure_mutable() 

2189 

2190 if ( 

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

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

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

2194 ): 

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

2196 if self.mode == "PA": 

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

2198 value = value[:3] 

2199 assert self.palette is not None 

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

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

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

2203 

2204 def remap_palette( 

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

2206 ) -> Image: 

2207 """ 

2208 Rewrites the image to reorder the palette. 

2209 

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

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

2212 is the identity transform. 

2213 :param source_palette: Bytes or None. 

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

2215 

2216 """ 

2217 from . import ImagePalette 

2218 

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

2220 msg = "illegal image mode" 

2221 raise ValueError(msg) 

2222 

2223 bands = 3 

2224 palette_mode = "RGB" 

2225 if source_palette is None: 

2226 if self.mode == "P": 

2227 self.load() 

2228 palette_mode = self.im.getpalettemode() 

2229 if palette_mode == "RGBA": 

2230 bands = 4 

2231 source_palette = self.im.getpalette(palette_mode) 

2232 else: # L-mode 

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

2234 elif len(source_palette) > 768: 

2235 bands = 4 

2236 palette_mode = "RGBA" 

2237 

2238 palette_bytes = b"" 

2239 new_positions = [0] * 256 

2240 

2241 # pick only the used colors from the palette 

2242 for i, oldPosition in enumerate(dest_map): 

2243 palette_bytes += source_palette[ 

2244 oldPosition * bands : oldPosition * bands + bands 

2245 ] 

2246 new_positions[oldPosition] = i 

2247 

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

2249 

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

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

2252 # from palette 1 to palette 2. New_positions is 

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

2254 # palette 1 with any holes removed. 

2255 

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

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

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

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

2260 # sans palette thus converting the image bytes, then 

2261 # assigning the optimized RGB palette. 

2262 

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

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

2265 

2266 mapping_palette = bytearray(new_positions) 

2267 

2268 m_im = self.copy() 

2269 m_im._mode = "P" 

2270 

2271 m_im.palette = ImagePalette.ImagePalette( 

2272 palette_mode, palette=mapping_palette * bands 

2273 ) 

2274 # possibly set palette dirty, then 

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

2276 # or just force it. 

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

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

2279 

2280 m_im = m_im.convert("L") 

2281 

2282 m_im.putpalette(palette_bytes, palette_mode) 

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

2284 

2285 if "transparency" in self.info: 

2286 try: 

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

2288 except ValueError: 

2289 if "transparency" in m_im.info: 

2290 del m_im.info["transparency"] 

2291 

2292 return m_im 

2293 

2294 def _get_safe_box( 

2295 self, 

2296 size: tuple[int, int], 

2297 resample: Resampling, 

2298 box: tuple[float, float, float, float], 

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

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

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

2302 """ 

2303 filter_support = _filters_support[resample] - 0.5 

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

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

2306 support_x = filter_support * scale_x 

2307 support_y = filter_support * scale_y 

2308 

2309 return ( 

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

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

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

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

2314 ) 

2315 

2316 def resize( 

2317 self, 

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

2319 resample: int | None = None, 

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

2321 reducing_gap: float | None = None, 

2322 ) -> Image: 

2323 """ 

2324 Returns a resized copy of this image. 

2325 

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

2327 (width, height). 

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

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

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

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

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

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

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

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

2336 the source image region to be scaled. 

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

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

2339 :param reducing_gap: Apply optimization by resizing the image 

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

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

2342 Second, resizing using regular resampling. The last step 

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

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

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

2346 the closer the result to the fair resampling. 

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

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

2349 indistinguishable from fair resampling in most cases. 

2350 The default value is None (no optimization). 

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

2352 """ 

2353 

2354 if resample is None: 

2355 resample = Resampling.BICUBIC 

2356 elif resample not in ( 

2357 Resampling.NEAREST, 

2358 Resampling.BILINEAR, 

2359 Resampling.BICUBIC, 

2360 Resampling.LANCZOS, 

2361 Resampling.BOX, 

2362 Resampling.HAMMING, 

2363 ): 

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

2365 

2366 filters = [ 

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

2368 for filter in ( 

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

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

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

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

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

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

2375 ) 

2376 ] 

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

2378 raise ValueError(msg) 

2379 

2380 if reducing_gap is not None and reducing_gap < 1.0: 

2381 msg = "reducing_gap must be 1.0 or greater" 

2382 raise ValueError(msg) 

2383 

2384 if box is None: 

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

2386 

2387 size = tuple(size) 

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

2389 return self.copy() 

2390 

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

2392 resample = Resampling.NEAREST 

2393 

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

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

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

2397 return im.convert(self.mode) 

2398 

2399 self.load() 

2400 

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

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

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

2404 if factor_x > 1 or factor_y > 1: 

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

2406 factor = (factor_x, factor_y) 

2407 self = ( 

2408 self.reduce(factor, box=reduce_box) 

2409 if callable(self.reduce) 

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

2411 ) 

2412 box = ( 

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

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

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

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

2417 ) 

2418 

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

2420 im = self.im.resize( 

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

2422 ) 

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

2424 else: 

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

2426 return self._new(im) 

2427 

2428 def reduce( 

2429 self, 

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

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

2432 ) -> Image: 

2433 """ 

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

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

2436 the resulting size will be rounded up. 

2437 

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

2439 for width and height separately. 

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

2441 the source image region to be reduced. 

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

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

2444 """ 

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

2446 factor = (factor, factor) 

2447 

2448 if box is None: 

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

2450 

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

2452 return self.copy() 

2453 

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

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

2456 im = im.reduce(factor, box) 

2457 return im.convert(self.mode) 

2458 

2459 self.load() 

2460 

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

2462 

2463 def rotate( 

2464 self, 

2465 angle: float, 

2466 resample: Resampling = Resampling.NEAREST, 

2467 expand: int | bool = False, 

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

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

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

2471 ) -> Image: 

2472 """ 

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

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

2475 clockwise around its centre. 

2476 

2477 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2484 See :ref:`concept-filters`. 

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

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

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

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

2489 the center and no translation. 

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

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

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

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

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

2495 """ 

2496 

2497 angle = angle % 360.0 

2498 

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

2500 # translating or changing the center. 

2501 if not (center or translate): 

2502 if angle == 0: 

2503 return self.copy() 

2504 if angle == 180: 

2505 return self.transpose(Transpose.ROTATE_180) 

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

2507 return self.transpose( 

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

2509 ) 

2510 

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

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

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

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

2515 

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

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

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

2519 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2520 

2521 # The reverse matrix is thus: 

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

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

2524 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2525 

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

2527 # compensate for the expand flag. 

2528 

2529 w, h = self.size 

2530 

2531 if translate is None: 

2532 post_trans = (0, 0) 

2533 else: 

2534 post_trans = translate 

2535 if center is None: 

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

2537 

2538 angle = -math.radians(angle) 

2539 matrix = [ 

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

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

2542 0.0, 

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

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

2545 0.0, 

2546 ] 

2547 

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

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

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

2551 

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

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

2554 ) 

2555 matrix[2] += center[0] 

2556 matrix[5] += center[1] 

2557 

2558 if expand: 

2559 # calculate output size 

2560 xx = [] 

2561 yy = [] 

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

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

2564 xx.append(transformed_x) 

2565 yy.append(transformed_y) 

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

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

2568 

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

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

2571 # translation vector as new translation vector. 

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

2573 w, h = nw, nh 

2574 

2575 return self.transform( 

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

2577 ) 

2578 

2579 def save( 

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

2581 ) -> None: 

2582 """ 

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

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

2585 extension, if possible. 

2586 

2587 Keyword options can be used to provide additional instructions 

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

2589 silently ignored. The available options are described in the 

2590 :doc:`image format documentation 

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

2592 

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

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

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

2596 methods, and be opened in binary mode. 

2597 

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

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

2600 format to use is determined from the filename extension. 

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

2602 parameter should always be used. 

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

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

2605 saving multiple images:: 

2606 

2607 # Saving XMP data to a single image 

2608 from PIL import Image 

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

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

2611 

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

2613 from PIL import Image 

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

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

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

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

2618 :returns: None 

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

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

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

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

2623 """ 

2624 

2625 filename: str | bytes = "" 

2626 open_fp = False 

2627 if is_path(fp): 

2628 filename = os.fspath(fp) 

2629 open_fp = True 

2630 elif fp == sys.stdout and isinstance(sys.stdout, io.TextIOWrapper): 

2631 fp = sys.stdout.buffer 

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

2633 # only set the name for metadata purposes 

2634 filename = os.fspath(fp.name) 

2635 

2636 if format: 

2637 preinit() 

2638 else: 

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

2640 ext = ( 

2641 filename_ext.decode() 

2642 if isinstance(filename_ext, bytes) 

2643 else filename_ext 

2644 ) 

2645 

2646 # Try importing only the plugin for this extension first 

2647 if not _import_plugin_for_extension(ext): 

2648 preinit() 

2649 

2650 if ext not in EXTENSION: 

2651 init() 

2652 try: 

2653 format = EXTENSION[ext] 

2654 except KeyError as e: 

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

2656 raise ValueError(msg) from e 

2657 

2658 from . import ImageFile 

2659 

2660 # may mutate self! 

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

2662 filename 

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

2664 self._ensure_mutable() 

2665 else: 

2666 self.load() 

2667 

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

2669 self._default_encoderinfo = params 

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

2671 self._attach_default_encoderinfo(self) 

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

2673 

2674 if format.upper() not in SAVE: 

2675 init() 

2676 if save_all or ( 

2677 save_all is None 

2678 and params.get("append_images") 

2679 and format.upper() in SAVE_ALL 

2680 ): 

2681 save_handler = SAVE_ALL[format.upper()] 

2682 else: 

2683 save_handler = SAVE[format.upper()] 

2684 

2685 created = False 

2686 if open_fp: 

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

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

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

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

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

2692 else: 

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

2694 else: 

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

2696 

2697 try: 

2698 save_handler(self, fp, filename) 

2699 except Exception: 

2700 if open_fp: 

2701 fp.close() 

2702 if created: 

2703 try: 

2704 os.remove(filename) 

2705 except PermissionError: 

2706 pass 

2707 raise 

2708 finally: 

2709 self.encoderinfo = encoderinfo 

2710 if open_fp: 

2711 fp.close() 

2712 

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

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

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

2716 return encoderinfo 

2717 

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

2719 """ 

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

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

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

2723 library automatically seeks to frame 0. 

2724 

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

2726 

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

2728 number of available frames. 

2729 

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

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

2732 of the sequence. 

2733 """ 

2734 

2735 # overridden by file handlers 

2736 if frame != 0: 

2737 msg = "no more images in file" 

2738 raise EOFError(msg) 

2739 

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

2741 """ 

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

2743 

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

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

2746 

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

2748 PNG format. 

2749 

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

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

2752 

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

2754 

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

2756 

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

2758 """ 

2759 

2760 from . import ImageShow 

2761 

2762 ImageShow.show(self, title) 

2763 

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

2765 """ 

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

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

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

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

2770 blue). 

2771 

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

2773 method can be more convenient and faster. 

2774 

2775 :returns: A tuple containing bands. 

2776 """ 

2777 

2778 self.load() 

2779 if self.im.bands == 1: 

2780 return (self.copy(),) 

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

2782 

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

2784 """ 

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

2786 

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

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

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

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

2791 

2792 .. versionadded:: 4.3.0 

2793 """ 

2794 self.load() 

2795 

2796 if isinstance(channel, str): 

2797 try: 

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

2799 except ValueError as e: 

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

2801 raise ValueError(msg) from e 

2802 

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

2804 

2805 def tell(self) -> int: 

2806 """ 

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

2808 

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

2810 number of available frames. 

2811 

2812 :returns: Frame number, starting with 0. 

2813 """ 

2814 return 0 

2815 

2816 def thumbnail( 

2817 self, 

2818 size: tuple[float, float], 

2819 resample: Resampling = Resampling.BICUBIC, 

2820 reducing_gap: float | None = 2.0, 

2821 ) -> None: 

2822 """ 

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

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

2825 the given size. This method calculates an appropriate thumbnail 

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

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

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

2829 

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

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

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

2833 image. 

2834 

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

2836 (width, height). 

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

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

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

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

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

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

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

2844 :param reducing_gap: Apply optimization by resizing the image 

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

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

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

2848 Second, resizing using regular resampling. The last step 

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

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

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

2852 the closer the result to the fair resampling. 

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

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

2855 indistinguishable from fair resampling in most cases. 

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

2857 while still being faster in many cases). 

2858 :returns: None 

2859 """ 

2860 

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

2862 

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

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

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

2866 

2867 x, y = provided_size 

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

2869 return None 

2870 

2871 aspect = self.width / self.height 

2872 if x / y >= aspect: 

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

2874 else: 

2875 y = round_aspect( 

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

2877 ) 

2878 return x, y 

2879 

2880 preserved_size = preserve_aspect_ratio() 

2881 if preserved_size is None: 

2882 return 

2883 final_size = preserved_size 

2884 

2885 box = None 

2886 if reducing_gap is not None: 

2887 res = self.draft( 

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

2889 ) 

2890 if res is not None: 

2891 box = res[1] 

2892 

2893 if self.size != final_size: 

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

2895 

2896 self.im = im.im 

2897 self._size = final_size 

2898 self._mode = self.im.mode 

2899 

2900 self.readonly = 0 

2901 

2902 # FIXME: the different transform methods need further explanation 

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

2904 def transform( 

2905 self, 

2906 size: tuple[int, int], 

2907 method: Transform | ImageTransformHandler | SupportsGetData, 

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

2909 resample: int = Resampling.NEAREST, 

2910 fill: int = 1, 

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

2912 ) -> Image: 

2913 """ 

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

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

2916 to the new image using the given transform. 

2917 

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

2919 (width, height). 

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

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

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

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

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

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

2926 in one operation). 

2927 

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

2929 object:: 

2930 

2931 class Example(Image.ImageTransformHandler): 

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

2933 # Return result 

2934 

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

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

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

2938 

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

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

2941 

2942 class Example: 

2943 def getdata(self): 

2944 method = Image.Transform.EXTENT 

2945 data = (0, 0, 100, 100) 

2946 return method, data 

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

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

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

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

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

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

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

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

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

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

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

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

2959 transform in the output image. 

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

2961 """ 

2962 

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

2964 return ( 

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

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

2967 .convert(self.mode) 

2968 ) 

2969 

2970 if isinstance(method, ImageTransformHandler): 

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

2972 

2973 if hasattr(method, "getdata"): 

2974 # compatibility w. old-style transform objects 

2975 method, data = method.getdata() 

2976 

2977 if data is None: 

2978 msg = "missing method data" 

2979 raise ValueError(msg) 

2980 

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

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

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

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

2985 if method == Transform.MESH: 

2986 # list of quads 

2987 for box, quad in data: 

2988 im.__transformer( 

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

2990 ) 

2991 else: 

2992 im.__transformer( 

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

2994 ) 

2995 

2996 return im 

2997 

2998 def __transformer( 

2999 self, 

3000 box: tuple[int, int, int, int], 

3001 image: Image, 

3002 method: Transform, 

3003 data: Sequence[float], 

3004 resample: int = Resampling.NEAREST, 

3005 fill: bool = True, 

3006 ) -> None: 

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

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

3009 

3010 if method == Transform.AFFINE: 

3011 data = data[:6] 

3012 

3013 elif method == Transform.EXTENT: 

3014 # convert extent to an affine transform 

3015 x0, y0, x1, y1 = data 

3016 xs = (x1 - x0) / w 

3017 ys = (y1 - y0) / h 

3018 method = Transform.AFFINE 

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

3020 

3021 elif method == Transform.PERSPECTIVE: 

3022 data = data[:8] 

3023 

3024 elif method == Transform.QUAD: 

3025 # quadrilateral warp. data specifies the four corners 

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

3027 nw = data[:2] 

3028 sw = data[2:4] 

3029 se = data[4:6] 

3030 ne = data[6:8] 

3031 x0, y0 = nw 

3032 As = 1.0 / w 

3033 At = 1.0 / h 

3034 data = ( 

3035 x0, 

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

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

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

3039 y0, 

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

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

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

3043 ) 

3044 

3045 else: 

3046 msg = "unknown transformation method" 

3047 raise ValueError(msg) 

3048 

3049 if resample not in ( 

3050 Resampling.NEAREST, 

3051 Resampling.BILINEAR, 

3052 Resampling.BICUBIC, 

3053 ): 

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

3055 unusable: dict[int, str] = { 

3056 Resampling.BOX: "Image.Resampling.BOX", 

3057 Resampling.HAMMING: "Image.Resampling.HAMMING", 

3058 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

3059 } 

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

3061 else: 

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

3063 

3064 filters = [ 

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

3066 for filter in ( 

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

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

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

3070 ) 

3071 ] 

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

3073 raise ValueError(msg) 

3074 

3075 image.load() 

3076 

3077 self.load() 

3078 

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

3080 resample = Resampling.NEAREST 

3081 

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

3083 

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

3085 """ 

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

3087 

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

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

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

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

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

3093 """ 

3094 

3095 self.load() 

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

3097 

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

3099 """ 

3100 Randomly spread pixels in an image. 

3101 

3102 :param distance: Distance to spread pixels. 

3103 """ 

3104 self.load() 

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

3106 

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

3108 """Returns a QImage copy of this image""" 

3109 from . import ImageQt 

3110 

3111 if not ImageQt.qt_is_installed: 

3112 msg = "Qt bindings are not installed" 

3113 raise ImportError(msg) 

3114 return ImageQt.toqimage(self) 

3115 

3116 def toqpixmap(self) -> ImageQt.QPixmap: 

3117 """Returns a QPixmap copy of this image""" 

3118 from . import ImageQt 

3119 

3120 if not ImageQt.qt_is_installed: 

3121 msg = "Qt bindings are not installed" 

3122 raise ImportError(msg) 

3123 return ImageQt.toqpixmap(self) 

3124 

3125 

3126# -------------------------------------------------------------------- 

3127# Abstract handlers. 

3128 

3129 

3130class ImagePointHandler(abc.ABC): 

3131 """ 

3132 Used as a mixin by point transforms 

3133 (for use with :py:meth:`~PIL.Image.Image.point`) 

3134 """ 

3135 

3136 @abc.abstractmethod 

3137 def point(self, im: Image) -> Image: 

3138 pass 

3139 

3140 

3141class ImageTransformHandler(abc.ABC): 

3142 """ 

3143 Used as a mixin by geometry transforms 

3144 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3145 """ 

3146 

3147 @abc.abstractmethod 

3148 def transform( 

3149 self, 

3150 size: tuple[int, int], 

3151 image: Image, 

3152 **options: Any, 

3153 ) -> Image: 

3154 pass 

3155 

3156 

3157# -------------------------------------------------------------------- 

3158# Factories 

3159 

3160 

3161def _check_size(size: Any) -> None: 

3162 """ 

3163 Common check to enforce type and sanity check on size tuples 

3164 

3165 :param size: Should be a 2 tuple of (width, height) 

3166 :returns: None, or raises a ValueError 

3167 """ 

3168 

3169 if not isinstance(size, (list, tuple)): 

3170 msg = "Size must be a list or tuple" 

3171 raise ValueError(msg) 

3172 if len(size) != 2: 

3173 msg = "Size must be a sequence of length 2" 

3174 raise ValueError(msg) 

3175 if size[0] < 0 or size[1] < 0: 

3176 msg = "Width and height must be >= 0" 

3177 raise ValueError(msg) 

3178 

3179 

3180def new( 

3181 mode: str, 

3182 size: tuple[int, int] | list[int], 

3183 color: float | tuple[float, ...] | str | None = 0, 

3184) -> Image: 

3185 """ 

3186 Creates a new image with the given mode and size. 

3187 

3188 :param mode: The mode to use for the new image. See: 

3189 :ref:`concept-modes`. 

3190 :param size: A 2-tuple, containing (width, height) in pixels. 

3191 :param color: What color to use for the image. Default is black. If given, 

3192 this should be a single integer or floating point value for single-band 

3193 modes, and a tuple for multi-band modes (one value per band). When 

3194 creating RGB or HSV images, you can also use color strings as supported 

3195 by the ImageColor module. See :ref:`colors` for more information. If the 

3196 color is None, the image is not initialised. 

3197 :returns: An :py:class:`~PIL.Image.Image` object. 

3198 """ 

3199 

3200 _check_size(size) 

3201 

3202 if color is None: 

3203 # don't initialize 

3204 return Image()._new(core.new(mode, size)) 

3205 

3206 if isinstance(color, str): 

3207 # css3-style specifier 

3208 

3209 from . import ImageColor 

3210 

3211 color = ImageColor.getcolor(color, mode) 

3212 

3213 im = Image() 

3214 if ( 

3215 mode == "P" 

3216 and isinstance(color, (list, tuple)) 

3217 and all(isinstance(i, int) for i in color) 

3218 ): 

3219 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3220 if len(color_ints) == 3 or len(color_ints) == 4: 

3221 # RGB or RGBA value for a P image 

3222 from . import ImagePalette 

3223 

3224 im.palette = ImagePalette.ImagePalette() 

3225 color = im.palette.getcolor(color_ints) 

3226 return im._new(core.fill(mode, size, color)) 

3227 

3228 

3229def frombytes( 

3230 mode: str, 

3231 size: tuple[int, int], 

3232 data: DecoderInput, 

3233 decoder_name: str = "raw", 

3234 *args: Any, 

3235) -> Image: 

3236 """ 

3237 Creates a copy of an image memory from pixel data in a buffer. 

3238 

3239 In its simplest form, this function takes three arguments 

3240 (mode, size, and unpacked pixel data). 

3241 

3242 You can also use any pixel decoder supported by PIL. For more 

3243 information on available decoders, see the section 

3244 :ref:`Writing Your Own File Codec <file-codecs>`. 

3245 

3246 Note that this function decodes pixel data only, not entire images. 

3247 If you have an entire image in a string, wrap it in a 

3248 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3249 it. 

3250 

3251 :param mode: The image mode. See: :ref:`concept-modes`. 

3252 :param size: The image size. 

3253 :param data: A byte buffer containing raw data for the given mode. 

3254 :param decoder_name: What decoder to use. 

3255 :param args: Additional parameters for the given decoder. 

3256 :returns: An :py:class:`~PIL.Image.Image` object. 

3257 """ 

3258 

3259 _check_size(size) 

3260 

3261 im = new(mode, size) 

3262 if im.width != 0 and im.height != 0: 

3263 decoder_args: Any = args 

3264 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3265 # may pass tuple instead of argument list 

3266 decoder_args = decoder_args[0] 

3267 

3268 if decoder_name == "raw" and decoder_args == (): 

3269 decoder_args = mode 

3270 

3271 im.frombytes(data, decoder_name, decoder_args) 

3272 return im 

3273 

3274 

3275def frombuffer( 

3276 mode: str, 

3277 size: tuple[int, int], 

3278 data: bytes | SupportsArrayInterface, 

3279 decoder_name: str = "raw", 

3280 *args: Any, 

3281) -> Image: 

3282 """ 

3283 Creates an image memory referencing pixel data in a byte buffer. 

3284 

3285 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3286 in the byte buffer, where possible. This means that changes to the 

3287 original buffer object are reflected in this image). Not all modes can 

3288 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3289 

3290 Note that this function decodes pixel data only, not entire images. 

3291 If you have an entire image file in a string, wrap it in a 

3292 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3293 

3294 The default parameters used for the "raw" decoder differs from that used for 

3295 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3296 future release. The current release issues a warning if you do this; to disable 

3297 the warning, you should provide the full set of parameters. See below for details. 

3298 

3299 :param mode: The image mode. See: :ref:`concept-modes`. 

3300 :param size: The image size. 

3301 :param data: A bytes or other buffer object containing raw 

3302 data for the given mode. 

3303 :param decoder_name: What decoder to use. 

3304 :param args: Additional parameters for the given decoder. For the 

3305 default encoder ("raw"), it's recommended that you provide the 

3306 full set of parameters:: 

3307 

3308 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3309 

3310 :returns: An :py:class:`~PIL.Image.Image` object. 

3311 

3312 .. versionadded:: 1.1.4 

3313 """ 

3314 

3315 _check_size(size) 

3316 

3317 # may pass tuple instead of argument list 

3318 if len(args) == 1 and isinstance(args[0], tuple): 

3319 args = args[0] 

3320 

3321 if decoder_name == "raw": 

3322 if args == (): 

3323 args = mode, 0, 1 

3324 if args[0] in _MAPMODES: 

3325 im = new(mode, (0, 0)) 

3326 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3327 if mode == "P": 

3328 from . import ImagePalette 

3329 

3330 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3331 im.readonly = 1 

3332 return im 

3333 

3334 return frombytes(mode, size, data, decoder_name, args) 

3335 

3336 

3337class SupportsArrayInterface(Protocol): 

3338 """ 

3339 An object that has an ``__array_interface__`` dictionary. 

3340 """ 

3341 

3342 @property 

3343 def __array_interface__(self) -> dict[str, Any]: 

3344 raise NotImplementedError() 

3345 

3346 def __len__(self) -> int: 

3347 raise NotImplementedError() 

3348 

3349 

3350DecoderInput = bytes | bytearray | memoryview | SupportsArrayInterface 

3351 

3352 

3353class SupportsArrowArrayInterface(Protocol): 

3354 """ 

3355 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3356 data interface. 

3357 """ 

3358 

3359 def __arrow_c_array__( 

3360 self, requested_schema: PyCapsule = None # type: ignore[name-defined] # noqa: F821 

3361 ) -> tuple[PyCapsule, PyCapsule]: # type: ignore[name-defined] # noqa: F821 

3362 raise NotImplementedError() 

3363 

3364 

3365def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3366 """ 

3367 Creates an image memory from an object exporting the array interface 

3368 (using the buffer protocol):: 

3369 

3370 from PIL import Image 

3371 import numpy as np 

3372 a = np.zeros((5, 5)) 

3373 im = Image.fromarray(a) 

3374 

3375 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3376 and :py:func:`~PIL.Image.frombuffer` is used. 

3377 

3378 In the case of NumPy, be aware that Pillow modes do not always correspond 

3379 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3380 32-bit signed integer pixels, and 32-bit floating point pixels. 

3381 

3382 Pillow images can also be converted to arrays:: 

3383 

3384 from PIL import Image 

3385 import numpy as np 

3386 im = Image.open("hopper.jpg") 

3387 a = np.asarray(im) 

3388 

3389 When converting Pillow images to arrays however, only pixel values are 

3390 transferred. This means that P and PA mode images will lose their palette. 

3391 

3392 :param obj: Object with array interface 

3393 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not 

3394 contain information about palettes or color spaces, this can be used to place 

3395 grayscale L mode data within a P mode image, or read RGB data as YCbCr for 

3396 example. 

3397 

3398 See: :ref:`concept-modes` for general information about modes. 

3399 :returns: An image object. 

3400 

3401 .. versionadded:: 1.1.6 

3402 """ 

3403 arr = obj.__array_interface__ 

3404 shape = arr["shape"] 

3405 ndim = len(shape) 

3406 strides = arr.get("strides", None) 

3407 try: 

3408 typekey = (1, 1) + shape[2:], arr["typestr"] 

3409 except KeyError as e: 

3410 if mode is not None: 

3411 typekey = None 

3412 color_modes: list[str] = [] 

3413 else: 

3414 msg = "Cannot handle this data type" 

3415 raise TypeError(msg) from e 

3416 if typekey is not None: 

3417 try: 

3418 typemode, rawmode, color_modes = _fromarray_typemap[typekey] 

3419 except KeyError as e: 

3420 typekey_shape, typestr = typekey 

3421 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3422 raise TypeError(msg) from e 

3423 if mode is not None: 

3424 if mode != typemode and mode not in color_modes: 

3425 msg = "Invalid mode for data type" 

3426 raise ValueError(msg) 

3427 rawmode = mode 

3428 else: 

3429 mode = typemode 

3430 if mode in ["1", "L", "I", "P", "F"]: 

3431 ndmax = 2 

3432 elif mode == "RGB": 

3433 ndmax = 3 

3434 else: 

3435 ndmax = 4 

3436 if ndim > ndmax: 

3437 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3438 raise ValueError(msg) 

3439 

3440 size = 1 if ndim == 1 else shape[1], shape[0] 

3441 if strides is not None: 

3442 if hasattr(obj, "tobytes"): 

3443 obj = obj.tobytes() 

3444 elif hasattr(obj, "tostring"): 

3445 obj = obj.tostring() 

3446 else: 

3447 msg = "'strides' requires either tobytes() or tostring()" 

3448 raise ValueError(msg) 

3449 

3450 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3451 

3452 

3453def fromarrow( 

3454 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3455) -> Image: 

3456 """Creates an image with zero-copy shared memory from an object exporting 

3457 the arrow_c_array interface protocol:: 

3458 

3459 from PIL import Image 

3460 import pyarrow as pa 

3461 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3462 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3463 

3464 If the data representation of the ``obj`` is not compatible with 

3465 Pillow internal storage, a ValueError is raised. 

3466 

3467 Pillow images can also be converted to Arrow objects:: 

3468 

3469 from PIL import Image 

3470 import pyarrow as pa 

3471 im = Image.open('hopper.jpg') 

3472 arr = pa.array(im) 

3473 

3474 As with array support, when converting Pillow images to arrays, 

3475 only pixel values are transferred. This means that P and PA mode 

3476 images will lose their palette. 

3477 

3478 :param obj: Object with an arrow_c_array interface 

3479 :param mode: Image mode. 

3480 :param size: Image size. This must match the storage of the arrow object. 

3481 :returns: An Image object 

3482 

3483 Note that according to the Arrow spec, both the producer and the 

3484 consumer should consider the exported array to be immutable, as 

3485 unsynchronized updates will potentially cause inconsistent data. 

3486 

3487 See: :ref:`arrow-support` for more detailed information 

3488 

3489 .. versionadded:: 11.2.1 

3490 

3491 """ 

3492 if not hasattr(obj, "__arrow_c_array__"): 

3493 msg = "arrow_c_array interface not found" 

3494 raise ValueError(msg) 

3495 

3496 schema_capsule, array_capsule = obj.__arrow_c_array__() 

3497 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3498 if _im: 

3499 return Image()._new(_im) 

3500 

3501 msg = "new_arrow returned None without an exception" 

3502 raise ValueError(msg) 

3503 

3504 

3505def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3506 """Creates an image instance from a QImage image""" 

3507 from . import ImageQt 

3508 

3509 if not ImageQt.qt_is_installed: 

3510 msg = "Qt bindings are not installed" 

3511 raise ImportError(msg) 

3512 return ImageQt.fromqimage(im) 

3513 

3514 

3515def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3516 """Creates an image instance from a QPixmap image""" 

3517 from . import ImageQt 

3518 

3519 if not ImageQt.qt_is_installed: 

3520 msg = "Qt bindings are not installed" 

3521 raise ImportError(msg) 

3522 return ImageQt.fromqpixmap(im) 

3523 

3524 

3525_fromarray_typemap = { 

3526 # (shape, typestr) => mode, rawmode, color modes 

3527 # first two members of shape are set to one 

3528 ((1, 1), "|b1"): ("1", "1;8", []), 

3529 ((1, 1), "|u1"): ("L", "L", ["P"]), 

3530 ((1, 1), "|i1"): ("I", "I;8", []), 

3531 ((1, 1), "<u2"): ("I", "I;16", []), 

3532 ((1, 1), ">u2"): ("I", "I;16B", []), 

3533 ((1, 1), "<i2"): ("I", "I;16S", []), 

3534 ((1, 1), ">i2"): ("I", "I;16BS", []), 

3535 ((1, 1), "<u4"): ("I", "I;32", []), 

3536 ((1, 1), ">u4"): ("I", "I;32B", []), 

3537 ((1, 1), "<i4"): ("I", "I;32S", []), 

3538 ((1, 1), ">i4"): ("I", "I;32BS", []), 

3539 ((1, 1), "<f4"): ("F", "F;32F", []), 

3540 ((1, 1), ">f4"): ("F", "F;32BF", []), 

3541 ((1, 1), "<f8"): ("F", "F;64F", []), 

3542 ((1, 1), ">f8"): ("F", "F;64BF", []), 

3543 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]), 

3544 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), 

3545 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), 

3546 # shortcuts: 

3547 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []), 

3548 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []), 

3549} 

3550 

3551 

3552def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3553 if MAX_IMAGE_PIXELS is None: 

3554 return 

3555 

3556 pixels = max(1, size[0]) * max(1, size[1]) 

3557 

3558 if pixels > 2 * MAX_IMAGE_PIXELS: 

3559 msg = ( 

3560 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3561 "pixels, could be decompression bomb DOS attack." 

3562 ) 

3563 raise DecompressionBombError(msg) 

3564 

3565 if pixels > MAX_IMAGE_PIXELS: 

3566 warnings.warn( 

3567 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3568 "could be decompression bomb DOS attack.", 

3569 DecompressionBombWarning, 

3570 ) 

3571 

3572 

3573def open( 

3574 fp: StrOrBytesPath | IO[bytes], 

3575 mode: Literal["r"] = "r", 

3576 formats: list[str] | tuple[str, ...] | None = None, 

3577) -> ImageFile.ImageFile: 

3578 """ 

3579 Opens and identifies the given image file. 

3580 

3581 This is a lazy operation; this function identifies the file, but 

3582 the file remains open and the actual image data is not read from 

3583 the file until you try to process the data (or call the 

3584 :py:meth:`~PIL.Image.Image.load` method). See 

3585 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3586 

3587 :param fp: A filename (string), os.PathLike object or a file object. 

3588 The file object must implement ``file.read``, 

3589 ``file.seek``, and ``file.tell`` methods, 

3590 and be opened in binary mode. The file object will also seek to zero 

3591 before reading. 

3592 :param mode: The mode. If given, this argument must be "r". 

3593 :param formats: A list or tuple of formats to attempt to load the file in. 

3594 This can be used to restrict the set of formats checked. 

3595 Pass ``None`` to try all supported formats. You can print the set of 

3596 available formats by running ``python3 -m PIL`` or using 

3597 the :py:func:`PIL.features.pilinfo` function. 

3598 :returns: An :py:class:`~PIL.Image.Image` object. 

3599 :exception FileNotFoundError: If the file cannot be found. 

3600 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3601 identified. 

3602 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3603 instance is used for ``fp``. 

3604 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3605 """ 

3606 

3607 if mode != "r": 

3608 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3609 raise ValueError(msg) 

3610 elif isinstance(fp, io.StringIO): 

3611 msg = ( # type: ignore[unreachable] 

3612 "StringIO cannot be used to open an image. " 

3613 "Binary data must be used instead." 

3614 ) 

3615 raise ValueError(msg) 

3616 

3617 if formats is None: 

3618 formats = ID 

3619 elif not isinstance(formats, (list, tuple)): 

3620 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3621 raise TypeError(msg) 

3622 

3623 exclusive_fp = False 

3624 filename: str | bytes = "" 

3625 if is_path(fp): 

3626 filename = os.fspath(fp) 

3627 fp = builtins.open(filename, "rb") 

3628 exclusive_fp = True 

3629 else: 

3630 fp = cast(IO[bytes], fp) 

3631 

3632 try: 

3633 fp.seek(0) 

3634 except (AttributeError, io.UnsupportedOperation): 

3635 fp = io.BytesIO(fp.read()) 

3636 exclusive_fp = True 

3637 

3638 prefix = fp.read(16) 

3639 

3640 # Try to import just the plugin needed for this file extension 

3641 # before falling back to preinit() which imports common plugins 

3642 ext = os.path.splitext(filename)[1] if filename else "" 

3643 if not _import_plugin_for_extension(ext): 

3644 preinit() 

3645 

3646 warning_messages: list[str] = [] 

3647 

3648 def _open_core( 

3649 fp: IO[bytes], 

3650 filename: str | bytes, 

3651 prefix: bytes, 

3652 formats: list[str] | tuple[str, ...], 

3653 ) -> ImageFile.ImageFile | None: 

3654 for i in formats: 

3655 i = i.upper() 

3656 if i not in OPEN: 

3657 init() 

3658 try: 

3659 factory, accept = OPEN[i] 

3660 result = not accept or accept(prefix) 

3661 if isinstance(result, str): 

3662 warning_messages.append(result) 

3663 elif result: 

3664 fp.seek(0) 

3665 im = factory(fp, filename) 

3666 _decompression_bomb_check(im.size) 

3667 return im 

3668 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3669 if WARN_POSSIBLE_FORMATS: 

3670 warning_messages.append(i + " opening failed. " + str(e)) 

3671 except BaseException: 

3672 if exclusive_fp: 

3673 fp.close() 

3674 raise 

3675 return None 

3676 

3677 im = _open_core(fp, filename, prefix, formats) 

3678 

3679 if im is None and formats is ID: 

3680 # Try preinit (few common plugins) then init (all plugins) 

3681 for loader in (preinit, init): 

3682 checked_formats = ID.copy() 

3683 loader() 

3684 if formats != checked_formats: 

3685 im = _open_core( 

3686 fp, 

3687 filename, 

3688 prefix, 

3689 tuple(f for f in formats if f not in checked_formats), 

3690 ) 

3691 if im is not None: 

3692 break 

3693 

3694 if im: 

3695 im._exclusive_fp = exclusive_fp 

3696 return im 

3697 

3698 if exclusive_fp: 

3699 fp.close() 

3700 for message in warning_messages: 

3701 warnings.warn(message) 

3702 msg = "cannot identify image file %r" % (filename if filename else fp) 

3703 raise UnidentifiedImageError(msg) 

3704 

3705 

3706# 

3707# Image processing. 

3708 

3709 

3710def alpha_composite(im1: Image, im2: Image) -> Image: 

3711 """ 

3712 Alpha composite im2 over im1. 

3713 

3714 :param im1: The first image. Must have mode RGBA or LA. 

3715 :param im2: The second image. Must have the same mode and size as the first image. 

3716 :returns: An :py:class:`~PIL.Image.Image` object. 

3717 """ 

3718 

3719 im1.load() 

3720 im2.load() 

3721 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3722 

3723 

3724def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3725 """ 

3726 Creates a new image by interpolating between two input images, using 

3727 a constant alpha:: 

3728 

3729 out = image1 * (1.0 - alpha) + image2 * alpha 

3730 

3731 :param im1: The first image. 

3732 :param im2: The second image. Must have the same mode and size as 

3733 the first image. 

3734 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3735 copy of the first image is returned. If alpha is 1.0, a copy of 

3736 the second image is returned. There are no restrictions on the 

3737 alpha value. If necessary, the result is clipped to fit into 

3738 the allowed output range. 

3739 :returns: An :py:class:`~PIL.Image.Image` object. 

3740 """ 

3741 

3742 im1.load() 

3743 im2.load() 

3744 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3745 

3746 

3747def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3748 """ 

3749 Create composite image by blending images using a transparency mask. 

3750 

3751 :param image1: The first image. 

3752 :param image2: The second image. Must have the same mode and 

3753 size as the first image. 

3754 :param mask: A mask image. This image can have mode 

3755 "1", "L", or "RGBA", and must have the same size as the 

3756 other two images. 

3757 """ 

3758 

3759 image = image2.copy() 

3760 image.paste(image1, None, mask) 

3761 return image 

3762 

3763 

3764def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3765 """ 

3766 Applies the function (which should take one argument) to each pixel 

3767 in the given image. If the image has more than one band, the same 

3768 function is applied to each band. Note that the function is 

3769 evaluated once for each possible pixel value, so you cannot use 

3770 random components or other generators. 

3771 

3772 :param image: The input image. 

3773 :param function: A function object, taking one integer argument. 

3774 :returns: An :py:class:`~PIL.Image.Image` object. 

3775 """ 

3776 

3777 return image.point(args[0]) 

3778 

3779 

3780def merge(mode: str, bands: Sequence[Image]) -> Image: 

3781 """ 

3782 Merge a set of single band images into a new multiband image. 

3783 

3784 :param mode: The mode to use for the output image. See: 

3785 :ref:`concept-modes`. 

3786 :param bands: A sequence containing one single-band image for 

3787 each band in the output image. All bands must have the 

3788 same size. 

3789 :returns: An :py:class:`~PIL.Image.Image` object. 

3790 """ 

3791 

3792 if getmodebands(mode) != len(bands) or "*" in mode: 

3793 msg = "wrong number of bands" 

3794 raise ValueError(msg) 

3795 for band in bands[1:]: 

3796 if band.mode != getmodetype(mode): 

3797 msg = "mode mismatch" 

3798 raise ValueError(msg) 

3799 if band.size != bands[0].size: 

3800 msg = "size mismatch" 

3801 raise ValueError(msg) 

3802 for band in bands: 

3803 band.load() 

3804 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3805 

3806 

3807# -------------------------------------------------------------------- 

3808# Plugin registry 

3809 

3810 

3811def register_open( 

3812 id: str, 

3813 factory: ( 

3814 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3815 | type[ImageFile.ImageFile] 

3816 ), 

3817 accept: Callable[[bytes], bool | str] | None = None, 

3818) -> None: 

3819 """ 

3820 Register an image file plugin. This function should not be used 

3821 in application code. 

3822 

3823 :param id: An image format identifier. 

3824 :param factory: An image file factory method. 

3825 :param accept: An optional function that can be used to quickly 

3826 reject images having another format. 

3827 """ 

3828 id = id.upper() 

3829 if id not in ID: 

3830 ID.append(id) 

3831 OPEN[id] = factory, accept 

3832 

3833 

3834def register_mime(id: str, mimetype: str) -> None: 

3835 """ 

3836 Registers an image MIME type by populating ``Image.MIME``. This function 

3837 should not be used in application code. 

3838 

3839 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3840 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3841 provide a different result for specific images. 

3842 

3843 :param id: An image format identifier. 

3844 :param mimetype: The image MIME type for this format. 

3845 """ 

3846 MIME[id.upper()] = mimetype 

3847 

3848 

3849def register_save( 

3850 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3851) -> None: 

3852 """ 

3853 Registers an image save function. This function should not be 

3854 used in application code. 

3855 

3856 :param id: An image format identifier. 

3857 :param driver: A function to save images in this format. 

3858 """ 

3859 SAVE[id.upper()] = driver 

3860 

3861 

3862def register_save_all( 

3863 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3864) -> None: 

3865 """ 

3866 Registers an image function to save all the frames 

3867 of a multiframe format. This function should not be 

3868 used in application code. 

3869 

3870 :param id: An image format identifier. 

3871 :param driver: A function to save images in this format. 

3872 """ 

3873 SAVE_ALL[id.upper()] = driver 

3874 

3875 

3876def register_extension(id: str, extension: str) -> None: 

3877 """ 

3878 Registers an image extension. This function should not be 

3879 used in application code. 

3880 

3881 :param id: An image format identifier. 

3882 :param extension: An extension used for this format. 

3883 """ 

3884 EXTENSION[extension.lower()] = id.upper() 

3885 

3886 

3887def register_extensions(id: str, extensions: list[str]) -> None: 

3888 """ 

3889 Registers image extensions. This function should not be 

3890 used in application code. 

3891 

3892 :param id: An image format identifier. 

3893 :param extensions: A list of extensions used for this format. 

3894 """ 

3895 for extension in extensions: 

3896 register_extension(id, extension) 

3897 

3898 

3899def registered_extensions() -> dict[str, str]: 

3900 """ 

3901 Returns a dictionary containing all file extensions belonging 

3902 to registered plugins 

3903 """ 

3904 init() 

3905 return EXTENSION 

3906 

3907 

3908def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3909 """ 

3910 Registers an image decoder. This function should not be 

3911 used in application code. 

3912 

3913 :param name: The name of the decoder 

3914 :param decoder: An ImageFile.PyDecoder object 

3915 

3916 .. versionadded:: 4.1.0 

3917 """ 

3918 DECODERS[name] = decoder 

3919 

3920 

3921def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3922 """ 

3923 Registers an image encoder. This function should not be 

3924 used in application code. 

3925 

3926 :param name: The name of the encoder 

3927 :param encoder: An ImageFile.PyEncoder object 

3928 

3929 .. versionadded:: 4.1.0 

3930 """ 

3931 ENCODERS[name] = encoder 

3932 

3933 

3934# -------------------------------------------------------------------- 

3935# Effects 

3936 

3937 

3938def effect_mandelbrot( 

3939 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3940) -> Image: 

3941 """ 

3942 Generate a Mandelbrot set covering the given extent. 

3943 

3944 :param size: The requested size in pixels, as a 2-tuple: 

3945 (width, height). 

3946 :param extent: The extent to cover, as a 4-tuple: 

3947 (x0, y0, x1, y1). 

3948 :param quality: Quality. 

3949 """ 

3950 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3951 

3952 

3953def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3954 """ 

3955 Generate Gaussian noise centered around 128. 

3956 

3957 :param size: The requested size in pixels, as a 2-tuple: 

3958 (width, height). 

3959 :param sigma: Standard deviation of noise. 

3960 """ 

3961 return Image()._new(core.effect_noise(size, sigma)) 

3962 

3963 

3964def linear_gradient(mode: str) -> Image: 

3965 """ 

3966 Generate 256x256 linear gradient from black to white, top to bottom. 

3967 

3968 :param mode: Input mode. 

3969 """ 

3970 return Image()._new(core.linear_gradient(mode)) 

3971 

3972 

3973def radial_gradient(mode: str) -> Image: 

3974 """ 

3975 Generate 256x256 radial gradient from black to white, centre to edge. 

3976 

3977 :param mode: Input mode. 

3978 """ 

3979 return Image()._new(core.radial_gradient(mode)) 

3980 

3981 

3982# -------------------------------------------------------------------- 

3983# Resources 

3984 

3985 

3986def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

3987 env_dict = env if env is not None else os.environ 

3988 

3989 for var_name, setter in [ 

3990 ("PILLOW_ALIGNMENT", core.set_alignment), 

3991 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

3992 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

3993 ]: 

3994 if var_name not in env_dict: 

3995 continue 

3996 

3997 var = env_dict[var_name].lower() 

3998 

3999 units = 1 

4000 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

4001 if var.endswith(postfix): 

4002 units = mul 

4003 var = var[: -len(postfix)] 

4004 

4005 try: 

4006 var_int = int(var) * units 

4007 except ValueError: 

4008 warnings.warn(f"{var_name} is not int") 

4009 continue 

4010 

4011 try: 

4012 setter(var_int) 

4013 except ValueError as e: 

4014 warnings.warn(f"{var_name}: {e}") 

4015 

4016 

4017_apply_env_variables() 

4018atexit.register(core.clear_cache) 

4019 

4020 

4021if TYPE_CHECKING: 

4022 _ExifBase = MutableMapping[int, Any] 

4023else: 

4024 _ExifBase = MutableMapping 

4025 

4026 

4027class Exif(_ExifBase): 

4028 """ 

4029 This class provides read and write access to EXIF image data:: 

4030 

4031 from PIL import Image 

4032 im = Image.open("exif.png") 

4033 exif = im.getexif() # Returns an instance of this class 

4034 

4035 Information can be read and written, iterated over or deleted:: 

4036 

4037 print(exif[274]) # 1 

4038 exif[274] = 2 

4039 for k, v in exif.items(): 

4040 print("Tag", k, "Value", v) # Tag 274 Value 2 

4041 del exif[274] 

4042 

4043 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

4044 returns a dictionary:: 

4045 

4046 from PIL import ExifTags 

4047 im = Image.open("exif_gps.jpg") 

4048 exif = im.getexif() 

4049 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

4050 print(gps_ifd) 

4051 

4052 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

4053 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

4054 

4055 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

4056 

4057 print(exif[ExifTags.Base.Software]) # PIL 

4058 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

4059 """ 

4060 

4061 endian: str | None = None 

4062 bigtiff = False 

4063 _loaded = False 

4064 

4065 def __init__(self) -> None: 

4066 self._data: dict[int, Any] = {} 

4067 self._hidden_data: dict[int, Any] = {} 

4068 self._ifds: dict[int, dict[int, Any]] = {} 

4069 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

4070 self._loaded_exif: bytes | None = None 

4071 

4072 def _fixup(self, value: Any) -> Any: 

4073 try: 

4074 if len(value) == 1 and isinstance(value, tuple): 

4075 return value[0] 

4076 except Exception: 

4077 pass 

4078 return value 

4079 

4080 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

4081 # Helper function 

4082 # returns a dict with any single item tuples/lists as individual values 

4083 return {k: self._fixup(v) for k, v in src_dict.items()} 

4084 

4085 def _get_ifd_dict( 

4086 self, offset: int, group: int | None = None 

4087 ) -> dict[int, Any] | None: 

4088 try: 

4089 # an offset pointer to the location of the nested embedded IFD. 

4090 # It should be a long, but may be corrupted. 

4091 self.fp.seek(offset) 

4092 except (KeyError, TypeError): 

4093 return None 

4094 else: 

4095 from . import TiffImagePlugin 

4096 

4097 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

4098 info.load(self.fp) 

4099 return self._fixup_dict(dict(info)) 

4100 

4101 def _get_head(self) -> bytes: 

4102 version = b"\x2b" if self.bigtiff else b"\x2a" 

4103 if self.endian == "<": 

4104 head = b"II" + version + b"\x00" + o32le(8) 

4105 else: 

4106 head = b"MM\x00" + version + o32be(8) 

4107 if self.bigtiff: 

4108 head += o32le(8) if self.endian == "<" else o32be(8) 

4109 head += b"\x00\x00\x00\x00" 

4110 return head 

4111 

4112 def load(self, data: bytes) -> None: 

4113 # Extract EXIF information. This is highly experimental, 

4114 # and is likely to be replaced with something better in a future 

4115 # version. 

4116 

4117 # The EXIF record consists of a TIFF file embedded in a JPEG 

4118 # application marker (!). 

4119 if data == self._loaded_exif: 

4120 return 

4121 self._loaded_exif = data 

4122 self._data.clear() 

4123 self._hidden_data.clear() 

4124 self._ifds.clear() 

4125 while data and data.startswith(b"Exif\x00\x00"): 

4126 data = data[6:] 

4127 if not data: 

4128 self._info = None 

4129 return 

4130 

4131 self.fp: IO[bytes] = io.BytesIO(data) 

4132 self.head = self.fp.read(8) 

4133 # process dictionary 

4134 from . import TiffImagePlugin 

4135 

4136 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4137 self.endian = self._info._endian 

4138 self.fp.seek(self._info.next) 

4139 self._info.load(self.fp) 

4140 

4141 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4142 self._loaded_exif = None 

4143 self._data.clear() 

4144 self._hidden_data.clear() 

4145 self._ifds.clear() 

4146 

4147 # process dictionary 

4148 from . import TiffImagePlugin 

4149 

4150 self.fp = fp 

4151 if offset is not None: 

4152 self.head = self._get_head() 

4153 else: 

4154 self.head = self.fp.read(8) 

4155 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4156 if self.endian is None: 

4157 self.endian = self._info._endian 

4158 if offset is None: 

4159 offset = self._info.next 

4160 self.fp.tell() 

4161 self.fp.seek(offset) 

4162 self._info.load(self.fp) 

4163 

4164 def _get_merged_dict(self) -> dict[int, Any]: 

4165 merged_dict = dict(self) 

4166 

4167 # get EXIF extension 

4168 if ExifTags.IFD.Exif in self: 

4169 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4170 if ifd: 

4171 merged_dict.update(ifd) 

4172 

4173 # GPS 

4174 if ExifTags.IFD.GPSInfo in self: 

4175 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4176 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4177 ) 

4178 

4179 return merged_dict 

4180 

4181 def tobytes(self, offset: int = 8) -> bytes: 

4182 from . import TiffImagePlugin 

4183 

4184 head = self._get_head() 

4185 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4186 for tag, ifd_dict in self._ifds.items(): 

4187 if tag not in self: 

4188 ifd[tag] = ifd_dict 

4189 for tag, value in self.items(): 

4190 if tag in [ 

4191 ExifTags.IFD.Exif, 

4192 ExifTags.IFD.GPSInfo, 

4193 ] and not isinstance(value, dict): 

4194 value = self.get_ifd(tag) 

4195 if ( 

4196 tag == ExifTags.IFD.Exif 

4197 and ExifTags.IFD.Interop in value 

4198 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4199 ): 

4200 value = value.copy() 

4201 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4202 ifd[tag] = value 

4203 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4204 

4205 def get_ifd(self, tag: int) -> dict[int, Any]: 

4206 if tag not in self._ifds: 

4207 if tag == ExifTags.IFD.IFD1: 

4208 if self._info is not None and self._info.next != 0: 

4209 ifd = self._get_ifd_dict(self._info.next) 

4210 if ifd is not None: 

4211 self._ifds[tag] = ifd 

4212 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4213 offset = self._hidden_data.get(tag, self.get(tag)) 

4214 if offset is not None: 

4215 ifd = self._get_ifd_dict(offset, tag) 

4216 if ifd is not None: 

4217 self._ifds[tag] = ifd 

4218 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4219 if ExifTags.IFD.Exif not in self._ifds: 

4220 self.get_ifd(ExifTags.IFD.Exif) 

4221 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4222 if tag == ExifTags.IFD.MakerNote: 

4223 from .TiffImagePlugin import ImageFileDirectory_v2 

4224 

4225 try: 

4226 if tag_data.startswith(b"FUJIFILM"): 

4227 ifd_offset = i32le(tag_data, 8) 

4228 ifd_data = tag_data[ifd_offset:] 

4229 

4230 makernote = {} 

4231 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4232 ifd_tag, typ, count, data = struct.unpack( 

4233 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4234 ) 

4235 try: 

4236 ( 

4237 unit_size, 

4238 handler, 

4239 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4240 except KeyError: 

4241 continue 

4242 size = count * unit_size 

4243 if size > 4: 

4244 (offset,) = struct.unpack("<L", data) 

4245 data = ifd_data[offset - 12 : offset + size - 12] 

4246 else: 

4247 data = data[:size] 

4248 

4249 if len(data) != size: 

4250 warnings.warn( 

4251 "Possibly corrupt EXIF MakerNote data. " 

4252 f"Expecting to read {size} bytes but only got " 

4253 f"{len(data)}. Skipping tag {ifd_tag}" 

4254 ) 

4255 continue 

4256 

4257 if not data: 

4258 continue 

4259 

4260 makernote[ifd_tag] = handler( 

4261 ImageFileDirectory_v2(), data, False 

4262 ) 

4263 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4264 elif self.get(0x010F) == "Nintendo": 

4265 makernote = {} 

4266 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4267 ifd_tag, typ, count, data = struct.unpack( 

4268 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4269 ) 

4270 if ifd_tag == 0x1101: 

4271 # CameraInfo 

4272 (offset,) = struct.unpack(">L", data) 

4273 self.fp.seek(offset) 

4274 

4275 camerainfo: dict[str, int | bytes] = { 

4276 "ModelID": self.fp.read(4) 

4277 } 

4278 

4279 self.fp.read(4) 

4280 # Seconds since 2000 

4281 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4282 

4283 self.fp.read(4) 

4284 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4285 

4286 self.fp.read(12) 

4287 parallax = self.fp.read(4) 

4288 handler = ImageFileDirectory_v2._load_dispatch[ 

4289 TiffTags.FLOAT 

4290 ][1] 

4291 camerainfo["Parallax"] = handler( 

4292 ImageFileDirectory_v2(), parallax, False 

4293 )[0] 

4294 

4295 self.fp.read(4) 

4296 camerainfo["Category"] = self.fp.read(2) 

4297 

4298 makernote = {0x1101: camerainfo} 

4299 self._ifds[tag] = makernote 

4300 except struct.error: 

4301 pass 

4302 else: 

4303 # Interop 

4304 ifd = self._get_ifd_dict(tag_data, tag) 

4305 if ifd is not None: 

4306 self._ifds[tag] = ifd 

4307 ifd = self._ifds.setdefault(tag, {}) 

4308 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4309 ifd = { 

4310 k: v 

4311 for (k, v) in ifd.items() 

4312 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4313 } 

4314 return ifd 

4315 

4316 def hide_offsets(self) -> None: 

4317 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4318 if tag in self: 

4319 self._hidden_data[tag] = self[tag] 

4320 del self[tag] 

4321 

4322 def __str__(self) -> str: 

4323 if self._info is not None: 

4324 # Load all keys into self._data 

4325 for tag in self._info: 

4326 self[tag] 

4327 

4328 return str(self._data) 

4329 

4330 def __len__(self) -> int: 

4331 keys = set(self._data) 

4332 if self._info is not None: 

4333 keys.update(self._info) 

4334 return len(keys) 

4335 

4336 def __getitem__(self, tag: int) -> Any: 

4337 if self._info is not None and tag not in self._data and tag in self._info: 

4338 self._data[tag] = self._fixup(self._info[tag]) 

4339 del self._info[tag] 

4340 return self._data[tag] 

4341 

4342 def __contains__(self, tag: object) -> bool: 

4343 return tag in self._data or (self._info is not None and tag in self._info) 

4344 

4345 def __setitem__(self, tag: int, value: Any) -> None: 

4346 if self._info is not None and tag in self._info: 

4347 del self._info[tag] 

4348 self._data[tag] = value 

4349 

4350 def __delitem__(self, tag: int) -> None: 

4351 if self._info is not None and tag in self._info: 

4352 del self._info[tag] 

4353 else: 

4354 del self._data[tag] 

4355 if tag in self._ifds: 

4356 del self._ifds[tag] 

4357 

4358 def __iter__(self) -> Iterator[int]: 

4359 keys = set(self._data) 

4360 if self._info is not None: 

4361 keys.update(self._info) 

4362 return iter(keys)