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

1766 statements  

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# the Image class wrapper 

6# 

7# partial release history: 

8# 1995-09-09 fl Created 

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

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

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

12# 2000-06-07 fl PIL release 1.1 

13# 2000-10-20 fl PIL release 1.1.1 

14# 2001-05-07 fl PIL release 1.1.2 

15# 2002-03-15 fl PIL release 1.1.3 

16# 2003-05-10 fl PIL release 1.1.4 

17# 2005-03-28 fl PIL release 1.1.5 

18# 2006-12-02 fl PIL release 1.1.6 

19# 2009-11-15 fl PIL release 1.1.7 

20# 

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

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

23# 

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

25# 

26 

27from __future__ import annotations 

28 

29import abc 

30import atexit 

31import builtins 

32import io 

33import logging 

34import math 

35import os 

36import re 

37import struct 

38import sys 

39import tempfile 

40import warnings 

41from collections.abc import MutableMapping 

42from enum import IntEnum 

43from typing import IO, Protocol, cast 

44 

45# VERSION was removed in Pillow 6.0.0. 

46# PILLOW_VERSION was removed in Pillow 9.0.0. 

47# Use __version__ instead. 

48from . import ( 

49 ExifTags, 

50 ImageMode, 

51 TiffTags, 

52 UnidentifiedImageError, 

53 __version__, 

54 _plugins, 

55) 

56from ._binary import i32le, o32be, o32le 

57from ._deprecate import deprecate 

58from ._util import DeferredError, is_path 

59 

60ElementTree: ModuleType | None 

61try: 

62 from defusedxml import ElementTree 

63except ImportError: 

64 ElementTree = None 

65 

66TYPE_CHECKING = False 

67if TYPE_CHECKING: 

68 from collections.abc import Callable, Iterator, Sequence 

69 from types import ModuleType 

70 from typing import Any, Literal 

71 

72logger = logging.getLogger(__name__) 

73 

74 

75class DecompressionBombWarning(RuntimeWarning): 

76 pass 

77 

78 

79class DecompressionBombError(Exception): 

80 pass 

81 

82 

83WARN_POSSIBLE_FORMATS: bool = False 

84 

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

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

87 

88 

89try: 

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

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

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

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

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

95 from . import _imaging as core 

96 

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

98 msg = ( 

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

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

101 f"Pillow version: {__version__}" 

102 ) 

103 raise ImportError(msg) 

104 

105except ImportError as v: 

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

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

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

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

110 # possible. 

111 warnings.warn( 

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

113 RuntimeWarning, 

114 ) 

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

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

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

118 # see docs/porting.rst 

119 raise 

120 

121 

122# 

123# Constants 

124 

125 

126# transpose 

127class Transpose(IntEnum): 

128 FLIP_LEFT_RIGHT = 0 

129 FLIP_TOP_BOTTOM = 1 

130 ROTATE_90 = 2 

131 ROTATE_180 = 3 

132 ROTATE_270 = 4 

133 TRANSPOSE = 5 

134 TRANSVERSE = 6 

135 

136 

137# transforms (also defined in Imaging.h) 

138class Transform(IntEnum): 

139 AFFINE = 0 

140 EXTENT = 1 

141 PERSPECTIVE = 2 

142 QUAD = 3 

143 MESH = 4 

144 

145 

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

147class Resampling(IntEnum): 

148 NEAREST = 0 

149 BOX = 4 

150 BILINEAR = 2 

151 HAMMING = 5 

152 BICUBIC = 3 

153 LANCZOS = 1 

154 

155 

156_filters_support = { 

157 Resampling.BOX: 0.5, 

158 Resampling.BILINEAR: 1.0, 

159 Resampling.HAMMING: 1.0, 

160 Resampling.BICUBIC: 2.0, 

161 Resampling.LANCZOS: 3.0, 

162} 

163 

164 

165# dithers 

166class Dither(IntEnum): 

167 NONE = 0 

168 ORDERED = 1 # Not yet implemented 

169 RASTERIZE = 2 # Not yet implemented 

170 FLOYDSTEINBERG = 3 # default 

171 

172 

173# palettes/quantizers 

174class Palette(IntEnum): 

175 WEB = 0 

176 ADAPTIVE = 1 

177 

178 

179class Quantize(IntEnum): 

180 MEDIANCUT = 0 

181 MAXCOVERAGE = 1 

182 FASTOCTREE = 2 

183 LIBIMAGEQUANT = 3 

184 

185 

186module = sys.modules[__name__] 

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

188 for item in enum: 

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

190 

191 

192if hasattr(core, "DEFAULT_STRATEGY"): 

193 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

194 FILTERED = core.FILTERED 

195 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

196 RLE = core.RLE 

197 FIXED = core.FIXED 

198 

199 

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

201# Registries 

202 

203TYPE_CHECKING = False 

204if TYPE_CHECKING: 

205 import mmap 

206 from xml.etree.ElementTree import Element 

207 

208 from IPython.lib.pretty import PrettyPrinter 

209 

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

211 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath 

212ID: list[str] = [] 

213OPEN: dict[ 

214 str, 

215 tuple[ 

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

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

218 ], 

219] = {} 

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

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

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

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

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

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

226 

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

228# Modes 

229 

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

231 

232 

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

234 m = ImageMode.getmode(im.mode) 

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

236 extra = len(m.bands) 

237 if extra != 1: 

238 shape += (extra,) 

239 return shape, m.typestr 

240 

241 

242MODES = [ 

243 "1", 

244 "CMYK", 

245 "F", 

246 "HSV", 

247 "I", 

248 "I;16", 

249 "I;16B", 

250 "I;16L", 

251 "I;16N", 

252 "L", 

253 "LA", 

254 "La", 

255 "LAB", 

256 "P", 

257 "PA", 

258 "RGB", 

259 "RGBA", 

260 "RGBa", 

261 "RGBX", 

262 "YCbCr", 

263] 

264 

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

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

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

268 

269 

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

271 """ 

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

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

274 contain color data. 

275 

276 :param mode: Input mode. 

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

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

279 """ 

280 return ImageMode.getmode(mode).basemode 

281 

282 

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

284 """ 

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

286 single-layer mode suitable for storing individual bands. 

287 

288 :param mode: Input mode. 

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

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

291 """ 

292 return ImageMode.getmode(mode).basetype 

293 

294 

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

296 """ 

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

298 a tuple containing the names of individual bands (use 

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

300 individual band. 

301 

302 :param mode: Input mode. 

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

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

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

306 """ 

307 return ImageMode.getmode(mode).bands 

308 

309 

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

311 """ 

312 Gets the number of individual bands for this mode. 

313 

314 :param mode: Input mode. 

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

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

317 """ 

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

319 

320 

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

322# Helpers 

323 

324_initialized = 0 

325 

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

327_EXTENSION_PLUGIN: dict[str, str] = { 

328 # Common formats (preinit) 

329 ".bmp": "BmpImagePlugin", 

330 ".dib": "BmpImagePlugin", 

331 ".gif": "GifImagePlugin", 

332 ".jfif": "JpegImagePlugin", 

333 ".jpe": "JpegImagePlugin", 

334 ".jpg": "JpegImagePlugin", 

335 ".jpeg": "JpegImagePlugin", 

336 ".pbm": "PpmImagePlugin", 

337 ".pgm": "PpmImagePlugin", 

338 ".pnm": "PpmImagePlugin", 

339 ".ppm": "PpmImagePlugin", 

340 ".pfm": "PpmImagePlugin", 

341 ".png": "PngImagePlugin", 

342 ".apng": "PngImagePlugin", 

343 # Less common formats (init) 

344 ".avif": "AvifImagePlugin", 

345 ".avifs": "AvifImagePlugin", 

346 ".blp": "BlpImagePlugin", 

347 ".bufr": "BufrStubImagePlugin", 

348 ".cur": "CurImagePlugin", 

349 ".dcx": "DcxImagePlugin", 

350 ".dds": "DdsImagePlugin", 

351 ".ps": "EpsImagePlugin", 

352 ".eps": "EpsImagePlugin", 

353 ".fit": "FitsImagePlugin", 

354 ".fits": "FitsImagePlugin", 

355 ".fli": "FliImagePlugin", 

356 ".flc": "FliImagePlugin", 

357 ".fpx": "FpxImagePlugin", 

358 ".ftc": "FtexImagePlugin", 

359 ".ftu": "FtexImagePlugin", 

360 ".gbr": "GbrImagePlugin", 

361 ".grib": "GribStubImagePlugin", 

362 ".h5": "Hdf5StubImagePlugin", 

363 ".hdf": "Hdf5StubImagePlugin", 

364 ".icns": "IcnsImagePlugin", 

365 ".ico": "IcoImagePlugin", 

366 ".im": "ImImagePlugin", 

367 ".iim": "IptcImagePlugin", 

368 ".jp2": "Jpeg2KImagePlugin", 

369 ".j2k": "Jpeg2KImagePlugin", 

370 ".jpc": "Jpeg2KImagePlugin", 

371 ".jpf": "Jpeg2KImagePlugin", 

372 ".jpx": "Jpeg2KImagePlugin", 

373 ".j2c": "Jpeg2KImagePlugin", 

374 ".mic": "MicImagePlugin", 

375 ".mpg": "MpegImagePlugin", 

376 ".mpeg": "MpegImagePlugin", 

377 ".mpo": "MpoImagePlugin", 

378 ".msp": "MspImagePlugin", 

379 ".palm": "PalmImagePlugin", 

380 ".pcd": "PcdImagePlugin", 

381 ".pcx": "PcxImagePlugin", 

382 ".pdf": "PdfImagePlugin", 

383 ".pxr": "PixarImagePlugin", 

384 ".psd": "PsdImagePlugin", 

385 ".qoi": "QoiImagePlugin", 

386 ".bw": "SgiImagePlugin", 

387 ".rgb": "SgiImagePlugin", 

388 ".rgba": "SgiImagePlugin", 

389 ".sgi": "SgiImagePlugin", 

390 ".ras": "SunImagePlugin", 

391 ".tga": "TgaImagePlugin", 

392 ".icb": "TgaImagePlugin", 

393 ".vda": "TgaImagePlugin", 

394 ".vst": "TgaImagePlugin", 

395 ".tif": "TiffImagePlugin", 

396 ".tiff": "TiffImagePlugin", 

397 ".webp": "WebPImagePlugin", 

398 ".wmf": "WmfImagePlugin", 

399 ".emf": "WmfImagePlugin", 

400 ".xbm": "XbmImagePlugin", 

401 ".xpm": "XpmImagePlugin", 

402} 

403 

404 

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

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

407 if not ext: 

408 return False 

409 

410 if isinstance(ext, bytes): 

411 ext = ext.decode() 

412 ext = ext.lower() 

413 if ext in EXTENSION: 

414 return True 

415 

416 plugin = _EXTENSION_PLUGIN.get(ext) 

417 if plugin is None: 

418 return False 

419 

420 try: 

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

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

423 return True 

424 except ImportError as e: 

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

426 return False 

427 

428 

429def preinit() -> None: 

430 """ 

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

432 

433 It is called when opening or saving images. 

434 """ 

435 

436 global _initialized 

437 if _initialized >= 1: 

438 return 

439 

440 try: 

441 from . import BmpImagePlugin 

442 

443 assert BmpImagePlugin 

444 except ImportError: 

445 pass 

446 try: 

447 from . import GifImagePlugin 

448 

449 assert GifImagePlugin 

450 except ImportError: 

451 pass 

452 try: 

453 from . import JpegImagePlugin 

454 

455 assert JpegImagePlugin 

456 except ImportError: 

457 pass 

458 try: 

459 from . import PpmImagePlugin 

460 

461 assert PpmImagePlugin 

462 except ImportError: 

463 pass 

464 try: 

465 from . import PngImagePlugin 

466 

467 assert PngImagePlugin 

468 except ImportError: 

469 pass 

470 

471 _initialized = 1 

472 

473 

474def init() -> bool: 

475 """ 

476 Explicitly initializes the Python Imaging Library. This function 

477 loads all available file format drivers. 

478 

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

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

481 """ 

482 

483 global _initialized 

484 if _initialized >= 2: 

485 return False 

486 

487 for plugin in _plugins: 

488 try: 

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

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

491 except ImportError as e: # noqa: PERF203 

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

493 

494 if OPEN or SAVE: 

495 _initialized = 2 

496 return True 

497 return False 

498 

499 

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

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

502 

503 

504def _getdecoder( 

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

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

507 # tweak arguments 

508 if args is None: 

509 args = () 

510 elif not isinstance(args, tuple): 

511 args = (args,) 

512 

513 try: 

514 decoder = DECODERS[decoder_name] 

515 except KeyError: 

516 pass 

517 else: 

518 return decoder(mode, *args + extra) 

519 

520 try: 

521 # get decoder 

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

523 except AttributeError as e: 

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

525 raise OSError(msg) from e 

526 return decoder(mode, *args + extra) 

527 

528 

529def _getencoder( 

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

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

532 # tweak arguments 

533 if args is None: 

534 args = () 

535 elif not isinstance(args, tuple): 

536 args = (args,) 

537 

538 try: 

539 encoder = ENCODERS[encoder_name] 

540 except KeyError: 

541 pass 

542 else: 

543 return encoder(mode, *args + extra) 

544 

545 try: 

546 # get encoder 

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

548 except AttributeError as e: 

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

550 raise OSError(msg) from e 

551 return encoder(mode, *args + extra) 

552 

553 

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

555# Simple expression analyzer 

556 

557 

558class ImagePointTransform: 

559 """ 

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

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

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

563 """ 

564 

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

566 self.scale = scale 

567 self.offset = offset 

568 

569 def __neg__(self) -> ImagePointTransform: 

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

571 

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

573 if isinstance(other, ImagePointTransform): 

574 return ImagePointTransform( 

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

576 ) 

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

578 

579 __radd__ = __add__ 

580 

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

582 return self + -other 

583 

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

585 return other + -self 

586 

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

588 if isinstance(other, ImagePointTransform): 

589 return NotImplemented 

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

591 

592 __rmul__ = __mul__ 

593 

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

595 if isinstance(other, ImagePointTransform): 

596 return NotImplemented 

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

598 

599 

600def _getscaleoffset( 

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

602) -> tuple[float, float]: 

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

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

605 

606 

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

608# Implementation wrapper 

609 

610 

611class SupportsGetData(Protocol): 

612 def getdata( 

613 self, 

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

615 

616 

617class Image: 

618 """ 

619 This class represents an image object. To create 

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

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

622 directly. 

623 

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

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

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

627 """ 

628 

629 format: str | None = None 

630 format_description: str | None = None 

631 _close_exclusive_fp_after_loading = True 

632 

633 def __init__(self) -> None: 

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

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

636 self._mode = "" 

637 self._size = (0, 0) 

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

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

640 self.readonly = 0 

641 self._exif: Exif | None = None 

642 

643 @property 

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

645 if isinstance(self._im, DeferredError): 

646 raise self._im.ex 

647 assert self._im is not None 

648 return self._im 

649 

650 @im.setter 

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

652 self._im = im 

653 

654 @property 

655 def width(self) -> int: 

656 return self.size[0] 

657 

658 @property 

659 def height(self) -> int: 

660 return self.size[1] 

661 

662 @property 

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

664 return self._size 

665 

666 @property 

667 def mode(self) -> str: 

668 return self._mode 

669 

670 @property 

671 def readonly(self) -> int: 

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

673 

674 @readonly.setter 

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

676 self._readonly = readonly 

677 

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

679 new = Image() 

680 new.im = im 

681 new._mode = im.mode 

682 new._size = im.size 

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

684 if self.palette: 

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

686 else: 

687 from . import ImagePalette 

688 

689 new.palette = ImagePalette.ImagePalette() 

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

691 return new 

692 

693 # Context manager support 

694 def __enter__(self) -> Image: 

695 return self 

696 

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

698 pass 

699 

700 def close(self) -> None: 

701 """ 

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

703 The image data will be unusable afterward. 

704 

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

706 have not had their file read and closed by the 

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

708 more information. 

709 """ 

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

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

712 self.map.close() 

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

714 

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

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

717 # object is gone. 

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

719 

720 def _copy(self) -> None: 

721 self.load() 

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

723 self.readonly = 0 

724 

725 def _ensure_mutable(self) -> None: 

726 if self.readonly: 

727 self._copy() 

728 else: 

729 self.load() 

730 

731 def _dump( 

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

733 ) -> str: 

734 suffix = 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 :rtype: :py:class:`.PixelAccess` 

982 """ 

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

984 # realize palette 

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

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

987 self.palette.dirty = 0 

988 self.palette.rawmode = None 

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

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

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

992 else: 

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

994 self.palette.mode = "RGBA" 

995 elif self.palette.mode != mode: 

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

997 # then update the Python palette data 

998 self.palette.palette = self.im.getpalette( 

999 self.palette.mode, self.palette.mode 

1000 ) 

1001 

1002 if self._im is not None: 

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

1004 return None 

1005 

1006 def verify(self) -> None: 

1007 """ 

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

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

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

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

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

1013 file. 

1014 """ 

1015 pass 

1016 

1017 def convert( 

1018 self, 

1019 mode: str | None = None, 

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

1021 dither: Dither | None = None, 

1022 palette: Palette = Palette.WEB, 

1023 colors: int = 256, 

1024 ) -> Image: 

1025 """ 

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

1027 method translates pixels through the palette. If mode is 

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

1029 and the palette can be represented without a palette. 

1030 

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

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

1033 

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

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

1036 

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

1038 

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

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

1041 dither to approximate the original image luminosity levels. If 

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

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

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

1045 

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

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

1048 and ``dither`` and ``palette`` are ignored. 

1049 

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

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

1052 

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

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

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

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

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

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

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

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

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

1062 :data:`Palette.ADAPTIVE`. 

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

1064 palette. Defaults to 256. 

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

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

1067 """ 

1068 

1069 self.load() 

1070 

1071 has_transparency = "transparency" in self.info 

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

1073 # determine default mode 

1074 if self.palette: 

1075 mode = self.palette.mode 

1076 else: 

1077 mode = "RGB" 

1078 if mode == "RGB" and has_transparency: 

1079 mode = "RGBA" 

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

1081 return self.copy() 

1082 

1083 if matrix: 

1084 # matrix conversion 

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

1086 msg = "illegal conversion" 

1087 raise ValueError(msg) 

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

1089 new_im = self._new(im) 

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

1091 transparency = new_im.info["transparency"] 

1092 

1093 def convert_transparency( 

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

1095 ) -> int: 

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

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

1098 

1099 if mode == "L": 

1100 transparency = convert_transparency(matrix, transparency) 

1101 elif len(mode) == 3: 

1102 transparency = tuple( 

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

1104 for i in range(len(transparency)) 

1105 ) 

1106 new_im.info["transparency"] = transparency 

1107 return new_im 

1108 

1109 if self.mode == "RGBA": 

1110 if mode == "P": 

1111 return self.quantize(colors) 

1112 elif mode == "PA": 

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

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

1115 p = rgb.quantize(colors) 

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

1117 

1118 trns = None 

1119 delete_trns = False 

1120 # transparency handling 

1121 if has_transparency: 

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

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

1124 ): 

1125 # Use transparent conversion to promote from transparent 

1126 # color to an alpha channel. 

1127 new_im = self._new( 

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

1129 ) 

1130 del new_im.info["transparency"] 

1131 return new_im 

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

1133 t = self.info["transparency"] 

1134 if isinstance(t, bytes): 

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

1136 warnings.warn( 

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

1138 "converted to RGBA images" 

1139 ) 

1140 delete_trns = True 

1141 else: 

1142 # get the new transparency color. 

1143 # use existing conversions 

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

1145 if self.mode == "P": 

1146 assert self.palette is not None 

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

1148 if isinstance(t, tuple): 

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

1150 assert trns_im.palette is not None 

1151 try: 

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

1153 except ValueError as e: 

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

1155 # If all 256 colors are in use, 

1156 # then there is no need for transparency 

1157 t = None 

1158 else: 

1159 raise ValueError(err) from e 

1160 if t is None: 

1161 trns = None 

1162 else: 

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

1164 

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

1166 trns_im = trns_im.convert(mode) 

1167 else: 

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

1169 # after quantization. 

1170 trns_im = trns_im.convert("RGB") 

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

1172 

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

1174 t = self.info["transparency"] 

1175 delete_trns = True 

1176 

1177 if isinstance(t, bytes): 

1178 self.im.putpalettealphas(t) 

1179 elif isinstance(t, int): 

1180 self.im.putpalettealpha(t, 0) 

1181 else: 

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

1183 raise ValueError(msg) 

1184 

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

1186 im = self.im.quantize(colors) 

1187 new_im = self._new(im) 

1188 from . import ImagePalette 

1189 

1190 new_im.palette = ImagePalette.ImagePalette( 

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

1192 ) 

1193 if delete_trns: 

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

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

1196 del new_im.info["transparency"] 

1197 if trns is not None: 

1198 try: 

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

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

1201 new_im, 

1202 ) 

1203 except Exception: 

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

1205 # transparency hanging around to mess us up. 

1206 del new_im.info["transparency"] 

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

1208 return new_im 

1209 

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

1211 im = self 

1212 if mode == "LAB": 

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

1214 im = im.convert("RGBA") 

1215 other_mode = im.mode 

1216 else: 

1217 other_mode = mode 

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

1219 from . import ImageCms 

1220 

1221 srgb = ImageCms.createProfile("sRGB") 

1222 lab = ImageCms.createProfile("LAB") 

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

1224 transform = ImageCms.buildTransform( 

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

1226 ) 

1227 return transform.apply(im) 

1228 

1229 # colorspace conversion 

1230 if dither is None: 

1231 dither = Dither.FLOYDSTEINBERG 

1232 

1233 try: 

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

1235 except ValueError: 

1236 try: 

1237 # normalize source image and try again 

1238 modebase = getmodebase(self.mode) 

1239 if modebase == self.mode: 

1240 raise 

1241 im = self.im.convert(modebase) 

1242 im = im.convert(mode, dither) 

1243 except KeyError as e: 

1244 msg = "illegal conversion" 

1245 raise ValueError(msg) from e 

1246 

1247 new_im = self._new(im) 

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

1249 from . import ImagePalette 

1250 

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

1252 if delete_trns: 

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

1254 del new_im.info["transparency"] 

1255 if trns is not None: 

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

1257 try: 

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

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

1260 ) 

1261 except ValueError as e: 

1262 del new_im.info["transparency"] 

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

1264 # If all 256 colors are in use, 

1265 # then there is no need for transparency 

1266 warnings.warn( 

1267 "Couldn't allocate palette entry for transparency" 

1268 ) 

1269 else: 

1270 new_im.info["transparency"] = trns 

1271 return new_im 

1272 

1273 def quantize( 

1274 self, 

1275 colors: int = 256, 

1276 method: int | None = None, 

1277 kmeans: int = 0, 

1278 palette: Image | None = None, 

1279 dither: Dither = Dither.FLOYDSTEINBERG, 

1280 ) -> Image: 

1281 """ 

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

1283 of colors. 

1284 

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

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

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

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

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

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

1291 ``feature="libimagequant"``). 

1292 

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

1294 

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

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

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

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

1299 :param palette: Quantize to the palette of given 

1300 :py:class:`PIL.Image.Image`. 

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

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

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

1304 (default). 

1305 :returns: A new image 

1306 """ 

1307 

1308 self.load() 

1309 

1310 if method is None: 

1311 # defaults: 

1312 method = Quantize.MEDIANCUT 

1313 if self.mode == "RGBA": 

1314 method = Quantize.FASTOCTREE 

1315 

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

1317 Quantize.FASTOCTREE, 

1318 Quantize.LIBIMAGEQUANT, 

1319 ): 

1320 # Caller specified an invalid mode. 

1321 msg = ( 

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

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

1324 ) 

1325 raise ValueError(msg) 

1326 

1327 if palette: 

1328 # use palette from reference image 

1329 palette.load() 

1330 if palette.mode != "P": 

1331 msg = "bad mode for palette image" 

1332 raise ValueError(msg) 

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

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

1335 raise ValueError(msg) 

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

1337 new_im = self._new(im) 

1338 assert palette.palette is not None 

1339 new_im.palette = palette.palette.copy() 

1340 return new_im 

1341 

1342 if kmeans < 0: 

1343 msg = "kmeans must not be negative" 

1344 raise ValueError(msg) 

1345 

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

1347 

1348 from . import ImagePalette 

1349 

1350 mode = im.im.getpalettemode() 

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

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

1353 

1354 return im 

1355 

1356 def copy(self) -> Image: 

1357 """ 

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

1359 into an image, but still retain the original. 

1360 

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

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

1363 """ 

1364 self.load() 

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

1366 

1367 __copy__ = copy 

1368 

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

1370 """ 

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

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

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

1374 

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

1376 

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

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

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

1380 """ 

1381 

1382 if box is None: 

1383 return self.copy() 

1384 

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

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

1387 raise ValueError(msg) 

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

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

1390 raise ValueError(msg) 

1391 

1392 self.load() 

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

1394 

1395 def _crop( 

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

1397 ) -> core.ImagingCore: 

1398 """ 

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

1400 

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

1402 includes additional sanity checks. 

1403 

1404 :param im: a core image object 

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

1406 :returns: A core image object. 

1407 """ 

1408 

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

1410 

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

1412 

1413 _decompression_bomb_check(absolute_values) 

1414 

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

1416 

1417 def draft( 

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

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

1420 """ 

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

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

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

1424 JPEG to grayscale while loading it. 

1425 

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

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

1428 

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

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

1431 effect. 

1432 

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

1434 currently implemented only for JPEG and MPO images. 

1435 

1436 :param mode: The requested mode. 

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

1438 (width, height). 

1439 """ 

1440 pass 

1441 

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

1443 """ 

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

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

1446 

1447 :param filter: Filter kernel. 

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

1449 

1450 from . import ImageFilter 

1451 

1452 self.load() 

1453 

1454 if callable(filter): 

1455 filter = filter() 

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

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

1458 raise TypeError(msg) 

1459 

1460 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1463 

1464 ims = [ 

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

1466 ] 

1467 return merge(self.mode, ims) 

1468 

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

1470 """ 

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

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

1473 

1474 :returns: A tuple containing band names. 

1475 :rtype: tuple 

1476 """ 

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

1478 

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

1480 """ 

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

1482 image. 

1483 

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

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

1486 Otherwise, trim pixels when all channels are zero. 

1487 Keyword-only argument. 

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

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

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

1491 method returns None. 

1492 

1493 """ 

1494 

1495 self.load() 

1496 return self.im.getbbox(alpha_only) 

1497 

1498 def getcolors( 

1499 self, maxcolors: int = 256 

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

1501 """ 

1502 Returns a list of colors used in this image. 

1503 

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

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

1506 return the index of the color in the palette. 

1507 

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

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

1510 256 colors. 

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

1512 """ 

1513 

1514 self.load() 

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

1516 h = self.im.histogram() 

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

1518 if len(out) > maxcolors: 

1519 return None 

1520 return out 

1521 return self.im.getcolors(maxcolors) 

1522 

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

1524 """ 

1525 Returns the contents of this image as a sequence object 

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

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

1528 line zero, and so on. 

1529 

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

1531 internal PIL data type, which only supports certain sequence 

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

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

1534 

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

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

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

1538 :returns: A sequence-like object. 

1539 """ 

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

1541 

1542 self.load() 

1543 if band is not None: 

1544 return self.im.getband(band) 

1545 return self.im # could be abused 

1546 

1547 def get_flattened_data( 

1548 self, band: int | None = None 

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

1550 """ 

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

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

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

1554 

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

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

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

1558 :returns: A tuple containing pixel values. 

1559 """ 

1560 self.load() 

1561 if band is not None: 

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

1563 return tuple(self.im) 

1564 

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

1566 """ 

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

1568 the image. 

1569 

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

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

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

1573 """ 

1574 

1575 self.load() 

1576 if self.im.bands > 1: 

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

1578 return self.im.getextrema() 

1579 

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

1581 """ 

1582 Returns a dictionary containing the XMP tags. 

1583 Requires defusedxml to be installed. 

1584 

1585 :returns: XMP tags in a dictionary. 

1586 """ 

1587 

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

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

1590 

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

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

1593 children = list(element) 

1594 if children: 

1595 for child in children: 

1596 name = get_name(child.tag) 

1597 child_value = get_value(child) 

1598 if name in value: 

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

1600 value[name] = [value[name]] 

1601 value[name].append(child_value) 

1602 else: 

1603 value[name] = child_value 

1604 elif value: 

1605 if element.text: 

1606 value["text"] = element.text 

1607 else: 

1608 return element.text 

1609 return value 

1610 

1611 if ElementTree is None: 

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

1613 return {} 

1614 if "xmp" not in self.info: 

1615 return {} 

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

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

1618 

1619 def getexif(self) -> Exif: 

1620 """ 

1621 Gets EXIF data from the image. 

1622 

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

1624 """ 

1625 if self._exif is None: 

1626 self._exif = Exif() 

1627 elif self._exif._loaded: 

1628 return self._exif 

1629 self._exif._loaded = True 

1630 

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

1632 if exif_info is None: 

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

1634 exif_info = bytes.fromhex( 

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

1636 ) 

1637 elif hasattr(self, "tag_v2"): 

1638 from . import TiffImagePlugin 

1639 

1640 assert isinstance(self, TiffImagePlugin.TiffImageFile) 

1641 self._exif.bigtiff = self.tag_v2._bigtiff 

1642 self._exif.endian = self.tag_v2._endian 

1643 

1644 assert self.fp is not None 

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

1646 if exif_info is not None: 

1647 self._exif.load(exif_info) 

1648 

1649 # XMP tags 

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

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

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

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

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

1655 if xmp_tags: 

1656 match = re.search(pattern, xmp_tags) 

1657 if match: 

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

1659 

1660 return self._exif 

1661 

1662 def _reload_exif(self) -> None: 

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

1664 return 

1665 self._exif._loaded = False 

1666 self.getexif() 

1667 

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

1669 from . import ImageFile 

1670 

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

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

1673 

1674 def getim(self) -> CapsuleType: 

1675 """ 

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

1677 

1678 :returns: A capsule object. 

1679 """ 

1680 

1681 self.load() 

1682 return self.im.ptr 

1683 

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

1685 """ 

1686 Returns the image palette as a list. 

1687 

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

1689 return the palette in its current mode. 

1690 

1691 .. versionadded:: 9.1.0 

1692 

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

1694 image has no palette. 

1695 """ 

1696 

1697 self.load() 

1698 try: 

1699 mode = self.im.getpalettemode() 

1700 except ValueError: 

1701 return None # no palette 

1702 if rawmode is None: 

1703 rawmode = mode 

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

1705 

1706 @property 

1707 def has_transparency_data(self) -> bool: 

1708 """ 

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

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

1711 in the info dictionary. 

1712 

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

1714 within are opaque. 

1715 

1716 :returns: A boolean. 

1717 """ 

1718 if ( 

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

1720 or "transparency" in self.info 

1721 ): 

1722 return True 

1723 if self.mode == "P": 

1724 assert self.palette is not None 

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

1726 return False 

1727 

1728 def apply_transparency(self) -> None: 

1729 """ 

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

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

1732 Otherwise, the image is unchanged. 

1733 """ 

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

1735 return 

1736 

1737 from . import ImagePalette 

1738 

1739 palette = self.getpalette("RGBA") 

1740 assert palette is not None 

1741 transparency = self.info["transparency"] 

1742 if isinstance(transparency, bytes): 

1743 for i, alpha in enumerate(transparency): 

1744 palette[i * 4 + 3] = alpha 

1745 else: 

1746 palette[transparency * 4 + 3] = 0 

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

1748 self.palette.dirty = 1 

1749 

1750 del self.info["transparency"] 

1751 

1752 def getpixel( 

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

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

1755 """ 

1756 Returns the pixel value at a given position. 

1757 

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

1759 :ref:`coordinate-system`. 

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

1761 this method returns a tuple. 

1762 """ 

1763 

1764 self.load() 

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

1766 

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

1768 """ 

1769 Get projection to x and y axes 

1770 

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

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

1773 """ 

1774 

1775 self.load() 

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

1777 return list(x), list(y) 

1778 

1779 def histogram( 

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

1781 ) -> list[int]: 

1782 """ 

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

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

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

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

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

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

1789 

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

1791 by this method. 

1792 

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

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

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

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

1797 

1798 :param mask: An optional mask. 

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

1800 :returns: A list containing pixel counts. 

1801 """ 

1802 self.load() 

1803 if mask: 

1804 mask.load() 

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

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

1807 return self.im.histogram( 

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

1809 ) 

1810 return self.im.histogram() 

1811 

1812 def entropy( 

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

1814 ) -> float: 

1815 """ 

1816 Calculates and returns the entropy for the image. 

1817 

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

1819 image by this method. 

1820 

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

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

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

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

1825 

1826 :param mask: An optional mask. 

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

1828 :returns: A float value representing the image entropy 

1829 """ 

1830 self.load() 

1831 if mask: 

1832 mask.load() 

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

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

1835 return self.im.entropy( 

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

1837 ) 

1838 return self.im.entropy() 

1839 

1840 def paste( 

1841 self, 

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

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

1844 mask: Image | None = None, 

1845 ) -> None: 

1846 """ 

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

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

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

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

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

1852 

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

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

1855 details). 

1856 

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

1858 containing pixel values. The method then fills the region 

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

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

1861 :ref:`colors` for more information. 

1862 

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

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

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

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

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

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

1869 channels if they have them. 

1870 

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

1872 combine images with respect to their alpha channels. 

1873 

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

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

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

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

1878 upper left corner. 

1879 

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

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

1882 is interpreted as a mask image. 

1883 :param mask: An optional mask image. 

1884 """ 

1885 

1886 if isinstance(box, Image): 

1887 if mask is not None: 

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

1889 raise ValueError(msg) 

1890 # abbreviated paste(im, mask) syntax 

1891 mask = box 

1892 box = None 

1893 

1894 if box is None: 

1895 box = (0, 0) 

1896 

1897 if len(box) == 2: 

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

1899 if isinstance(im, Image): 

1900 size = im.size 

1901 elif isinstance(mask, Image): 

1902 size = mask.size 

1903 else: 

1904 # FIXME: use self.size here? 

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

1906 raise ValueError(msg) 

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

1908 

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

1910 if isinstance(im, str): 

1911 from . import ImageColor 

1912 

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

1914 elif isinstance(im, Image): 

1915 im.load() 

1916 if self.mode != im.mode: 

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

1918 # should use an adapter for this! 

1919 im = im.convert(self.mode) 

1920 source = im.im 

1921 else: 

1922 source = im 

1923 

1924 self._ensure_mutable() 

1925 

1926 if mask: 

1927 mask.load() 

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

1929 else: 

1930 self.im.paste(source, box) 

1931 

1932 def alpha_composite( 

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

1934 ) -> None: 

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

1936 onto this image. 

1937 

1938 :param im: image to composite over this one 

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

1940 left corner in this (destination) image. 

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

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

1943 bottom) for the bounds of the source rectangle 

1944 

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

1946 """ 

1947 

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

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

1950 raise ValueError(msg) 

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

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

1953 raise ValueError(msg) 

1954 

1955 if len(source) == 4: 

1956 overlay_crop_box = tuple(source) 

1957 elif len(source) == 2: 

1958 overlay_crop_box = tuple(source) + im.size 

1959 else: 

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

1961 raise ValueError(msg) 

1962 

1963 if not len(dest) == 2: 

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

1965 raise ValueError(msg) 

1966 if min(source) < 0: 

1967 msg = "Source must be non-negative" 

1968 raise ValueError(msg) 

1969 

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

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

1972 overlay = im 

1973 else: 

1974 overlay = im.crop(overlay_crop_box) 

1975 

1976 # target for the paste 

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

1978 

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

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

1981 background = self 

1982 else: 

1983 background = self.crop(box) 

1984 

1985 result = alpha_composite(background, overlay) 

1986 self.paste(result, box) 

1987 

1988 def point( 

1989 self, 

1990 lut: ( 

1991 Sequence[float] 

1992 | NumpyArray 

1993 | Callable[[int], float] 

1994 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1995 | ImagePointHandler 

1996 ), 

1997 mode: str | None = None, 

1998 ) -> Image: 

1999 """ 

2000 Maps this image through a lookup table or function. 

2001 

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

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

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

2005 single argument. The function is called once for each 

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

2007 all bands of the image. 

2008 

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

2010 object:: 

2011 

2012 class Example(Image.ImagePointHandler): 

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

2014 # Return result 

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

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

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

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

2019 """ 

2020 

2021 self.load() 

2022 

2023 if isinstance(lut, ImagePointHandler): 

2024 return lut.point(self) 

2025 

2026 if callable(lut): 

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

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

2029 # check if the function can be used with point_transform 

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

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

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

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

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

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

2036 else: 

2037 flatLut = lut 

2038 

2039 if self.mode == "F": 

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

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

2042 raise ValueError(msg) 

2043 

2044 if mode != "F": 

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

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

2047 

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

2049 """ 

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

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

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

2053 

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

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

2056 """ 

2057 

2058 self._ensure_mutable() 

2059 

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

2061 # attempt to promote self to a matching alpha mode 

2062 try: 

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

2064 try: 

2065 self.im.setmode(mode) 

2066 except (AttributeError, ValueError) as e: 

2067 # do things the hard way 

2068 im = self.im.convert(mode) 

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

2070 msg = "alpha channel could not be added" 

2071 raise ValueError(msg) from e # sanity check 

2072 self.im = im 

2073 self._mode = self.im.mode 

2074 except KeyError as e: 

2075 msg = "illegal image mode" 

2076 raise ValueError(msg) from e 

2077 

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

2079 band = 1 

2080 else: 

2081 band = 3 

2082 

2083 if isinstance(alpha, Image): 

2084 # alpha layer 

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

2086 msg = "illegal image mode" 

2087 raise ValueError(msg) 

2088 alpha.load() 

2089 if alpha.mode == "1": 

2090 alpha = alpha.convert("L") 

2091 else: 

2092 # constant alpha 

2093 try: 

2094 self.im.fillband(band, alpha) 

2095 except (AttributeError, ValueError): 

2096 # do things the hard way 

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

2098 else: 

2099 return 

2100 

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

2102 

2103 def putdata( 

2104 self, 

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

2106 scale: float = 1.0, 

2107 offset: float = 0.0, 

2108 ) -> None: 

2109 """ 

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

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

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

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

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

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

2116 

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

2118 information about values. 

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

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

2121 """ 

2122 

2123 self._ensure_mutable() 

2124 

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

2126 

2127 def putpalette( 

2128 self, 

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

2130 rawmode: str = "RGB", 

2131 ) -> None: 

2132 """ 

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

2134 or "LA" image. 

2135 

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

2137 integer value for each channel in the raw mode. 

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

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

2140 index in the 256 colors. 

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

2142 containing red, green, blue and alpha values. 

2143 

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

2145 

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

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

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

2149 """ 

2150 from . import ImagePalette 

2151 

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

2153 msg = "illegal image mode" 

2154 raise ValueError(msg) 

2155 if isinstance(data, ImagePalette.ImagePalette): 

2156 if data.rawmode is not None: 

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

2158 else: 

2159 palette = ImagePalette.ImagePalette(palette=data.palette) 

2160 palette.dirty = 1 

2161 else: 

2162 if not isinstance(data, bytes): 

2163 data = bytes(data) 

2164 palette = ImagePalette.raw(rawmode, data) 

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

2166 self.palette = palette 

2167 if rawmode.startswith("CMYK"): 

2168 self.palette.mode = "CMYK" 

2169 elif "A" in rawmode: 

2170 self.palette.mode = "RGBA" 

2171 else: 

2172 self.palette.mode = "RGB" 

2173 self.load() # install new palette 

2174 

2175 def putpixel( 

2176 self, 

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

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

2179 ) -> None: 

2180 """ 

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

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

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

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

2185 

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

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

2188 module instead. 

2189 

2190 See: 

2191 

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

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

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

2195 

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

2197 :ref:`coordinate-system`. 

2198 :param value: The pixel value. 

2199 """ 

2200 

2201 self._ensure_mutable() 

2202 

2203 if ( 

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

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

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

2207 ): 

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

2209 if self.mode == "PA": 

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

2211 value = value[:3] 

2212 assert self.palette is not None 

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

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

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

2216 

2217 def remap_palette( 

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

2219 ) -> Image: 

2220 """ 

2221 Rewrites the image to reorder the palette. 

2222 

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

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

2225 is the identity transform. 

2226 :param source_palette: Bytes or None. 

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

2228 

2229 """ 

2230 from . import ImagePalette 

2231 

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

2233 msg = "illegal image mode" 

2234 raise ValueError(msg) 

2235 

2236 bands = 3 

2237 palette_mode = "RGB" 

2238 if source_palette is None: 

2239 if self.mode == "P": 

2240 self.load() 

2241 palette_mode = self.im.getpalettemode() 

2242 if palette_mode == "RGBA": 

2243 bands = 4 

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

2245 else: # L-mode 

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

2247 elif len(source_palette) > 768: 

2248 bands = 4 

2249 palette_mode = "RGBA" 

2250 

2251 palette_bytes = b"" 

2252 new_positions = [0] * 256 

2253 

2254 # pick only the used colors from the palette 

2255 for i, oldPosition in enumerate(dest_map): 

2256 palette_bytes += source_palette[ 

2257 oldPosition * bands : oldPosition * bands + bands 

2258 ] 

2259 new_positions[oldPosition] = i 

2260 

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

2262 

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

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

2265 # from palette 1 to palette 2. New_positions is 

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

2267 # palette 1 with any holes removed. 

2268 

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

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

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

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

2273 # sans palette thus converting the image bytes, then 

2274 # assigning the optimized RGB palette. 

2275 

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

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

2278 

2279 mapping_palette = bytearray(new_positions) 

2280 

2281 m_im = self.copy() 

2282 m_im._mode = "P" 

2283 

2284 m_im.palette = ImagePalette.ImagePalette( 

2285 palette_mode, palette=mapping_palette * bands 

2286 ) 

2287 # possibly set palette dirty, then 

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

2289 # or just force it. 

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

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

2292 

2293 m_im = m_im.convert("L") 

2294 

2295 m_im.putpalette(palette_bytes, palette_mode) 

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

2297 

2298 if "transparency" in self.info: 

2299 try: 

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

2301 except ValueError: 

2302 if "transparency" in m_im.info: 

2303 del m_im.info["transparency"] 

2304 

2305 return m_im 

2306 

2307 def _get_safe_box( 

2308 self, 

2309 size: tuple[int, int], 

2310 resample: Resampling, 

2311 box: tuple[float, float, float, float], 

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

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

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

2315 """ 

2316 filter_support = _filters_support[resample] - 0.5 

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

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

2319 support_x = filter_support * scale_x 

2320 support_y = filter_support * scale_y 

2321 

2322 return ( 

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

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

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

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

2327 ) 

2328 

2329 def resize( 

2330 self, 

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

2332 resample: int | None = None, 

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

2334 reducing_gap: float | None = None, 

2335 ) -> Image: 

2336 """ 

2337 Returns a resized copy of this image. 

2338 

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

2340 (width, height). 

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

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

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

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

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

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

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

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

2349 the source image region to be scaled. 

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

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

2352 :param reducing_gap: Apply optimization by resizing the image 

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

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

2355 Second, resizing using regular resampling. The last step 

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

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

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

2359 the closer the result to the fair resampling. 

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

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

2362 indistinguishable from fair resampling in most cases. 

2363 The default value is None (no optimization). 

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

2365 """ 

2366 

2367 if resample is None: 

2368 resample = Resampling.BICUBIC 

2369 elif resample not in ( 

2370 Resampling.NEAREST, 

2371 Resampling.BILINEAR, 

2372 Resampling.BICUBIC, 

2373 Resampling.LANCZOS, 

2374 Resampling.BOX, 

2375 Resampling.HAMMING, 

2376 ): 

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

2378 

2379 filters = [ 

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

2381 for filter in ( 

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

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

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

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

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

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

2388 ) 

2389 ] 

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

2391 raise ValueError(msg) 

2392 

2393 if reducing_gap is not None and reducing_gap < 1.0: 

2394 msg = "reducing_gap must be 1.0 or greater" 

2395 raise ValueError(msg) 

2396 

2397 if box is None: 

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

2399 

2400 size = tuple(size) 

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

2402 return self.copy() 

2403 

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

2405 resample = Resampling.NEAREST 

2406 

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

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

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

2410 return im.convert(self.mode) 

2411 

2412 self.load() 

2413 

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

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

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

2417 if factor_x > 1 or factor_y > 1: 

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

2419 factor = (factor_x, factor_y) 

2420 self = ( 

2421 self.reduce(factor, box=reduce_box) 

2422 if callable(self.reduce) 

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

2424 ) 

2425 box = ( 

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

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

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

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

2430 ) 

2431 

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

2433 im = self.im.resize( 

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

2435 ) 

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

2437 else: 

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

2439 return self._new(im) 

2440 

2441 def reduce( 

2442 self, 

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

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

2445 ) -> Image: 

2446 """ 

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

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

2449 the resulting size will be rounded up. 

2450 

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

2452 for width and height separately. 

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

2454 the source image region to be reduced. 

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

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

2457 """ 

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

2459 factor = (factor, factor) 

2460 

2461 if box is None: 

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

2463 

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

2465 return self.copy() 

2466 

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

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

2469 im = im.reduce(factor, box) 

2470 return im.convert(self.mode) 

2471 

2472 self.load() 

2473 

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

2475 

2476 def rotate( 

2477 self, 

2478 angle: float, 

2479 resample: Resampling = Resampling.NEAREST, 

2480 expand: int | bool = False, 

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

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

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

2484 ) -> Image: 

2485 """ 

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

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

2488 clockwise around its centre. 

2489 

2490 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2497 See :ref:`concept-filters`. 

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

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

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

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

2502 the center and no translation. 

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

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

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

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

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

2508 """ 

2509 

2510 angle = angle % 360.0 

2511 

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

2513 # translating or changing the center. 

2514 if not (center or translate): 

2515 if angle == 0: 

2516 return self.copy() 

2517 if angle == 180: 

2518 return self.transpose(Transpose.ROTATE_180) 

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

2520 return self.transpose( 

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

2522 ) 

2523 

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

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

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

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

2528 

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

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

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

2532 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2533 

2534 # The reverse matrix is thus: 

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

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

2537 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2538 

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

2540 # compensate for the expand flag. 

2541 

2542 w, h = self.size 

2543 

2544 if translate is None: 

2545 post_trans = (0, 0) 

2546 else: 

2547 post_trans = translate 

2548 if center is None: 

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

2550 

2551 angle = -math.radians(angle) 

2552 matrix = [ 

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

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

2555 0.0, 

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

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

2558 0.0, 

2559 ] 

2560 

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

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

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

2564 

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

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

2567 ) 

2568 matrix[2] += center[0] 

2569 matrix[5] += center[1] 

2570 

2571 if expand: 

2572 # calculate output size 

2573 xx = [] 

2574 yy = [] 

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

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

2577 xx.append(transformed_x) 

2578 yy.append(transformed_y) 

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

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

2581 

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

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

2584 # translation vector as new translation vector. 

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

2586 w, h = nw, nh 

2587 

2588 return self.transform( 

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

2590 ) 

2591 

2592 def save( 

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

2594 ) -> None: 

2595 """ 

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

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

2598 extension, if possible. 

2599 

2600 Keyword options can be used to provide additional instructions 

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

2602 silently ignored. The available options are described in the 

2603 :doc:`image format documentation 

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

2605 

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

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

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

2609 methods, and be opened in binary mode. 

2610 

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

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

2613 format to use is determined from the filename extension. 

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

2615 parameter should always be used. 

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

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

2618 saving multiple images:: 

2619 

2620 # Saving XMP data to a single image 

2621 from PIL import Image 

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

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

2624 

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

2626 from PIL import Image 

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

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

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

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

2631 :returns: None 

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

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

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

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

2636 """ 

2637 

2638 filename: str | bytes = "" 

2639 open_fp = False 

2640 if is_path(fp): 

2641 filename = os.fspath(fp) 

2642 open_fp = True 

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

2644 fp = sys.stdout.buffer 

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

2646 # only set the name for metadata purposes 

2647 filename = os.fspath(fp.name) 

2648 

2649 if format: 

2650 preinit() 

2651 else: 

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

2653 ext = ( 

2654 filename_ext.decode() 

2655 if isinstance(filename_ext, bytes) 

2656 else filename_ext 

2657 ) 

2658 

2659 # Try importing only the plugin for this extension first 

2660 if not _import_plugin_for_extension(ext): 

2661 preinit() 

2662 

2663 if ext not in EXTENSION: 

2664 init() 

2665 try: 

2666 format = EXTENSION[ext] 

2667 except KeyError as e: 

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

2669 raise ValueError(msg) from e 

2670 

2671 from . import ImageFile 

2672 

2673 # may mutate self! 

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

2675 filename 

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

2677 self._ensure_mutable() 

2678 else: 

2679 self.load() 

2680 

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

2682 self._default_encoderinfo = params 

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

2684 self._attach_default_encoderinfo(self) 

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

2686 

2687 if format.upper() not in SAVE: 

2688 init() 

2689 if save_all or ( 

2690 save_all is None 

2691 and params.get("append_images") 

2692 and format.upper() in SAVE_ALL 

2693 ): 

2694 save_handler = SAVE_ALL[format.upper()] 

2695 else: 

2696 save_handler = SAVE[format.upper()] 

2697 

2698 created = False 

2699 if open_fp: 

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

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

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

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

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

2705 else: 

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

2707 else: 

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

2709 

2710 try: 

2711 save_handler(self, fp, filename) 

2712 except Exception: 

2713 if open_fp: 

2714 fp.close() 

2715 if created: 

2716 try: 

2717 os.remove(filename) 

2718 except PermissionError: 

2719 pass 

2720 raise 

2721 finally: 

2722 self.encoderinfo = encoderinfo 

2723 if open_fp: 

2724 fp.close() 

2725 

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

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

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

2729 return encoderinfo 

2730 

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

2732 """ 

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

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

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

2736 library automatically seeks to frame 0. 

2737 

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

2739 

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

2741 number of available frames. 

2742 

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

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

2745 of the sequence. 

2746 """ 

2747 

2748 # overridden by file handlers 

2749 if frame != 0: 

2750 msg = "no more images in file" 

2751 raise EOFError(msg) 

2752 

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

2754 """ 

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

2756 

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

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

2759 

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

2761 PNG format. 

2762 

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

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

2765 

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

2767 

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

2769 

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

2771 """ 

2772 

2773 from . import ImageShow 

2774 

2775 ImageShow.show(self, title) 

2776 

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

2778 """ 

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

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

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

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

2783 blue). 

2784 

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

2786 method can be more convenient and faster. 

2787 

2788 :returns: A tuple containing bands. 

2789 """ 

2790 

2791 self.load() 

2792 if self.im.bands == 1: 

2793 return (self.copy(),) 

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

2795 

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

2797 """ 

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

2799 

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

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

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

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

2804 

2805 .. versionadded:: 4.3.0 

2806 """ 

2807 self.load() 

2808 

2809 if isinstance(channel, str): 

2810 try: 

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

2812 except ValueError as e: 

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

2814 raise ValueError(msg) from e 

2815 

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

2817 

2818 def tell(self) -> int: 

2819 """ 

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

2821 

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

2823 number of available frames. 

2824 

2825 :returns: Frame number, starting with 0. 

2826 """ 

2827 return 0 

2828 

2829 def thumbnail( 

2830 self, 

2831 size: tuple[float, float], 

2832 resample: Resampling = Resampling.BICUBIC, 

2833 reducing_gap: float | None = 2.0, 

2834 ) -> None: 

2835 """ 

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

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

2838 the given size. This method calculates an appropriate thumbnail 

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

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

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

2842 

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

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

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

2846 image. 

2847 

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

2849 (width, height). 

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

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

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

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

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

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

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

2857 :param reducing_gap: Apply optimization by resizing the image 

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

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

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

2861 Second, resizing using regular resampling. The last step 

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

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

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

2865 the closer the result to the fair resampling. 

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

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

2868 indistinguishable from fair resampling in most cases. 

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

2870 while still being faster in many cases). 

2871 :returns: None 

2872 """ 

2873 

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

2875 

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

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

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

2879 

2880 x, y = provided_size 

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

2882 return None 

2883 

2884 aspect = self.width / self.height 

2885 if x / y >= aspect: 

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

2887 else: 

2888 y = round_aspect( 

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

2890 ) 

2891 return x, y 

2892 

2893 preserved_size = preserve_aspect_ratio() 

2894 if preserved_size is None: 

2895 return 

2896 final_size = preserved_size 

2897 

2898 box = None 

2899 if reducing_gap is not None: 

2900 res = self.draft( 

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

2902 ) 

2903 if res is not None: 

2904 box = res[1] 

2905 

2906 if self.size != final_size: 

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

2908 

2909 self.im = im.im 

2910 self._size = final_size 

2911 self._mode = self.im.mode 

2912 

2913 self.readonly = 0 

2914 

2915 # FIXME: the different transform methods need further explanation 

2916 # instead of bloating the method docs, add a separate chapter. 

2917 def transform( 

2918 self, 

2919 size: tuple[int, int], 

2920 method: Transform | ImageTransformHandler | SupportsGetData, 

2921 data: Sequence[Any] | None = None, 

2922 resample: int = Resampling.NEAREST, 

2923 fill: int = 1, 

2924 fillcolor: float | tuple[float, ...] | str | None = None, 

2925 ) -> Image: 

2926 """ 

2927 Transforms this image. This method creates a new image with the 

2928 given size, and the same mode as the original, and copies data 

2929 to the new image using the given transform. 

2930 

2931 :param size: The output size in pixels, as a 2-tuple: 

2932 (width, height). 

2933 :param method: The transformation method. This is one of 

2934 :py:data:`Transform.EXTENT` (cut out a rectangular subregion), 

2935 :py:data:`Transform.AFFINE` (affine transform), 

2936 :py:data:`Transform.PERSPECTIVE` (perspective transform), 

2937 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or 

2938 :py:data:`Transform.MESH` (map a number of source quadrilaterals 

2939 in one operation). 

2940 

2941 It may also be an :py:class:`~PIL.Image.ImageTransformHandler` 

2942 object:: 

2943 

2944 class Example(Image.ImageTransformHandler): 

2945 def transform(self, size, data, resample, fill=1): 

2946 # Return result 

2947 

2948 Implementations of :py:class:`~PIL.Image.ImageTransformHandler` 

2949 for some of the :py:class:`Transform` methods are provided 

2950 in :py:mod:`~PIL.ImageTransform`. 

2951 

2952 It may also be an object with a ``method.getdata`` method 

2953 that returns a tuple supplying new ``method`` and ``data`` values:: 

2954 

2955 class Example: 

2956 def getdata(self): 

2957 method = Image.Transform.EXTENT 

2958 data = (0, 0, 100, 100) 

2959 return method, data 

2960 :param data: Extra data to the transformation method. 

2961 :param resample: Optional resampling filter. It can be one of 

2962 :py:data:`Resampling.NEAREST` (use nearest neighbour), 

2963 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 

2964 environment), or :py:data:`Resampling.BICUBIC` (cubic spline 

2965 interpolation in a 4x4 environment). If omitted, or if the image 

2966 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. 

2967 See: :ref:`concept-filters`. 

2968 :param fill: If ``method`` is an 

2969 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of 

2970 the arguments passed to it. Otherwise, it is unused. 

2971 :param fillcolor: Optional fill color for the area outside the 

2972 transform in the output image. 

2973 :returns: An :py:class:`~PIL.Image.Image` object. 

2974 """ 

2975 

2976 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: 

2977 return ( 

2978 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2979 .transform(size, method, data, resample, fill, fillcolor) 

2980 .convert(self.mode) 

2981 ) 

2982 

2983 if isinstance(method, ImageTransformHandler): 

2984 return method.transform(size, self, resample=resample, fill=fill) 

2985 

2986 if hasattr(method, "getdata"): 

2987 # compatibility w. old-style transform objects 

2988 method, data = method.getdata() 

2989 

2990 if data is None: 

2991 msg = "missing method data" 

2992 raise ValueError(msg) 

2993 

2994 im = new(self.mode, size, fillcolor) 

2995 if self.mode == "P" and self.palette: 

2996 im.palette = self.palette.copy() 

2997 im.info = self.info.copy() 

2998 if method == Transform.MESH: 

2999 # list of quads 

3000 for box, quad in data: 

3001 im.__transformer( 

3002 box, self, Transform.QUAD, quad, resample, fillcolor is None 

3003 ) 

3004 else: 

3005 im.__transformer( 

3006 (0, 0) + size, self, method, data, resample, fillcolor is None 

3007 ) 

3008 

3009 return im 

3010 

3011 def __transformer( 

3012 self, 

3013 box: tuple[int, int, int, int], 

3014 image: Image, 

3015 method: Transform, 

3016 data: Sequence[float], 

3017 resample: int = Resampling.NEAREST, 

3018 fill: bool = True, 

3019 ) -> None: 

3020 w = box[2] - box[0] 

3021 h = box[3] - box[1] 

3022 

3023 if method == Transform.AFFINE: 

3024 data = data[:6] 

3025 

3026 elif method == Transform.EXTENT: 

3027 # convert extent to an affine transform 

3028 x0, y0, x1, y1 = data 

3029 xs = (x1 - x0) / w 

3030 ys = (y1 - y0) / h 

3031 method = Transform.AFFINE 

3032 data = (xs, 0, x0, 0, ys, y0) 

3033 

3034 elif method == Transform.PERSPECTIVE: 

3035 data = data[:8] 

3036 

3037 elif method == Transform.QUAD: 

3038 # quadrilateral warp. data specifies the four corners 

3039 # given as NW, SW, SE, and NE. 

3040 nw = data[:2] 

3041 sw = data[2:4] 

3042 se = data[4:6] 

3043 ne = data[6:8] 

3044 x0, y0 = nw 

3045 As = 1.0 / w 

3046 At = 1.0 / h 

3047 data = ( 

3048 x0, 

3049 (ne[0] - x0) * As, 

3050 (sw[0] - x0) * At, 

3051 (se[0] - sw[0] - ne[0] + x0) * As * At, 

3052 y0, 

3053 (ne[1] - y0) * As, 

3054 (sw[1] - y0) * At, 

3055 (se[1] - sw[1] - ne[1] + y0) * As * At, 

3056 ) 

3057 

3058 else: 

3059 msg = "unknown transformation method" 

3060 raise ValueError(msg) 

3061 

3062 if resample not in ( 

3063 Resampling.NEAREST, 

3064 Resampling.BILINEAR, 

3065 Resampling.BICUBIC, 

3066 ): 

3067 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

3068 unusable: dict[int, str] = { 

3069 Resampling.BOX: "Image.Resampling.BOX", 

3070 Resampling.HAMMING: "Image.Resampling.HAMMING", 

3071 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

3072 } 

3073 msg = unusable[resample] + f" ({resample}) cannot be used." 

3074 else: 

3075 msg = f"Unknown resampling filter ({resample})." 

3076 

3077 filters = [ 

3078 f"{filter[1]} ({filter[0]})" 

3079 for filter in ( 

3080 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

3081 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

3082 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

3083 ) 

3084 ] 

3085 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

3086 raise ValueError(msg) 

3087 

3088 image.load() 

3089 

3090 self.load() 

3091 

3092 if image.mode in ("1", "P"): 

3093 resample = Resampling.NEAREST 

3094 

3095 self.im.transform(box, image.im, method, data, resample, fill) 

3096 

3097 def transpose(self, method: Transpose) -> Image: 

3098 """ 

3099 Transpose image (flip or rotate in 90 degree steps) 

3100 

3101 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

3102 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

3103 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

3104 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

3105 :returns: Returns a flipped or rotated copy of this image. 

3106 """ 

3107 

3108 self.load() 

3109 return self._new(self.im.transpose(method)) 

3110 

3111 def effect_spread(self, distance: int) -> Image: 

3112 """ 

3113 Randomly spread pixels in an image. 

3114 

3115 :param distance: Distance to spread pixels. 

3116 """ 

3117 self.load() 

3118 return self._new(self.im.effect_spread(distance)) 

3119 

3120 def toqimage(self) -> ImageQt.ImageQt: 

3121 """Returns a QImage copy of this image""" 

3122 from . import ImageQt 

3123 

3124 if not ImageQt.qt_is_installed: 

3125 msg = "Qt bindings are not installed" 

3126 raise ImportError(msg) 

3127 return ImageQt.toqimage(self) 

3128 

3129 def toqpixmap(self) -> ImageQt.QPixmap: 

3130 """Returns a QPixmap copy of this image""" 

3131 from . import ImageQt 

3132 

3133 if not ImageQt.qt_is_installed: 

3134 msg = "Qt bindings are not installed" 

3135 raise ImportError(msg) 

3136 return ImageQt.toqpixmap(self) 

3137 

3138 

3139# -------------------------------------------------------------------- 

3140# Abstract handlers. 

3141 

3142 

3143class ImagePointHandler(abc.ABC): 

3144 """ 

3145 Used as a mixin by point transforms 

3146 (for use with :py:meth:`~PIL.Image.Image.point`) 

3147 """ 

3148 

3149 @abc.abstractmethod 

3150 def point(self, im: Image) -> Image: 

3151 pass 

3152 

3153 

3154class ImageTransformHandler(abc.ABC): 

3155 """ 

3156 Used as a mixin by geometry transforms 

3157 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3158 """ 

3159 

3160 @abc.abstractmethod 

3161 def transform( 

3162 self, 

3163 size: tuple[int, int], 

3164 image: Image, 

3165 **options: Any, 

3166 ) -> Image: 

3167 pass 

3168 

3169 

3170# -------------------------------------------------------------------- 

3171# Factories 

3172 

3173 

3174def _check_size(size: Any) -> None: 

3175 """ 

3176 Common check to enforce type and sanity check on size tuples 

3177 

3178 :param size: Should be a 2 tuple of (width, height) 

3179 :returns: None, or raises a ValueError 

3180 """ 

3181 

3182 if not isinstance(size, (list, tuple)): 

3183 msg = "Size must be a list or tuple" 

3184 raise ValueError(msg) 

3185 if len(size) != 2: 

3186 msg = "Size must be a sequence of length 2" 

3187 raise ValueError(msg) 

3188 if size[0] < 0 or size[1] < 0: 

3189 msg = "Width and height must be >= 0" 

3190 raise ValueError(msg) 

3191 

3192 

3193def new( 

3194 mode: str, 

3195 size: tuple[int, int] | list[int], 

3196 color: float | tuple[float, ...] | str | None = 0, 

3197) -> Image: 

3198 """ 

3199 Creates a new image with the given mode and size. 

3200 

3201 :param mode: The mode to use for the new image. See: 

3202 :ref:`concept-modes`. 

3203 :param size: A 2-tuple, containing (width, height) in pixels. 

3204 :param color: What color to use for the image. Default is black. If given, 

3205 this should be a single integer or floating point value for single-band 

3206 modes, and a tuple for multi-band modes (one value per band). When 

3207 creating RGB or HSV images, you can also use color strings as supported 

3208 by the ImageColor module. See :ref:`colors` for more information. If the 

3209 color is None, the image is not initialised. 

3210 :returns: An :py:class:`~PIL.Image.Image` object. 

3211 """ 

3212 

3213 _check_size(size) 

3214 

3215 if color is None: 

3216 # don't initialize 

3217 return Image()._new(core.new(mode, size)) 

3218 

3219 if isinstance(color, str): 

3220 # css3-style specifier 

3221 

3222 from . import ImageColor 

3223 

3224 color = ImageColor.getcolor(color, mode) 

3225 

3226 im = Image() 

3227 if ( 

3228 mode == "P" 

3229 and isinstance(color, (list, tuple)) 

3230 and all(isinstance(i, int) for i in color) 

3231 ): 

3232 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3233 if len(color_ints) == 3 or len(color_ints) == 4: 

3234 # RGB or RGBA value for a P image 

3235 from . import ImagePalette 

3236 

3237 im.palette = ImagePalette.ImagePalette() 

3238 color = im.palette.getcolor(color_ints) 

3239 return im._new(core.fill(mode, size, color)) 

3240 

3241 

3242def frombytes( 

3243 mode: str, 

3244 size: tuple[int, int], 

3245 data: DecoderInput, 

3246 decoder_name: str = "raw", 

3247 *args: Any, 

3248) -> Image: 

3249 """ 

3250 Creates a copy of an image memory from pixel data in a buffer. 

3251 

3252 In its simplest form, this function takes three arguments 

3253 (mode, size, and unpacked pixel data). 

3254 

3255 You can also use any pixel decoder supported by PIL. For more 

3256 information on available decoders, see the section 

3257 :ref:`Writing Your Own File Codec <file-codecs>`. 

3258 

3259 Note that this function decodes pixel data only, not entire images. 

3260 If you have an entire image in a string, wrap it in a 

3261 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3262 it. 

3263 

3264 :param mode: The image mode. See: :ref:`concept-modes`. 

3265 :param size: The image size. 

3266 :param data: A byte buffer containing raw data for the given mode. 

3267 :param decoder_name: What decoder to use. 

3268 :param args: Additional parameters for the given decoder. 

3269 :returns: An :py:class:`~PIL.Image.Image` object. 

3270 """ 

3271 

3272 _check_size(size) 

3273 

3274 im = new(mode, size) 

3275 if im.width != 0 and im.height != 0: 

3276 decoder_args: Any = args 

3277 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3278 # may pass tuple instead of argument list 

3279 decoder_args = decoder_args[0] 

3280 

3281 if decoder_name == "raw" and decoder_args == (): 

3282 decoder_args = mode 

3283 

3284 im.frombytes(data, decoder_name, decoder_args) 

3285 return im 

3286 

3287 

3288def frombuffer( 

3289 mode: str, 

3290 size: tuple[int, int], 

3291 data: bytes | SupportsArrayInterface, 

3292 decoder_name: str = "raw", 

3293 *args: Any, 

3294) -> Image: 

3295 """ 

3296 Creates an image memory referencing pixel data in a byte buffer. 

3297 

3298 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3299 in the byte buffer, where possible. This means that changes to the 

3300 original buffer object are reflected in this image). Not all modes can 

3301 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3302 

3303 Note that this function decodes pixel data only, not entire images. 

3304 If you have an entire image file in a string, wrap it in a 

3305 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3306 

3307 The default parameters used for the "raw" decoder differs from that used for 

3308 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3309 future release. The current release issues a warning if you do this; to disable 

3310 the warning, you should provide the full set of parameters. See below for details. 

3311 

3312 :param mode: The image mode. See: :ref:`concept-modes`. 

3313 :param size: The image size. 

3314 :param data: A bytes or other buffer object containing raw 

3315 data for the given mode. 

3316 :param decoder_name: What decoder to use. 

3317 :param args: Additional parameters for the given decoder. For the 

3318 default encoder ("raw"), it's recommended that you provide the 

3319 full set of parameters:: 

3320 

3321 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3322 

3323 :returns: An :py:class:`~PIL.Image.Image` object. 

3324 

3325 .. versionadded:: 1.1.4 

3326 """ 

3327 

3328 _check_size(size) 

3329 

3330 # may pass tuple instead of argument list 

3331 if len(args) == 1 and isinstance(args[0], tuple): 

3332 args = args[0] 

3333 

3334 if decoder_name == "raw": 

3335 if args == (): 

3336 args = mode, 0, 1 

3337 if args[0] in _MAPMODES: 

3338 im = new(mode, (0, 0)) 

3339 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3340 if mode == "P": 

3341 from . import ImagePalette 

3342 

3343 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3344 im.readonly = 1 

3345 return im 

3346 

3347 return frombytes(mode, size, data, decoder_name, args) 

3348 

3349 

3350class SupportsArrayInterface(Protocol): 

3351 """ 

3352 An object that has an ``__array_interface__`` dictionary. 

3353 """ 

3354 

3355 @property 

3356 def __array_interface__(self) -> dict[str, Any]: 

3357 raise NotImplementedError() 

3358 

3359 def __len__(self) -> int: 

3360 raise NotImplementedError() 

3361 

3362 

3363DecoderInput = bytes | bytearray | memoryview | SupportsArrayInterface 

3364 

3365 

3366class SupportsArrowArrayInterface(Protocol): 

3367 """ 

3368 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3369 data interface. 

3370 """ 

3371 

3372 def __arrow_c_array__( 

3373 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3374 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3375 raise NotImplementedError() 

3376 

3377 

3378def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3379 """ 

3380 Creates an image memory from an object exporting the array interface 

3381 (using the buffer protocol):: 

3382 

3383 from PIL import Image 

3384 import numpy as np 

3385 a = np.zeros((5, 5)) 

3386 im = Image.fromarray(a) 

3387 

3388 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3389 and :py:func:`~PIL.Image.frombuffer` is used. 

3390 

3391 In the case of NumPy, be aware that Pillow modes do not always correspond 

3392 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3393 32-bit signed integer pixels, and 32-bit floating point pixels. 

3394 

3395 Pillow images can also be converted to arrays:: 

3396 

3397 from PIL import Image 

3398 import numpy as np 

3399 im = Image.open("hopper.jpg") 

3400 a = np.asarray(im) 

3401 

3402 When converting Pillow images to arrays however, only pixel values are 

3403 transferred. This means that P and PA mode images will lose their palette. 

3404 

3405 :param obj: Object with array interface 

3406 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not 

3407 contain information about palettes or color spaces, this can be used to place 

3408 grayscale L mode data within a P mode image, or read RGB data as YCbCr for 

3409 example. 

3410 

3411 See: :ref:`concept-modes` for general information about modes. 

3412 :returns: An image object. 

3413 

3414 .. versionadded:: 1.1.6 

3415 """ 

3416 arr = obj.__array_interface__ 

3417 shape = arr["shape"] 

3418 ndim = len(shape) 

3419 strides = arr.get("strides", None) 

3420 try: 

3421 typekey = (1, 1) + shape[2:], arr["typestr"] 

3422 except KeyError as e: 

3423 if mode is not None: 

3424 typekey = None 

3425 color_modes: list[str] = [] 

3426 else: 

3427 msg = "Cannot handle this data type" 

3428 raise TypeError(msg) from e 

3429 if typekey is not None: 

3430 try: 

3431 typemode, rawmode, color_modes = _fromarray_typemap[typekey] 

3432 except KeyError as e: 

3433 typekey_shape, typestr = typekey 

3434 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3435 raise TypeError(msg) from e 

3436 if mode is not None: 

3437 if mode != typemode and mode not in color_modes: 

3438 deprecate("'mode' parameter for changing data types", 13) 

3439 rawmode = mode 

3440 else: 

3441 mode = typemode 

3442 if mode in ["1", "L", "I", "P", "F"]: 

3443 ndmax = 2 

3444 elif mode == "RGB": 

3445 ndmax = 3 

3446 else: 

3447 ndmax = 4 

3448 if ndim > ndmax: 

3449 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3450 raise ValueError(msg) 

3451 

3452 size = 1 if ndim == 1 else shape[1], shape[0] 

3453 if strides is not None: 

3454 if hasattr(obj, "tobytes"): 

3455 obj = obj.tobytes() 

3456 elif hasattr(obj, "tostring"): 

3457 obj = obj.tostring() 

3458 else: 

3459 msg = "'strides' requires either tobytes() or tostring()" 

3460 raise ValueError(msg) 

3461 

3462 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3463 

3464 

3465def fromarrow( 

3466 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3467) -> Image: 

3468 """Creates an image with zero-copy shared memory from an object exporting 

3469 the arrow_c_array interface protocol:: 

3470 

3471 from PIL import Image 

3472 import pyarrow as pa 

3473 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3474 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3475 

3476 If the data representation of the ``obj`` is not compatible with 

3477 Pillow internal storage, a ValueError is raised. 

3478 

3479 Pillow images can also be converted to Arrow objects:: 

3480 

3481 from PIL import Image 

3482 import pyarrow as pa 

3483 im = Image.open('hopper.jpg') 

3484 arr = pa.array(im) 

3485 

3486 As with array support, when converting Pillow images to arrays, 

3487 only pixel values are transferred. This means that P and PA mode 

3488 images will lose their palette. 

3489 

3490 :param obj: Object with an arrow_c_array interface 

3491 :param mode: Image mode. 

3492 :param size: Image size. This must match the storage of the arrow object. 

3493 :returns: An Image object 

3494 

3495 Note that according to the Arrow spec, both the producer and the 

3496 consumer should consider the exported array to be immutable, as 

3497 unsynchronized updates will potentially cause inconsistent data. 

3498 

3499 See: :ref:`arrow-support` for more detailed information 

3500 

3501 .. versionadded:: 11.2.1 

3502 

3503 """ 

3504 if not hasattr(obj, "__arrow_c_array__"): 

3505 msg = "arrow_c_array interface not found" 

3506 raise ValueError(msg) 

3507 

3508 schema_capsule, array_capsule = obj.__arrow_c_array__() 

3509 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3510 if _im: 

3511 return Image()._new(_im) 

3512 

3513 msg = "new_arrow returned None without an exception" 

3514 raise ValueError(msg) 

3515 

3516 

3517def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3518 """Creates an image instance from a QImage image""" 

3519 from . import ImageQt 

3520 

3521 if not ImageQt.qt_is_installed: 

3522 msg = "Qt bindings are not installed" 

3523 raise ImportError(msg) 

3524 return ImageQt.fromqimage(im) 

3525 

3526 

3527def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3528 """Creates an image instance from a QPixmap image""" 

3529 from . import ImageQt 

3530 

3531 if not ImageQt.qt_is_installed: 

3532 msg = "Qt bindings are not installed" 

3533 raise ImportError(msg) 

3534 return ImageQt.fromqpixmap(im) 

3535 

3536 

3537_fromarray_typemap = { 

3538 # (shape, typestr) => mode, rawmode, color modes 

3539 # first two members of shape are set to one 

3540 ((1, 1), "|b1"): ("1", "1;8", []), 

3541 ((1, 1), "|u1"): ("L", "L", ["P"]), 

3542 ((1, 1), "|i1"): ("I", "I;8", []), 

3543 ((1, 1), "<u2"): ("I", "I;16", []), 

3544 ((1, 1), ">u2"): ("I", "I;16B", []), 

3545 ((1, 1), "<i2"): ("I", "I;16S", []), 

3546 ((1, 1), ">i2"): ("I", "I;16BS", []), 

3547 ((1, 1), "<u4"): ("I", "I;32", []), 

3548 ((1, 1), ">u4"): ("I", "I;32B", []), 

3549 ((1, 1), "<i4"): ("I", "I;32S", []), 

3550 ((1, 1), ">i4"): ("I", "I;32BS", []), 

3551 ((1, 1), "<f4"): ("F", "F;32F", []), 

3552 ((1, 1), ">f4"): ("F", "F;32BF", []), 

3553 ((1, 1), "<f8"): ("F", "F;64F", []), 

3554 ((1, 1), ">f8"): ("F", "F;64BF", []), 

3555 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]), 

3556 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), 

3557 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), 

3558 # shortcuts: 

3559 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []), 

3560 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []), 

3561} 

3562 

3563 

3564def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3565 if MAX_IMAGE_PIXELS is None: 

3566 return 

3567 

3568 pixels = max(1, size[0]) * max(1, size[1]) 

3569 

3570 if pixels > 2 * MAX_IMAGE_PIXELS: 

3571 msg = ( 

3572 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3573 "pixels, could be decompression bomb DOS attack." 

3574 ) 

3575 raise DecompressionBombError(msg) 

3576 

3577 if pixels > MAX_IMAGE_PIXELS: 

3578 warnings.warn( 

3579 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3580 "could be decompression bomb DOS attack.", 

3581 DecompressionBombWarning, 

3582 ) 

3583 

3584 

3585def open( 

3586 fp: StrOrBytesPath | IO[bytes], 

3587 mode: Literal["r"] = "r", 

3588 formats: list[str] | tuple[str, ...] | None = None, 

3589) -> ImageFile.ImageFile: 

3590 """ 

3591 Opens and identifies the given image file. 

3592 

3593 This is a lazy operation; this function identifies the file, but 

3594 the file remains open and the actual image data is not read from 

3595 the file until you try to process the data (or call the 

3596 :py:meth:`~PIL.Image.Image.load` method). See 

3597 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3598 

3599 :param fp: A filename (string), os.PathLike object or a file object. 

3600 The file object must implement ``file.read``, 

3601 ``file.seek``, and ``file.tell`` methods, 

3602 and be opened in binary mode. The file object will also seek to zero 

3603 before reading. 

3604 :param mode: The mode. If given, this argument must be "r". 

3605 :param formats: A list or tuple of formats to attempt to load the file in. 

3606 This can be used to restrict the set of formats checked. 

3607 Pass ``None`` to try all supported formats. You can print the set of 

3608 available formats by running ``python3 -m PIL`` or using 

3609 the :py:func:`PIL.features.pilinfo` function. 

3610 :returns: An :py:class:`~PIL.Image.Image` object. 

3611 :exception FileNotFoundError: If the file cannot be found. 

3612 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3613 identified. 

3614 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3615 instance is used for ``fp``. 

3616 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3617 """ 

3618 

3619 if mode != "r": 

3620 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3621 raise ValueError(msg) 

3622 elif isinstance(fp, io.StringIO): 

3623 msg = ( # type: ignore[unreachable] 

3624 "StringIO cannot be used to open an image. " 

3625 "Binary data must be used instead." 

3626 ) 

3627 raise ValueError(msg) 

3628 

3629 if formats is None: 

3630 formats = ID 

3631 elif not isinstance(formats, (list, tuple)): 

3632 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3633 raise TypeError(msg) 

3634 

3635 exclusive_fp = False 

3636 filename: str | bytes = "" 

3637 if is_path(fp): 

3638 filename = os.fspath(fp) 

3639 fp = builtins.open(filename, "rb") 

3640 exclusive_fp = True 

3641 else: 

3642 fp = cast(IO[bytes], fp) 

3643 

3644 try: 

3645 fp.seek(0) 

3646 except (AttributeError, io.UnsupportedOperation): 

3647 fp = io.BytesIO(fp.read()) 

3648 exclusive_fp = True 

3649 

3650 prefix = fp.read(16) 

3651 

3652 # Try to import just the plugin needed for this file extension 

3653 # before falling back to preinit() which imports common plugins 

3654 ext = os.path.splitext(filename)[1] if filename else "" 

3655 if not _import_plugin_for_extension(ext): 

3656 preinit() 

3657 

3658 warning_messages: list[str] = [] 

3659 

3660 def _open_core( 

3661 fp: IO[bytes], 

3662 filename: str | bytes, 

3663 prefix: bytes, 

3664 formats: list[str] | tuple[str, ...], 

3665 ) -> ImageFile.ImageFile | None: 

3666 for i in formats: 

3667 i = i.upper() 

3668 if i not in OPEN: 

3669 init() 

3670 try: 

3671 factory, accept = OPEN[i] 

3672 result = not accept or accept(prefix) 

3673 if isinstance(result, str): 

3674 warning_messages.append(result) 

3675 elif result: 

3676 fp.seek(0) 

3677 im = factory(fp, filename) 

3678 _decompression_bomb_check(im.size) 

3679 return im 

3680 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3681 if WARN_POSSIBLE_FORMATS: 

3682 warning_messages.append(i + " opening failed. " + str(e)) 

3683 except BaseException: 

3684 if exclusive_fp: 

3685 fp.close() 

3686 raise 

3687 return None 

3688 

3689 im = _open_core(fp, filename, prefix, formats) 

3690 

3691 if im is None and formats is ID: 

3692 # Try preinit (few common plugins) then init (all plugins) 

3693 for loader in (preinit, init): 

3694 checked_formats = ID.copy() 

3695 loader() 

3696 if formats != checked_formats: 

3697 im = _open_core( 

3698 fp, 

3699 filename, 

3700 prefix, 

3701 tuple(f for f in formats if f not in checked_formats), 

3702 ) 

3703 if im is not None: 

3704 break 

3705 

3706 if im: 

3707 im._exclusive_fp = exclusive_fp 

3708 return im 

3709 

3710 if exclusive_fp: 

3711 fp.close() 

3712 for message in warning_messages: 

3713 warnings.warn(message) 

3714 msg = "cannot identify image file %r" % (filename if filename else fp) 

3715 raise UnidentifiedImageError(msg) 

3716 

3717 

3718# 

3719# Image processing. 

3720 

3721 

3722def alpha_composite(im1: Image, im2: Image) -> Image: 

3723 """ 

3724 Alpha composite im2 over im1. 

3725 

3726 :param im1: The first image. Must have mode RGBA or LA. 

3727 :param im2: The second image. Must have the same mode and size as the first image. 

3728 :returns: An :py:class:`~PIL.Image.Image` object. 

3729 """ 

3730 

3731 im1.load() 

3732 im2.load() 

3733 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3734 

3735 

3736def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3737 """ 

3738 Creates a new image by interpolating between two input images, using 

3739 a constant alpha:: 

3740 

3741 out = image1 * (1.0 - alpha) + image2 * alpha 

3742 

3743 :param im1: The first image. 

3744 :param im2: The second image. Must have the same mode and size as 

3745 the first image. 

3746 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3747 copy of the first image is returned. If alpha is 1.0, a copy of 

3748 the second image is returned. There are no restrictions on the 

3749 alpha value. If necessary, the result is clipped to fit into 

3750 the allowed output range. 

3751 :returns: An :py:class:`~PIL.Image.Image` object. 

3752 """ 

3753 

3754 im1.load() 

3755 im2.load() 

3756 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3757 

3758 

3759def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3760 """ 

3761 Create composite image by blending images using a transparency mask. 

3762 

3763 :param image1: The first image. 

3764 :param image2: The second image. Must have the same mode and 

3765 size as the first image. 

3766 :param mask: A mask image. This image can have mode 

3767 "1", "L", or "RGBA", and must have the same size as the 

3768 other two images. 

3769 """ 

3770 

3771 image = image2.copy() 

3772 image.paste(image1, None, mask) 

3773 return image 

3774 

3775 

3776def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3777 """ 

3778 Applies the function (which should take one argument) to each pixel 

3779 in the given image. If the image has more than one band, the same 

3780 function is applied to each band. Note that the function is 

3781 evaluated once for each possible pixel value, so you cannot use 

3782 random components or other generators. 

3783 

3784 :param image: The input image. 

3785 :param function: A function object, taking one integer argument. 

3786 :returns: An :py:class:`~PIL.Image.Image` object. 

3787 """ 

3788 

3789 return image.point(args[0]) 

3790 

3791 

3792def merge(mode: str, bands: Sequence[Image]) -> Image: 

3793 """ 

3794 Merge a set of single band images into a new multiband image. 

3795 

3796 :param mode: The mode to use for the output image. See: 

3797 :ref:`concept-modes`. 

3798 :param bands: A sequence containing one single-band image for 

3799 each band in the output image. All bands must have the 

3800 same size. 

3801 :returns: An :py:class:`~PIL.Image.Image` object. 

3802 """ 

3803 

3804 if getmodebands(mode) != len(bands) or "*" in mode: 

3805 msg = "wrong number of bands" 

3806 raise ValueError(msg) 

3807 for band in bands[1:]: 

3808 if band.mode != getmodetype(mode): 

3809 msg = "mode mismatch" 

3810 raise ValueError(msg) 

3811 if band.size != bands[0].size: 

3812 msg = "size mismatch" 

3813 raise ValueError(msg) 

3814 for band in bands: 

3815 band.load() 

3816 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3817 

3818 

3819# -------------------------------------------------------------------- 

3820# Plugin registry 

3821 

3822 

3823def register_open( 

3824 id: str, 

3825 factory: ( 

3826 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3827 | type[ImageFile.ImageFile] 

3828 ), 

3829 accept: Callable[[bytes], bool | str] | None = None, 

3830) -> None: 

3831 """ 

3832 Register an image file plugin. This function should not be used 

3833 in application code. 

3834 

3835 :param id: An image format identifier. 

3836 :param factory: An image file factory method. 

3837 :param accept: An optional function that can be used to quickly 

3838 reject images having another format. 

3839 """ 

3840 id = id.upper() 

3841 if id not in ID: 

3842 ID.append(id) 

3843 OPEN[id] = factory, accept 

3844 

3845 

3846def register_mime(id: str, mimetype: str) -> None: 

3847 """ 

3848 Registers an image MIME type by populating ``Image.MIME``. This function 

3849 should not be used in application code. 

3850 

3851 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3852 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3853 provide a different result for specific images. 

3854 

3855 :param id: An image format identifier. 

3856 :param mimetype: The image MIME type for this format. 

3857 """ 

3858 MIME[id.upper()] = mimetype 

3859 

3860 

3861def register_save( 

3862 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3863) -> None: 

3864 """ 

3865 Registers an image save function. This function should not be 

3866 used in application code. 

3867 

3868 :param id: An image format identifier. 

3869 :param driver: A function to save images in this format. 

3870 """ 

3871 SAVE[id.upper()] = driver 

3872 

3873 

3874def register_save_all( 

3875 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3876) -> None: 

3877 """ 

3878 Registers an image function to save all the frames 

3879 of a multiframe format. This function should not be 

3880 used in application code. 

3881 

3882 :param id: An image format identifier. 

3883 :param driver: A function to save images in this format. 

3884 """ 

3885 SAVE_ALL[id.upper()] = driver 

3886 

3887 

3888def register_extension(id: str, extension: str) -> None: 

3889 """ 

3890 Registers an image extension. This function should not be 

3891 used in application code. 

3892 

3893 :param id: An image format identifier. 

3894 :param extension: An extension used for this format. 

3895 """ 

3896 EXTENSION[extension.lower()] = id.upper() 

3897 

3898 

3899def register_extensions(id: str, extensions: list[str]) -> None: 

3900 """ 

3901 Registers image extensions. This function should not be 

3902 used in application code. 

3903 

3904 :param id: An image format identifier. 

3905 :param extensions: A list of extensions used for this format. 

3906 """ 

3907 for extension in extensions: 

3908 register_extension(id, extension) 

3909 

3910 

3911def registered_extensions() -> dict[str, str]: 

3912 """ 

3913 Returns a dictionary containing all file extensions belonging 

3914 to registered plugins 

3915 """ 

3916 init() 

3917 return EXTENSION 

3918 

3919 

3920def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3921 """ 

3922 Registers an image decoder. This function should not be 

3923 used in application code. 

3924 

3925 :param name: The name of the decoder 

3926 :param decoder: An ImageFile.PyDecoder object 

3927 

3928 .. versionadded:: 4.1.0 

3929 """ 

3930 DECODERS[name] = decoder 

3931 

3932 

3933def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3934 """ 

3935 Registers an image encoder. This function should not be 

3936 used in application code. 

3937 

3938 :param name: The name of the encoder 

3939 :param encoder: An ImageFile.PyEncoder object 

3940 

3941 .. versionadded:: 4.1.0 

3942 """ 

3943 ENCODERS[name] = encoder 

3944 

3945 

3946# -------------------------------------------------------------------- 

3947# Simple display support. 

3948 

3949 

3950def _show(image: Image, **options: Any) -> None: 

3951 from . import ImageShow 

3952 

3953 deprecate("Image._show", 13, "ImageShow.show") 

3954 ImageShow.show(image, **options) 

3955 

3956 

3957# -------------------------------------------------------------------- 

3958# Effects 

3959 

3960 

3961def effect_mandelbrot( 

3962 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3963) -> Image: 

3964 """ 

3965 Generate a Mandelbrot set covering the given extent. 

3966 

3967 :param size: The requested size in pixels, as a 2-tuple: 

3968 (width, height). 

3969 :param extent: The extent to cover, as a 4-tuple: 

3970 (x0, y0, x1, y1). 

3971 :param quality: Quality. 

3972 """ 

3973 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3974 

3975 

3976def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3977 """ 

3978 Generate Gaussian noise centered around 128. 

3979 

3980 :param size: The requested size in pixels, as a 2-tuple: 

3981 (width, height). 

3982 :param sigma: Standard deviation of noise. 

3983 """ 

3984 return Image()._new(core.effect_noise(size, sigma)) 

3985 

3986 

3987def linear_gradient(mode: str) -> Image: 

3988 """ 

3989 Generate 256x256 linear gradient from black to white, top to bottom. 

3990 

3991 :param mode: Input mode. 

3992 """ 

3993 return Image()._new(core.linear_gradient(mode)) 

3994 

3995 

3996def radial_gradient(mode: str) -> Image: 

3997 """ 

3998 Generate 256x256 radial gradient from black to white, centre to edge. 

3999 

4000 :param mode: Input mode. 

4001 """ 

4002 return Image()._new(core.radial_gradient(mode)) 

4003 

4004 

4005# -------------------------------------------------------------------- 

4006# Resources 

4007 

4008 

4009def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

4010 env_dict = env if env is not None else os.environ 

4011 

4012 for var_name, setter in [ 

4013 ("PILLOW_ALIGNMENT", core.set_alignment), 

4014 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

4015 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

4016 ]: 

4017 if var_name not in env_dict: 

4018 continue 

4019 

4020 var = env_dict[var_name].lower() 

4021 

4022 units = 1 

4023 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

4024 if var.endswith(postfix): 

4025 units = mul 

4026 var = var[: -len(postfix)] 

4027 

4028 try: 

4029 var_int = int(var) * units 

4030 except ValueError: 

4031 warnings.warn(f"{var_name} is not int") 

4032 continue 

4033 

4034 try: 

4035 setter(var_int) 

4036 except ValueError as e: 

4037 warnings.warn(f"{var_name}: {e}") 

4038 

4039 

4040_apply_env_variables() 

4041atexit.register(core.clear_cache) 

4042 

4043 

4044if TYPE_CHECKING: 

4045 _ExifBase = MutableMapping[int, Any] 

4046else: 

4047 _ExifBase = MutableMapping 

4048 

4049 

4050class Exif(_ExifBase): 

4051 """ 

4052 This class provides read and write access to EXIF image data:: 

4053 

4054 from PIL import Image 

4055 im = Image.open("exif.png") 

4056 exif = im.getexif() # Returns an instance of this class 

4057 

4058 Information can be read and written, iterated over or deleted:: 

4059 

4060 print(exif[274]) # 1 

4061 exif[274] = 2 

4062 for k, v in exif.items(): 

4063 print("Tag", k, "Value", v) # Tag 274 Value 2 

4064 del exif[274] 

4065 

4066 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

4067 returns a dictionary:: 

4068 

4069 from PIL import ExifTags 

4070 im = Image.open("exif_gps.jpg") 

4071 exif = im.getexif() 

4072 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

4073 print(gps_ifd) 

4074 

4075 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

4076 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

4077 

4078 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

4079 

4080 print(exif[ExifTags.Base.Software]) # PIL 

4081 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

4082 """ 

4083 

4084 endian: str | None = None 

4085 bigtiff = False 

4086 _loaded = False 

4087 

4088 def __init__(self) -> None: 

4089 self._data: dict[int, Any] = {} 

4090 self._hidden_data: dict[int, Any] = {} 

4091 self._ifds: dict[int, dict[int, Any]] = {} 

4092 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

4093 self._loaded_exif: bytes | None = None 

4094 

4095 def _fixup(self, value: Any) -> Any: 

4096 try: 

4097 if len(value) == 1 and isinstance(value, tuple): 

4098 return value[0] 

4099 except Exception: 

4100 pass 

4101 return value 

4102 

4103 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

4104 # Helper function 

4105 # returns a dict with any single item tuples/lists as individual values 

4106 return {k: self._fixup(v) for k, v in src_dict.items()} 

4107 

4108 def _get_ifd_dict( 

4109 self, offset: int, group: int | None = None 

4110 ) -> dict[int, Any] | None: 

4111 try: 

4112 # an offset pointer to the location of the nested embedded IFD. 

4113 # It should be a long, but may be corrupted. 

4114 self.fp.seek(offset) 

4115 except (KeyError, TypeError): 

4116 return None 

4117 else: 

4118 from . import TiffImagePlugin 

4119 

4120 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

4121 info.load(self.fp) 

4122 return self._fixup_dict(dict(info)) 

4123 

4124 def _get_head(self) -> bytes: 

4125 version = b"\x2b" if self.bigtiff else b"\x2a" 

4126 if self.endian == "<": 

4127 head = b"II" + version + b"\x00" + o32le(8) 

4128 else: 

4129 head = b"MM\x00" + version + o32be(8) 

4130 if self.bigtiff: 

4131 head += o32le(8) if self.endian == "<" else o32be(8) 

4132 head += b"\x00\x00\x00\x00" 

4133 return head 

4134 

4135 def load(self, data: bytes) -> None: 

4136 # Extract EXIF information. This is highly experimental, 

4137 # and is likely to be replaced with something better in a future 

4138 # version. 

4139 

4140 # The EXIF record consists of a TIFF file embedded in a JPEG 

4141 # application marker (!). 

4142 if data == self._loaded_exif: 

4143 return 

4144 self._loaded_exif = data 

4145 self._data.clear() 

4146 self._hidden_data.clear() 

4147 self._ifds.clear() 

4148 while data and data.startswith(b"Exif\x00\x00"): 

4149 data = data[6:] 

4150 if not data: 

4151 self._info = None 

4152 return 

4153 

4154 self.fp: IO[bytes] = io.BytesIO(data) 

4155 self.head = self.fp.read(8) 

4156 # process dictionary 

4157 from . import TiffImagePlugin 

4158 

4159 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4160 self.endian = self._info._endian 

4161 self.fp.seek(self._info.next) 

4162 self._info.load(self.fp) 

4163 

4164 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4165 self._loaded_exif = None 

4166 self._data.clear() 

4167 self._hidden_data.clear() 

4168 self._ifds.clear() 

4169 

4170 # process dictionary 

4171 from . import TiffImagePlugin 

4172 

4173 self.fp = fp 

4174 if offset is not None: 

4175 self.head = self._get_head() 

4176 else: 

4177 self.head = self.fp.read(8) 

4178 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4179 if self.endian is None: 

4180 self.endian = self._info._endian 

4181 if offset is None: 

4182 offset = self._info.next 

4183 self.fp.tell() 

4184 self.fp.seek(offset) 

4185 self._info.load(self.fp) 

4186 

4187 def _get_merged_dict(self) -> dict[int, Any]: 

4188 merged_dict = dict(self) 

4189 

4190 # get EXIF extension 

4191 if ExifTags.IFD.Exif in self: 

4192 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4193 if ifd: 

4194 merged_dict.update(ifd) 

4195 

4196 # GPS 

4197 if ExifTags.IFD.GPSInfo in self: 

4198 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4199 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4200 ) 

4201 

4202 return merged_dict 

4203 

4204 def tobytes(self, offset: int = 8) -> bytes: 

4205 from . import TiffImagePlugin 

4206 

4207 head = self._get_head() 

4208 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4209 for tag, ifd_dict in self._ifds.items(): 

4210 if tag not in self: 

4211 ifd[tag] = ifd_dict 

4212 for tag, value in self.items(): 

4213 if tag in [ 

4214 ExifTags.IFD.Exif, 

4215 ExifTags.IFD.GPSInfo, 

4216 ] and not isinstance(value, dict): 

4217 value = self.get_ifd(tag) 

4218 if ( 

4219 tag == ExifTags.IFD.Exif 

4220 and ExifTags.IFD.Interop in value 

4221 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4222 ): 

4223 value = value.copy() 

4224 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4225 ifd[tag] = value 

4226 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4227 

4228 def get_ifd(self, tag: int) -> dict[int, Any]: 

4229 if tag not in self._ifds: 

4230 if tag == ExifTags.IFD.IFD1: 

4231 if self._info is not None and self._info.next != 0: 

4232 ifd = self._get_ifd_dict(self._info.next) 

4233 if ifd is not None: 

4234 self._ifds[tag] = ifd 

4235 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4236 offset = self._hidden_data.get(tag, self.get(tag)) 

4237 if offset is not None: 

4238 ifd = self._get_ifd_dict(offset, tag) 

4239 if ifd is not None: 

4240 self._ifds[tag] = ifd 

4241 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4242 if ExifTags.IFD.Exif not in self._ifds: 

4243 self.get_ifd(ExifTags.IFD.Exif) 

4244 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4245 if tag == ExifTags.IFD.MakerNote: 

4246 from .TiffImagePlugin import ImageFileDirectory_v2 

4247 

4248 try: 

4249 if tag_data.startswith(b"FUJIFILM"): 

4250 ifd_offset = i32le(tag_data, 8) 

4251 ifd_data = tag_data[ifd_offset:] 

4252 

4253 makernote = {} 

4254 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4255 ifd_tag, typ, count, data = struct.unpack( 

4256 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4257 ) 

4258 try: 

4259 ( 

4260 unit_size, 

4261 handler, 

4262 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4263 except KeyError: 

4264 continue 

4265 size = count * unit_size 

4266 if size > 4: 

4267 (offset,) = struct.unpack("<L", data) 

4268 data = ifd_data[offset - 12 : offset + size - 12] 

4269 else: 

4270 data = data[:size] 

4271 

4272 if len(data) != size: 

4273 warnings.warn( 

4274 "Possibly corrupt EXIF MakerNote data. " 

4275 f"Expecting to read {size} bytes but only got " 

4276 f"{len(data)}. Skipping tag {ifd_tag}" 

4277 ) 

4278 continue 

4279 

4280 if not data: 

4281 continue 

4282 

4283 makernote[ifd_tag] = handler( 

4284 ImageFileDirectory_v2(), data, False 

4285 ) 

4286 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4287 elif self.get(0x010F) == "Nintendo": 

4288 makernote = {} 

4289 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4290 ifd_tag, typ, count, data = struct.unpack( 

4291 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4292 ) 

4293 if ifd_tag == 0x1101: 

4294 # CameraInfo 

4295 (offset,) = struct.unpack(">L", data) 

4296 self.fp.seek(offset) 

4297 

4298 camerainfo: dict[str, int | bytes] = { 

4299 "ModelID": self.fp.read(4) 

4300 } 

4301 

4302 self.fp.read(4) 

4303 # Seconds since 2000 

4304 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4305 

4306 self.fp.read(4) 

4307 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4308 

4309 self.fp.read(12) 

4310 parallax = self.fp.read(4) 

4311 handler = ImageFileDirectory_v2._load_dispatch[ 

4312 TiffTags.FLOAT 

4313 ][1] 

4314 camerainfo["Parallax"] = handler( 

4315 ImageFileDirectory_v2(), parallax, False 

4316 )[0] 

4317 

4318 self.fp.read(4) 

4319 camerainfo["Category"] = self.fp.read(2) 

4320 

4321 makernote = {0x1101: camerainfo} 

4322 self._ifds[tag] = makernote 

4323 except struct.error: 

4324 pass 

4325 else: 

4326 # Interop 

4327 ifd = self._get_ifd_dict(tag_data, tag) 

4328 if ifd is not None: 

4329 self._ifds[tag] = ifd 

4330 ifd = self._ifds.setdefault(tag, {}) 

4331 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4332 ifd = { 

4333 k: v 

4334 for (k, v) in ifd.items() 

4335 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4336 } 

4337 return ifd 

4338 

4339 def hide_offsets(self) -> None: 

4340 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4341 if tag in self: 

4342 self._hidden_data[tag] = self[tag] 

4343 del self[tag] 

4344 

4345 def __str__(self) -> str: 

4346 if self._info is not None: 

4347 # Load all keys into self._data 

4348 for tag in self._info: 

4349 self[tag] 

4350 

4351 return str(self._data) 

4352 

4353 def __len__(self) -> int: 

4354 keys = set(self._data) 

4355 if self._info is not None: 

4356 keys.update(self._info) 

4357 return len(keys) 

4358 

4359 def __getitem__(self, tag: int) -> Any: 

4360 if self._info is not None and tag not in self._data and tag in self._info: 

4361 self._data[tag] = self._fixup(self._info[tag]) 

4362 del self._info[tag] 

4363 return self._data[tag] 

4364 

4365 def __contains__(self, tag: object) -> bool: 

4366 return tag in self._data or (self._info is not None and tag in self._info) 

4367 

4368 def __setitem__(self, tag: int, value: Any) -> None: 

4369 if self._info is not None and tag in self._info: 

4370 del self._info[tag] 

4371 self._data[tag] = value 

4372 

4373 def __delitem__(self, tag: int) -> None: 

4374 if self._info is not None and tag in self._info: 

4375 del self._info[tag] 

4376 else: 

4377 del self._data[tag] 

4378 if tag in self._ifds: 

4379 del self._ifds[tag] 

4380 

4381 def __iter__(self) -> Iterator[int]: 

4382 keys = set(self._data) 

4383 if self._info is not None: 

4384 keys.update(self._info) 

4385 return iter(keys)