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

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

1758 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 

29__lazy_modules__ = { 

30 "PIL._binary", 

31 "PIL._deprecate", 

32 "PIL._util", 

33 "io", 

34 "math", 

35 "re", 

36 "struct", 

37} 

38 

39import abc 

40import atexit 

41import builtins 

42import io 

43import math 

44import os 

45import re 

46import struct 

47import sys 

48import warnings 

49from collections.abc import MutableMapping 

50from enum import IntEnum 

51from typing import IO, Protocol, cast 

52 

53# VERSION was removed in Pillow 6.0.0. 

54# PILLOW_VERSION was removed in Pillow 9.0.0. 

55# Use __version__ instead. 

56from . import ( 

57 ExifTags, 

58 ImageMode, 

59 TiffTags, 

60 UnidentifiedImageError, 

61 __version__, 

62 _plugins, 

63) 

64from ._binary import i32le, o32be, o32le 

65from ._deprecate import deprecate 

66from ._util import DeferredError, is_path 

67 

68TYPE_CHECKING = False 

69if TYPE_CHECKING: 

70 from collections.abc import Callable, Iterator, Sequence 

71 from typing import Any, Literal, Self 

72 

73 

74class DecompressionBombWarning(RuntimeWarning): 

75 pass 

76 

77 

78class DecompressionBombError(Exception): 

79 pass 

80 

81 

82WARN_POSSIBLE_FORMATS: bool = False 

83 

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

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

86 

87 

88try: 

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

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

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

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

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

94 from . import _imaging as core 

95 

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

97 msg = ( 

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

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

100 f"Pillow version: {__version__}" 

101 ) 

102 raise ImportError(msg) 

103 

104except ImportError as v: 

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

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

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

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

109 # possible. 

110 warnings.warn( 

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

112 RuntimeWarning, 

113 ) 

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

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

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

117 # see docs/porting.rst 

118 raise 

119 

120 

121# 

122# Constants 

123 

124 

125# transpose 

126class Transpose(IntEnum): 

127 FLIP_LEFT_RIGHT = 0 

128 FLIP_TOP_BOTTOM = 1 

129 ROTATE_90 = 2 

130 ROTATE_180 = 3 

131 ROTATE_270 = 4 

132 TRANSPOSE = 5 

133 TRANSVERSE = 6 

134 

135 

136# transforms (also defined in Imaging.h) 

137class Transform(IntEnum): 

138 AFFINE = 0 

139 EXTENT = 1 

140 PERSPECTIVE = 2 

141 QUAD = 3 

142 MESH = 4 

143 

144 

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

146class Resampling(IntEnum): 

147 NEAREST = 0 

148 BOX = 4 

149 BILINEAR = 2 

150 HAMMING = 5 

151 BICUBIC = 3 

152 LANCZOS = 1 

153 MKS2013 = 6 

154 MKS2021 = 7 

155 

156 

157_filters_support = { 

158 Resampling.BOX: 0.5, 

159 Resampling.BILINEAR: 1.0, 

160 Resampling.HAMMING: 1.0, 

161 Resampling.BICUBIC: 2.0, 

162 Resampling.LANCZOS: 3.0, 

163 Resampling.MKS2013: 2.5, 

164 Resampling.MKS2021: 4.5, 

165} 

166 

167 

168# dithers 

169class Dither(IntEnum): 

170 NONE = 0 

171 ORDERED = 1 # Not yet implemented 

172 RASTERIZE = 2 # Not yet implemented 

173 FLOYDSTEINBERG = 3 # default 

174 

175 

176# palettes/quantizers 

177class Palette(IntEnum): 

178 WEB = 0 

179 ADAPTIVE = 1 

180 

181 

182class Quantize(IntEnum): 

183 MEDIANCUT = 0 

184 MAXCOVERAGE = 1 

185 FASTOCTREE = 2 

186 LIBIMAGEQUANT = 3 

187 

188 

189module = sys.modules[__name__] 

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

191 for item in enum: 

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

193 

194 

195if hasattr(core, "DEFAULT_STRATEGY"): 

196 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

197 FILTERED = core.FILTERED 

198 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

199 RLE = core.RLE 

200 FIXED = core.FIXED 

201 

202 

203# -------------------------------------------------------------------- 

204# Registries 

205 

206TYPE_CHECKING = False 

207if TYPE_CHECKING: 

208 import mmap 

209 from xml.etree.ElementTree import Element 

210 

211 from IPython.lib.pretty import PrettyPrinter 

212 

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

214 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath 

215ID: list[str] = [] 

216OPEN: dict[ 

217 str, 

218 tuple[ 

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

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

221 ], 

222] = {} 

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

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

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

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

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

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

229 

230# -------------------------------------------------------------------- 

231# Modes 

232 

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

234 

235 

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

237 m = ImageMode.getmode(im.mode) 

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

239 extra = len(m.bands) 

240 if extra != 1: 

241 shape += (extra,) 

242 return shape, m.typestr 

243 

244 

245MODES = [ 

246 "1", 

247 "CMYK", 

248 "F", 

249 "HSV", 

250 "I", 

251 "I;16", 

252 "I;16B", 

253 "I;16L", 

254 "I;16N", 

255 "L", 

256 "LA", 

257 "La", 

258 "LAB", 

259 "P", 

260 "PA", 

261 "RGB", 

262 "RGBA", 

263 "RGBa", 

264 "RGBX", 

265 "YCbCr", 

266] 

267 

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

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

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

271 

272 

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

274 """ 

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

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

277 contain color data. 

278 

279 :param mode: Input mode. 

280 :returns: "L" or "RGB". 

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

282 """ 

283 return ImageMode.getmode(mode).basemode 

284 

285 

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

287 """ 

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

289 single-layer mode suitable for storing individual bands. 

290 

291 :param mode: Input mode. 

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

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

294 """ 

295 return ImageMode.getmode(mode).basetype 

296 

297 

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

299 """ 

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

301 a tuple containing the names of individual bands (use 

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

303 individual band. 

304 

305 :param mode: Input mode. 

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

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

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

309 """ 

310 return ImageMode.getmode(mode).bands 

311 

312 

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

314 """ 

315 Gets the number of individual bands for this mode. 

316 

317 :param mode: Input mode. 

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

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

320 """ 

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

322 

323 

324# -------------------------------------------------------------------- 

325# Helpers 

326 

327_initialized = 0 

328 

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

330_EXTENSION_PLUGIN: dict[str, str] = { 

331 # Common formats (preinit) 

332 ".bmp": "BmpImagePlugin", 

333 ".dib": "BmpImagePlugin", 

334 ".gif": "GifImagePlugin", 

335 ".jfif": "JpegImagePlugin", 

336 ".jpe": "JpegImagePlugin", 

337 ".jpg": "JpegImagePlugin", 

338 ".jpeg": "JpegImagePlugin", 

339 ".pbm": "PpmImagePlugin", 

340 ".pgm": "PpmImagePlugin", 

341 ".pnm": "PpmImagePlugin", 

342 ".ppm": "PpmImagePlugin", 

343 ".pfm": "PpmImagePlugin", 

344 ".png": "PngImagePlugin", 

345 ".apng": "PngImagePlugin", 

346 # Less common formats (init) 

347 ".avif": "AvifImagePlugin", 

348 ".avifs": "AvifImagePlugin", 

349 ".blp": "BlpImagePlugin", 

350 ".bufr": "BufrStubImagePlugin", 

351 ".cur": "CurImagePlugin", 

352 ".dcx": "DcxImagePlugin", 

353 ".dds": "DdsImagePlugin", 

354 ".ps": "EpsImagePlugin", 

355 ".eps": "EpsImagePlugin", 

356 ".fit": "FitsImagePlugin", 

357 ".fits": "FitsImagePlugin", 

358 ".fli": "FliImagePlugin", 

359 ".flc": "FliImagePlugin", 

360 ".fpx": "FpxImagePlugin", 

361 ".ftc": "FtexImagePlugin", 

362 ".ftu": "FtexImagePlugin", 

363 ".gbr": "GbrImagePlugin", 

364 ".grib": "GribStubImagePlugin", 

365 ".h5": "Hdf5StubImagePlugin", 

366 ".hdf": "Hdf5StubImagePlugin", 

367 ".icns": "IcnsImagePlugin", 

368 ".ico": "IcoImagePlugin", 

369 ".im": "ImImagePlugin", 

370 ".iim": "IptcImagePlugin", 

371 ".jp2": "Jpeg2KImagePlugin", 

372 ".j2k": "Jpeg2KImagePlugin", 

373 ".jpc": "Jpeg2KImagePlugin", 

374 ".jpf": "Jpeg2KImagePlugin", 

375 ".jpx": "Jpeg2KImagePlugin", 

376 ".j2c": "Jpeg2KImagePlugin", 

377 ".mic": "MicImagePlugin", 

378 ".mpg": "MpegImagePlugin", 

379 ".mpeg": "MpegImagePlugin", 

380 ".mpo": "MpoImagePlugin", 

381 ".msp": "MspImagePlugin", 

382 ".palm": "PalmImagePlugin", 

383 ".pcd": "PcdImagePlugin", 

384 ".pcx": "PcxImagePlugin", 

385 ".pdf": "PdfImagePlugin", 

386 ".pxr": "PixarImagePlugin", 

387 ".psd": "PsdImagePlugin", 

388 ".qoi": "QoiImagePlugin", 

389 ".bw": "SgiImagePlugin", 

390 ".rgb": "SgiImagePlugin", 

391 ".rgba": "SgiImagePlugin", 

392 ".sgi": "SgiImagePlugin", 

393 ".ras": "SunImagePlugin", 

394 ".tga": "TgaImagePlugin", 

395 ".icb": "TgaImagePlugin", 

396 ".vda": "TgaImagePlugin", 

397 ".vst": "TgaImagePlugin", 

398 ".tif": "TiffImagePlugin", 

399 ".tiff": "TiffImagePlugin", 

400 ".webp": "WebPImagePlugin", 

401 ".wmf": "WmfImagePlugin", 

402 ".emf": "WmfImagePlugin", 

403 ".xbm": "XbmImagePlugin", 

404 ".xpm": "XpmImagePlugin", 

405} 

406 

407 

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

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

410 if not ext: 

411 return False 

412 

413 if isinstance(ext, bytes): 

414 ext = ext.decode() 

415 ext = ext.lower() 

416 if ext in EXTENSION: 

417 return True 

418 

419 plugin = _EXTENSION_PLUGIN.get(ext) 

420 if plugin is None: 

421 return False 

422 

423 try: 

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

425 return True 

426 except ImportError: 

427 return False 

428 

429 

430def preinit() -> None: 

431 """ 

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

433 

434 It is called when opening or saving images. 

435 """ 

436 

437 global _initialized 

438 if _initialized >= 1: 

439 return 

440 

441 try: 

442 from . import BmpImagePlugin 

443 

444 assert BmpImagePlugin 

445 except ImportError: 

446 pass 

447 try: 

448 from . import GifImagePlugin 

449 

450 assert GifImagePlugin 

451 except ImportError: 

452 pass 

453 try: 

454 from . import JpegImagePlugin 

455 

456 assert JpegImagePlugin 

457 except ImportError: 

458 pass 

459 try: 

460 from . import PpmImagePlugin 

461 

462 assert PpmImagePlugin 

463 except ImportError: 

464 pass 

465 try: 

466 from . import PngImagePlugin 

467 

468 assert PngImagePlugin 

469 except ImportError: 

470 pass 

471 

472 _initialized = 1 

473 

474 

475def init() -> bool: 

476 """ 

477 Explicitly initializes the Python Imaging Library. This function 

478 loads all available file format drivers. 

479 

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

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

482 """ 

483 

484 global _initialized 

485 if _initialized >= 2: 

486 return False 

487 

488 for plugin in _plugins: 

489 try: 

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

491 except ImportError: 

492 pass 

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 _copy_info(self) -> dict[str | tuple[int, int], Any]: 

679 return {k: v.copy() if isinstance(v, list) else v for k, v in self.info.items()} 

680 

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

682 new = Image() 

683 new.im = im 

684 new._mode = im.mode 

685 new._size = im.size 

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

687 if self.palette: 

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

689 else: 

690 from . import ImagePalette 

691 

692 new.palette = ImagePalette.ImagePalette() 

693 new.info = self._copy_info() 

694 return new 

695 

696 # Context manager support 

697 def __enter__(self) -> Self: 

698 return self 

699 

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

701 pass 

702 

703 def close(self) -> None: 

704 """ 

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

706 The image data will be unusable afterward. 

707 

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

709 have not had their file read and closed by the 

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

711 more information. 

712 """ 

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

714 if sys.platform == "win32" and sys.implementation.name == "pypy": 

715 self.map.close() 

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

717 

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

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

720 # object is gone. 

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

722 

723 def _copy(self) -> None: 

724 self.load() 

725 self.im = self.im.copy() 

726 self.readonly = 0 

727 

728 def _ensure_mutable(self) -> None: 

729 if self.readonly: 

730 self._copy() 

731 else: 

732 self.load() 

733 

734 def _dump( 

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

736 ) -> str: 

737 suffix = f".{format}" if format else "" 

738 

739 if file: 

740 filename = file 

741 if not filename.endswith(suffix): 

742 filename += suffix 

743 else: 

744 import tempfile 

745 

746 f, filename = tempfile.mkstemp(suffix) 

747 os.close(f) 

748 

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

750 

751 return filename 

752 

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

754 if self.__class__ is not other.__class__: 

755 return False 

756 assert isinstance(other, Image) 

757 return ( 

758 self.mode == other.mode 

759 and self.size == other.size 

760 and self.info == other.info 

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

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

763 ) 

764 

765 def __repr__(self) -> str: 

766 return ( 

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

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

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

770 ) 

771 

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

773 """IPython plain text display support""" 

774 

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

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

777 p.text( 

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

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

780 ) 

781 

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

783 """Helper function for iPython display hook. 

784 

785 :param image_format: Image format. 

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

787 """ 

788 b = io.BytesIO() 

789 try: 

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

791 except Exception: 

792 return None 

793 return b.getvalue() 

794 

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

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

797 

798 :returns: PNG version of the image as bytes 

799 """ 

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

801 

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

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

804 

805 :returns: JPEG version of the image as bytes 

806 """ 

807 return self._repr_image("JPEG") 

808 

809 @property 

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

811 # numpy array interface support 

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

813 if self.mode == "1": 

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

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

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

817 else: 

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

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

820 return new 

821 

822 def __arrow_c_schema__(self) -> object: 

823 self.load() 

824 return self.im.__arrow_c_schema__() 

825 

826 def __arrow_c_array__( 

827 self, requested_schema: object | None = None 

828 ) -> tuple[object, object]: 

829 self.load() 

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

831 

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

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

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

835 

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

837 Image.__init__(self) 

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

839 self.info = info 

840 self._mode = mode 

841 self._size = size 

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

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

844 self.putpalette(palette) 

845 self.frombytes(data) 

846 

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

848 """ 

849 Return image as a bytes object. 

850 

851 .. warning:: 

852 

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

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

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

856 

857 :param encoder_name: What encoder to use. 

858 

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

860 To see how this packs pixel data into the returned 

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

862 

863 A list of C encoders can be seen under codecs 

864 section of the function array in 

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

866 within the relevant plugins. 

867 :param args: Extra arguments to the encoder. 

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

869 """ 

870 

871 encoder_args: Any = args 

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

873 # may pass tuple instead of argument list 

874 encoder_args = encoder_args[0] 

875 

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

877 encoder_args = self.mode 

878 

879 self.load() 

880 

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

882 return b"" 

883 

884 # unpack data 

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

886 e.setimage(self.im, (0, 0, *self.size)) 

887 

888 from . import ImageFile 

889 

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

891 

892 output = [] 

893 while True: 

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

895 output.append(data) 

896 if errcode: 

897 break 

898 if errcode < 0: 

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

900 raise RuntimeError(msg) 

901 

902 return b"".join(output) 

903 

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

905 """ 

906 Returns the image converted to an X11 bitmap. 

907 

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

909 

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

911 :returns: A string containing an X11 bitmap. 

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

913 """ 

914 

915 self.load() 

916 if self.mode != "1": 

917 msg = "not a bitmap" 

918 raise ValueError(msg) 

919 data = self.tobytes("xbm") 

920 return b"".join( 

921 [ 

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

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

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

925 data, 

926 b"};", 

927 ] 

928 ) 

929 

930 def frombytes( 

931 self, 

932 data: DecoderInput, 

933 decoder_name: str = "raw", 

934 *args: Any, 

935 ) -> None: 

936 """ 

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

938 

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

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

941 """ 

942 

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

944 return 

945 

946 decoder_args: Any = args 

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

948 # may pass tuple instead of argument list 

949 decoder_args = decoder_args[0] 

950 

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

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

953 if len(data) % multiple: 

954 msg = "not enough image data" 

955 raise ValueError(msg) 

956 

957 # default format 

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

959 decoder_args = self.mode 

960 

961 # unpack data 

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

963 d.setimage(self.im, (0, 0, *self.size)) 

964 s = d.decode(data) 

965 

966 if s[0] >= 0: 

967 msg = "not enough image data" 

968 raise ValueError(msg) 

969 if s[1] != 0: 

970 msg = "cannot decode image data" 

971 raise ValueError(msg) 

972 

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

974 """ 

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

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

977 Image class automatically loads an opened image when it is 

978 accessed for the first time. 

979 

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

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

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

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

984 

985 :returns: An image access object. 

986 """ 

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

988 # realize palette 

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

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

991 self.palette.dirty = 0 

992 self.palette.rawmode = None 

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

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

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

996 else: 

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

998 self.palette.mode = "RGBA" 

999 elif self.palette.mode != mode: 

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

1001 # then update the Python palette data 

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

1003 

1004 if self._im is not None: 

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

1006 return None 

1007 

1008 def verify(self) -> None: 

1009 """ 

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

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

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

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

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

1015 file. 

1016 """ 

1017 pass 

1018 

1019 def convert( 

1020 self, 

1021 mode: str | None = None, 

1022 matrix: list[float] | tuple[float, ...] | None = None, 

1023 dither: Dither | None = None, 

1024 palette: Palette = Palette.WEB, 

1025 colors: int = 256, 

1026 ) -> Image: 

1027 """ 

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

1029 method translates pixels through the palette. If mode is 

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

1031 and the palette can be represented without a palette. 

1032 

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

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

1035 

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

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

1038 

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

1040 

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

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

1043 dither to approximate the original image luminosity levels. If 

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

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

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

1047 

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

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

1050 and ``dither`` and ``palette`` are ignored. 

1051 

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

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

1054 

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

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

1057 should be 4- or 12-sequence containing floating point values. 

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

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

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

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

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

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

1064 :data:`Palette.ADAPTIVE`. 

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

1066 palette. Defaults to 256. 

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

1068 """ 

1069 

1070 self.load() 

1071 

1072 has_transparency = "transparency" in self.info 

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

1074 # determine default mode 

1075 if self.palette: 

1076 mode = self.palette.mode 

1077 else: 

1078 mode = "RGB" 

1079 if mode == "RGB" and has_transparency: 

1080 mode = "RGBA" 

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

1082 return self.copy() 

1083 

1084 if matrix: 

1085 # matrix conversion 

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

1087 msg = "illegal conversion" 

1088 raise ValueError(msg) 

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

1090 new_im = self._new(im) 

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

1092 transparency = new_im.info["transparency"] 

1093 

1094 def convert_transparency( 

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

1096 ) -> int: 

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

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

1099 

1100 if mode == "L": 

1101 transparency = convert_transparency(matrix, transparency) 

1102 elif len(mode) == 3: 

1103 transparency = tuple( 

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

1105 for i in range(len(transparency)) 

1106 ) 

1107 new_im.info["transparency"] = transparency 

1108 return new_im 

1109 

1110 if self.mode == "RGBA": 

1111 if mode == "P": 

1112 return self.quantize(colors) 

1113 elif mode == "PA": 

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

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

1116 p = rgb.quantize(colors) 

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

1118 

1119 trns = None 

1120 delete_trns = False 

1121 # transparency handling 

1122 if has_transparency: 

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

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

1125 ): 

1126 # Use transparent conversion to promote from transparent 

1127 # color to an alpha channel. 

1128 new_im = self._new( 

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

1130 ) 

1131 del new_im.info["transparency"] 

1132 return new_im 

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

1134 t = self.info["transparency"] 

1135 if isinstance(t, bytes): 

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

1137 warnings.warn( 

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

1139 "converted to RGBA images" 

1140 ) 

1141 delete_trns = True 

1142 else: 

1143 # get the new transparency color. 

1144 # use existing conversions 

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

1146 if self.mode == "P": 

1147 assert self.palette is not None 

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

1149 if isinstance(t, tuple): 

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

1151 assert trns_im.palette is not None 

1152 try: 

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

1154 except ValueError as e: 

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

1156 # If all 256 colors are in use, 

1157 # then there is no need for transparency 

1158 t = None 

1159 else: 

1160 raise ValueError(err) from e 

1161 if t is None: 

1162 trns = None 

1163 else: 

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

1165 

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

1167 trns_im = trns_im.convert(mode) 

1168 else: 

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

1170 # after quantization. 

1171 trns_im = trns_im.convert("RGB") 

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

1173 

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

1175 t = self.info["transparency"] 

1176 delete_trns = True 

1177 

1178 if isinstance(t, bytes): 

1179 self.im.putpalettealphas(t) 

1180 elif isinstance(t, int): 

1181 self.im.putpalettealpha(t, 0) 

1182 else: 

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

1184 raise ValueError(msg) 

1185 

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

1187 im = self.im.quantize(colors) 

1188 new_im = self._new(im) 

1189 from . import ImagePalette 

1190 

1191 new_im.palette = ImagePalette.ImagePalette( 

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

1193 ) 

1194 if delete_trns: 

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

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

1197 del new_im.info["transparency"] 

1198 if trns is not None: 

1199 try: 

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

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

1202 new_im, 

1203 ) 

1204 except Exception: 

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

1206 # transparency hanging around to mess us up. 

1207 del new_im.info["transparency"] 

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

1209 return new_im 

1210 

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

1212 im = self 

1213 if mode == "LAB": 

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

1215 im = im.convert("RGBA") 

1216 other_mode = im.mode 

1217 else: 

1218 other_mode = mode 

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

1220 from . import ImageCms 

1221 

1222 srgb = ImageCms.createProfile("sRGB") 

1223 lab = ImageCms.createProfile("LAB") 

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

1225 transform = ImageCms.buildTransform( 

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

1227 ) 

1228 return transform.apply(im) 

1229 

1230 # colorspace conversion 

1231 if dither is None: 

1232 dither = Dither.FLOYDSTEINBERG 

1233 

1234 try: 

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

1236 except ValueError: 

1237 try: 

1238 # normalize source image and try again 

1239 modebase = getmodebase(self.mode) 

1240 if modebase == self.mode: 

1241 raise 

1242 im = self.im.convert(modebase) 

1243 im = im.convert(mode, dither) 

1244 except KeyError as e: 

1245 msg = "illegal conversion" 

1246 raise ValueError(msg) from e 

1247 

1248 new_im = self._new(im) 

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

1250 from . import ImagePalette 

1251 

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

1253 if delete_trns: 

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

1255 del new_im.info["transparency"] 

1256 if trns is not None: 

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

1258 try: 

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

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

1261 new_im, 

1262 ) 

1263 except ValueError as e: 

1264 del new_im.info["transparency"] 

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

1266 # If all 256 colors are in use, 

1267 # then there is no need for transparency 

1268 warnings.warn( 

1269 "Couldn't allocate palette entry for transparency" 

1270 ) 

1271 else: 

1272 new_im.info["transparency"] = trns 

1273 return new_im 

1274 

1275 def quantize( 

1276 self, 

1277 colors: int = 256, 

1278 method: int | None = None, 

1279 kmeans: int = 0, 

1280 palette: Image | None = None, 

1281 dither: Dither = Dither.FLOYDSTEINBERG, 

1282 ) -> Image: 

1283 """ 

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

1285 of colors. 

1286 

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

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

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

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

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

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

1293 ``feature="libimagequant"``). 

1294 

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

1296 

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

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

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

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

1301 :param palette: Quantize to the palette of given 

1302 :py:class:`PIL.Image.Image`. 

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

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

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

1306 (default). 

1307 :returns: A new image 

1308 """ 

1309 

1310 self.load() 

1311 

1312 if method is None: 

1313 # defaults: 

1314 method = Quantize.MEDIANCUT 

1315 if self.mode == "RGBA": 

1316 method = Quantize.FASTOCTREE 

1317 

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

1319 Quantize.FASTOCTREE, 

1320 Quantize.LIBIMAGEQUANT, 

1321 ): 

1322 # Caller specified an invalid mode. 

1323 msg = ( 

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

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

1326 ) 

1327 raise ValueError(msg) 

1328 

1329 if palette: 

1330 # use palette from reference image 

1331 palette.load() 

1332 if palette.mode != "P": 

1333 msg = "bad mode for palette image" 

1334 raise ValueError(msg) 

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

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

1337 raise ValueError(msg) 

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

1339 new_im = self._new(im) 

1340 assert palette.palette is not None 

1341 new_im.palette = palette.palette.copy() 

1342 return new_im 

1343 

1344 if kmeans < 0: 

1345 msg = "kmeans must not be negative" 

1346 raise ValueError(msg) 

1347 

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

1349 

1350 from . import ImagePalette 

1351 

1352 mode = im.im.getpalettemode() 

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

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

1355 

1356 return im 

1357 

1358 def copy(self) -> Image: 

1359 """ 

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

1361 into an image, but still retain the original. 

1362 

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

1364 """ 

1365 self.load() 

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

1367 

1368 __copy__ = copy 

1369 

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

1371 """ 

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

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

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

1375 

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

1377 

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

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

1380 """ 

1381 

1382 if box is None or box == (0, 0, *self.size): 

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 """ 

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

1477 

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

1479 """ 

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

1481 image. 

1482 

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

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

1485 Otherwise, trim pixels when all channels are zero. 

1486 Keyword-only argument. 

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

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

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

1490 method returns None. 

1491 

1492 """ 

1493 

1494 self.load() 

1495 return self.im.getbbox(alpha_only) 

1496 

1497 def getcolors( 

1498 self, maxcolors: int = 256 

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

1500 """ 

1501 Returns a list of colors used in this image. 

1502 

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

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

1505 return the index of the color in the palette. 

1506 

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

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

1509 256 colors. 

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

1511 """ 

1512 

1513 self.load() 

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

1515 h = self.im.histogram() 

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

1517 if len(out) > maxcolors: 

1518 return None 

1519 return out 

1520 return self.im.getcolors(maxcolors) 

1521 

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

1523 """ 

1524 Returns the contents of this image as a sequence object 

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

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

1527 line zero, and so on. 

1528 

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

1530 internal PIL data type, which only supports certain sequence 

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

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

1533 

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

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

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

1537 :returns: A sequence-like object. 

1538 """ 

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

1540 

1541 self.load() 

1542 if band is not None: 

1543 return self.im.getband(band) 

1544 return self.im # could be abused 

1545 

1546 def get_flattened_data( 

1547 self, band: int | None = None 

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

1549 """ 

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

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

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

1553 

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

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

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

1557 :returns: A tuple containing pixel values. 

1558 """ 

1559 self.load() 

1560 if band is not None: 

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

1562 return tuple(self.im) 

1563 

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

1565 """ 

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

1567 the image. 

1568 

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

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

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

1572 """ 

1573 

1574 self.load() 

1575 if self.im.bands > 1: 

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

1577 return self.im.getextrema() 

1578 

1579 def getxmp(self, *, strip_namespaces: bool = True) -> dict[str, Any]: 

1580 """ 

1581 Returns a dictionary containing the XMP tags. 

1582 Requires defusedxml to be installed. 

1583 

1584 :param strip_namespaces: If ``False``, keep each tag's full 

1585 ``{namespace-uri}local-name`` form instead of stripping the namespace 

1586 prefix. 

1587 

1588 .. versionadded:: 13.0.0 

1589 

1590 :returns: XMP tags in a dictionary. 

1591 """ 

1592 try: 

1593 from defusedxml import ElementTree 

1594 except ImportError: 

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

1596 return {} 

1597 

1598 if strip_namespaces: 

1599 

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

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

1602 

1603 else: 

1604 

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

1606 return tag 

1607 

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

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

1610 children = list(element) 

1611 if children: 

1612 for child in children: 

1613 name = get_name(child.tag) 

1614 child_value = get_value(child) 

1615 if name in value: 

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

1617 value[name] = [value[name]] 

1618 value[name].append(child_value) 

1619 else: 

1620 value[name] = child_value 

1621 elif value: 

1622 if element.text: 

1623 value["text"] = element.text 

1624 else: 

1625 return element.text 

1626 return value 

1627 

1628 if "xmp" not in self.info: 

1629 return {} 

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

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

1632 

1633 def getexif(self) -> Exif: 

1634 """ 

1635 Gets EXIF data from the image. 

1636 

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

1638 """ 

1639 if self._exif is None: 

1640 self._exif = Exif() 

1641 elif self._exif._loaded: 

1642 return self._exif 

1643 self._exif._loaded = True 

1644 

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

1646 if exif_info is None: 

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

1648 exif_info = bytes.fromhex( 

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

1650 ) 

1651 elif hasattr(self, "tag_v2"): 

1652 from . import TiffImagePlugin 

1653 

1654 assert isinstance(self, TiffImagePlugin.TiffImageFile) 

1655 self._exif.bigtiff = self.tag_v2._bigtiff 

1656 self._exif.endian = self.tag_v2._endian 

1657 

1658 assert self.fp is not None 

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

1660 if exif_info is not None: 

1661 self._exif.load(exif_info) 

1662 

1663 # XMP tags 

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

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

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

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

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

1669 if xmp_tags: 

1670 match = re.search(pattern, xmp_tags) 

1671 if match: 

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

1673 

1674 return self._exif 

1675 

1676 def _reload_exif(self) -> None: 

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

1678 return 

1679 self._exif._loaded = False 

1680 self.getexif() 

1681 

1682 def getim(self) -> CapsuleType: 

1683 """ 

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

1685 

1686 :returns: A capsule object. 

1687 """ 

1688 

1689 self.load() 

1690 return self.im.ptr 

1691 

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

1693 """ 

1694 Returns the image palette as a list. 

1695 

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

1697 return the palette in its current mode. 

1698 

1699 .. versionadded:: 9.1.0 

1700 

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

1702 image has no palette. 

1703 """ 

1704 

1705 self.load() 

1706 try: 

1707 mode = self.im.getpalettemode() 

1708 except ValueError: 

1709 return None # no palette 

1710 if rawmode is None: 

1711 rawmode = mode 

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

1713 

1714 @property 

1715 def has_transparency_data(self) -> bool: 

1716 """ 

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

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

1719 in the info dictionary. 

1720 

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

1722 within are opaque. 

1723 

1724 :returns: A boolean. 

1725 """ 

1726 if ( 

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

1728 or "transparency" in self.info 

1729 ): 

1730 return True 

1731 if self.mode == "P": 

1732 assert self.palette is not None 

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

1734 return False 

1735 

1736 def apply_transparency(self) -> None: 

1737 """ 

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

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

1740 Otherwise, the image is unchanged. 

1741 """ 

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

1743 return 

1744 

1745 from . import ImagePalette 

1746 

1747 palette = self.getpalette("RGBA") 

1748 assert palette is not None 

1749 transparency = self.info["transparency"] 

1750 if isinstance(transparency, bytes): 

1751 for i, alpha in enumerate(transparency): 

1752 palette[i * 4 + 3] = alpha 

1753 else: 

1754 palette[transparency * 4 + 3] = 0 

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

1756 self.palette.dirty = 1 

1757 

1758 del self.info["transparency"] 

1759 

1760 def getpixel( 

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

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

1763 """ 

1764 Returns the pixel value at a given position. 

1765 

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

1767 :ref:`coordinate-system`. 

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

1769 this method returns a tuple. 

1770 """ 

1771 

1772 self.load() 

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

1774 

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

1776 """ 

1777 Get projection to x and y axes 

1778 

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

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

1781 """ 

1782 

1783 self.load() 

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

1785 return list(x), list(y) 

1786 

1787 def histogram( 

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

1789 ) -> list[int]: 

1790 """ 

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

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

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

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

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

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

1797 

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

1799 by this method. 

1800 

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

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

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

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

1805 

1806 :param mask: An optional mask. 

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

1808 :returns: A list containing pixel counts. 

1809 """ 

1810 self.load() 

1811 if mask: 

1812 mask.load() 

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

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

1815 return self.im.histogram( 

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

1817 ) 

1818 return self.im.histogram() 

1819 

1820 def entropy( 

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

1822 ) -> float: 

1823 """ 

1824 Calculates and returns the entropy for the image. 

1825 

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

1827 image by this method. 

1828 

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

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

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

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

1833 

1834 :param mask: An optional mask. 

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

1836 :returns: A float value representing the image entropy 

1837 """ 

1838 self.load() 

1839 if mask: 

1840 mask.load() 

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

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

1843 return self.im.entropy( 

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

1845 ) 

1846 return self.im.entropy() 

1847 

1848 def paste( 

1849 self, 

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

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

1852 mask: Image | None = None, 

1853 ) -> None: 

1854 """ 

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

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

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

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

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

1860 

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

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

1863 details). 

1864 

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

1866 containing pixel values. The method then fills the region 

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

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

1869 :ref:`colors` for more information. 

1870 

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

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

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

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

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

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

1877 channels if they have them. 

1878 

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

1880 combine images with respect to their alpha channels. 

1881 

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

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

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

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

1886 upper left corner. 

1887 

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

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

1890 is interpreted as a mask image. 

1891 :param mask: An optional mask image. 

1892 """ 

1893 

1894 if isinstance(box, Image): 

1895 if mask is not None: 

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

1897 raise ValueError(msg) 

1898 # abbreviated paste(im, mask) syntax 

1899 mask = box 

1900 box = None 

1901 

1902 if box is None: 

1903 box = (0, 0) 

1904 

1905 if len(box) == 2: 

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

1907 if isinstance(im, Image): 

1908 size = im.size 

1909 elif isinstance(mask, Image): 

1910 size = mask.size 

1911 else: 

1912 # FIXME: use self.size here? 

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

1914 raise ValueError(msg) 

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

1916 

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

1918 if isinstance(im, str): 

1919 from . import ImageColor 

1920 

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

1922 elif isinstance(im, Image): 

1923 im.load() 

1924 if self.mode != im.mode: 

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

1926 # should use an adapter for this! 

1927 im = im.convert(self.mode) 

1928 source = im.im 

1929 else: 

1930 source = im 

1931 

1932 self._ensure_mutable() 

1933 

1934 if mask: 

1935 mask.load() 

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

1937 else: 

1938 self.im.paste(source, box) 

1939 

1940 def alpha_composite( 

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

1942 ) -> None: 

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

1944 onto this image. 

1945 

1946 :param im: image to composite over this one 

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

1948 left corner in this (destination) image. 

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

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

1951 bottom) for the bounds of the source rectangle 

1952 

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

1954 """ 

1955 

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

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

1958 raise ValueError(msg) 

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

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

1961 raise ValueError(msg) 

1962 

1963 if len(source) == 4: 

1964 overlay_crop_box = tuple(source) 

1965 elif len(source) == 2: 

1966 overlay_crop_box = tuple(source) + im.size 

1967 else: 

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

1969 raise ValueError(msg) 

1970 

1971 if not len(dest) == 2: 

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

1973 raise ValueError(msg) 

1974 if min(source) < 0: 

1975 msg = "Source must be non-negative" 

1976 raise ValueError(msg) 

1977 

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

1979 if overlay_crop_box == (0, 0, *im.size): 

1980 overlay = im 

1981 else: 

1982 overlay = im.crop(overlay_crop_box) 

1983 

1984 # target for the paste 

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

1986 

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

1988 if box == (0, 0, *self.size): 

1989 background = self 

1990 else: 

1991 background = self.crop(box) 

1992 

1993 result = alpha_composite(background, overlay) 

1994 self.paste(result, box) 

1995 

1996 def point( 

1997 self, 

1998 lut: ( 

1999 Sequence[float] 

2000 | NumpyArray 

2001 | Callable[[int], float] 

2002 | Callable[[ImagePointTransform], ImagePointTransform | float] 

2003 | ImagePointHandler 

2004 ), 

2005 mode: str | None = None, 

2006 ) -> Image: 

2007 """ 

2008 Maps this image through a lookup table or function. 

2009 

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

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

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

2013 single argument. The function is called once for each 

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

2015 all bands of the image. 

2016 

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

2018 object:: 

2019 

2020 class Example(Image.ImagePointHandler): 

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

2022 # Return result 

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

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

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

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

2027 """ 

2028 

2029 self.load() 

2030 

2031 if isinstance(lut, ImagePointHandler): 

2032 return lut.point(self) 

2033 

2034 if callable(lut): 

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

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

2037 # check if the function can be used with point_transform 

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

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

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

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

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

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

2044 else: 

2045 flatLut = lut 

2046 

2047 if self.mode == "F": 

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

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

2050 raise ValueError(msg) 

2051 

2052 if mode != "F": 

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

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

2055 

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

2057 """ 

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

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

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

2061 

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

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

2064 """ 

2065 

2066 self._ensure_mutable() 

2067 

2068 if self.mode in ("RGB", "RGBX"): 

2069 # promote self to RGBA 

2070 self.im.setalpha() 

2071 self._mode = "RGBA" 

2072 elif self.mode not in ("LA", "PA", "RGBA"): 

2073 try: 

2074 # do things the hard way 

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

2076 im = self.im.convert(mode) 

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

2078 msg = "alpha channel could not be added" 

2079 raise ValueError(msg) # sanity check 

2080 self.im = im 

2081 self._mode = self.im.mode 

2082 except KeyError as e: 

2083 msg = "illegal image mode" 

2084 raise ValueError(msg) from e 

2085 

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

2087 band = 1 

2088 else: 

2089 band = 3 

2090 

2091 if isinstance(alpha, Image): 

2092 # alpha layer 

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

2094 msg = "illegal image mode" 

2095 raise ValueError(msg) 

2096 alpha.load() 

2097 if alpha.mode == "1": 

2098 alpha = alpha.convert("L") 

2099 else: 

2100 # constant alpha 

2101 try: 

2102 self.im.fillband(band, alpha) 

2103 except (AttributeError, ValueError): 

2104 # do things the hard way 

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

2106 else: 

2107 return 

2108 

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

2110 

2111 def putdata( 

2112 self, 

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

2114 scale: float = 1.0, 

2115 offset: float = 0.0, 

2116 ) -> None: 

2117 """ 

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

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

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

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

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

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

2124 

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

2126 information about values. 

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

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

2129 """ 

2130 

2131 self._ensure_mutable() 

2132 

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

2134 

2135 def putpalette( 

2136 self, 

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

2138 rawmode: str = "RGB", 

2139 ) -> None: 

2140 """ 

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

2142 or "LA" image. 

2143 

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

2145 integer value for each channel in the raw mode. 

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

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

2148 index in the 256 colors. 

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

2150 containing red, green, blue and alpha values. 

2151 

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

2153 

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

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

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

2157 """ 

2158 from . import ImagePalette 

2159 

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

2161 msg = "illegal image mode" 

2162 raise ValueError(msg) 

2163 if isinstance(data, ImagePalette.ImagePalette): 

2164 if data.rawmode is not None: 

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

2166 else: 

2167 palette = ImagePalette.ImagePalette(palette=data.palette) 

2168 palette.dirty = 1 

2169 else: 

2170 if not isinstance(data, bytes): 

2171 data = bytes(data) 

2172 palette = ImagePalette.raw(rawmode, data) 

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

2174 self.palette = palette 

2175 if rawmode.startswith("CMYK"): 

2176 self.palette.mode = "CMYK" 

2177 elif "A" in rawmode: 

2178 self.palette.mode = "RGBA" 

2179 else: 

2180 self.palette.mode = "RGB" 

2181 self.load() # install new palette 

2182 

2183 def putpixel( 

2184 self, 

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

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

2187 ) -> None: 

2188 """ 

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

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

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

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

2193 

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

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

2196 module instead. 

2197 

2198 See: 

2199 

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

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

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

2203 

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

2205 :ref:`coordinate-system`. 

2206 :param value: The pixel value. 

2207 """ 

2208 

2209 self._ensure_mutable() 

2210 

2211 if ( 

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

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

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

2215 ): 

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

2217 if self.mode == "PA": 

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

2219 value = value[:3] 

2220 assert self.palette is not None 

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

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

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

2224 

2225 def remap_palette( 

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

2227 ) -> Image: 

2228 """ 

2229 Rewrites the image to reorder the palette. 

2230 

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

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

2233 is the identity transform. 

2234 :param source_palette: Bytes or None. 

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

2236 

2237 """ 

2238 from . import ImagePalette 

2239 

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

2241 msg = "illegal image mode" 

2242 raise ValueError(msg) 

2243 

2244 bands = 3 

2245 palette_mode = "RGB" 

2246 if source_palette is None: 

2247 if self.mode == "P": 

2248 self.load() 

2249 palette_mode = self.im.getpalettemode() 

2250 if palette_mode == "RGBA": 

2251 bands = 4 

2252 source_palette = self.im.getpalette(palette_mode) 

2253 else: # L-mode 

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

2255 elif len(source_palette) > 768: 

2256 bands = 4 

2257 palette_mode = "RGBA" 

2258 

2259 palette_bytes = b"" 

2260 new_positions = [0] * 256 

2261 

2262 # pick only the used colors from the palette 

2263 for i, oldPosition in enumerate(dest_map): 

2264 palette_bytes += source_palette[ 

2265 oldPosition * bands : oldPosition * bands + bands 

2266 ] 

2267 new_positions[oldPosition] = i 

2268 

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

2270 

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

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

2273 # from palette 1 to palette 2. New_positions is 

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

2275 # palette 1 with any holes removed. 

2276 

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

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

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

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

2281 # sans palette thus converting the image bytes, then 

2282 # assigning the optimized RGB palette. 

2283 

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

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

2286 

2287 mapping_palette = bytearray(new_positions) 

2288 

2289 m_im = self.copy() 

2290 m_im._mode = "P" 

2291 

2292 m_im.palette = ImagePalette.ImagePalette( 

2293 palette_mode, palette=mapping_palette * bands 

2294 ) 

2295 # possibly set palette dirty, then 

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

2297 # or just force it. 

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

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

2300 

2301 m_im = m_im.convert("L") 

2302 

2303 m_im.putpalette(palette_bytes, palette_mode) 

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

2305 

2306 if "transparency" in self.info: 

2307 try: 

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

2309 except ValueError: 

2310 if "transparency" in m_im.info: 

2311 del m_im.info["transparency"] 

2312 

2313 return m_im 

2314 

2315 def _get_safe_box( 

2316 self, 

2317 size: tuple[int, int], 

2318 resample: Resampling, 

2319 box: tuple[float, float, float, float], 

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

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

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

2323 """ 

2324 filter_support = _filters_support[resample] - 0.5 

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

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

2327 support_x = filter_support * scale_x 

2328 support_y = filter_support * scale_y 

2329 

2330 return ( 

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

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

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

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

2335 ) 

2336 

2337 def resize( 

2338 self, 

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

2340 resample: int | None = None, 

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

2342 reducing_gap: float | None = None, 

2343 ) -> Image: 

2344 """ 

2345 Returns a resized copy of this image. 

2346 

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

2348 (width, height). 

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

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

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

2352 :py:data:`Resampling.BICUBIC`, :py:data:`Resampling.LANCZOS`, 

2353 :py:data:`Resampling.MKS2013`, or :py:data:`Resampling.MKS2021`. 

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

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

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

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

2358 the source image region to be scaled. 

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

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

2361 :param reducing_gap: Apply optimization by resizing the image 

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

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

2364 Second, resizing using regular resampling. The last step 

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

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

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

2368 the closer the result to the fair resampling. 

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

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

2371 indistinguishable from fair resampling in most cases. 

2372 The default value is None (no optimization). 

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

2374 """ 

2375 

2376 if resample is None: 

2377 resample = Resampling.BICUBIC 

2378 elif resample not in ( 

2379 Resampling.NEAREST, 

2380 Resampling.BILINEAR, 

2381 Resampling.BICUBIC, 

2382 Resampling.LANCZOS, 

2383 Resampling.BOX, 

2384 Resampling.HAMMING, 

2385 Resampling.MKS2013, 

2386 Resampling.MKS2021, 

2387 ): 

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

2389 

2390 filters = [ 

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

2392 for filter in ( 

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

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

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

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

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

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

2399 (Resampling.MKS2013, "Image.Resampling.MKS2013"), 

2400 (Resampling.MKS2021, "Image.Resampling.MKS2021"), 

2401 ) 

2402 ] 

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

2404 raise ValueError(msg) 

2405 

2406 if reducing_gap is not None and reducing_gap < 1.0: 

2407 msg = "reducing_gap must be 1.0 or greater" 

2408 raise ValueError(msg) 

2409 

2410 if box is None: 

2411 box = (0, 0, *self.size) 

2412 

2413 size = tuple(size) 

2414 if self.size == size and box == (0, 0, *self.size): 

2415 return self.copy() 

2416 

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

2418 resample = Resampling.NEAREST 

2419 

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

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

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

2423 return im.convert(self.mode) 

2424 

2425 self.load() 

2426 

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

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

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

2430 if factor_x > 1 or factor_y > 1: 

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

2432 factor = (factor_x, factor_y) 

2433 self = ( 

2434 self.reduce(factor, box=reduce_box) 

2435 if callable(self.reduce) 

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

2437 ) 

2438 box = ( 

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

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

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

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

2443 ) 

2444 

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

2446 im = self.im.resize( 

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

2448 ) 

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

2450 else: 

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

2452 return self._new(im) 

2453 

2454 def reduce( 

2455 self, 

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

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

2458 ) -> Image: 

2459 """ 

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

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

2462 the resulting size will be rounded up. 

2463 

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

2465 for width and height separately. 

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

2467 the source image region to be reduced. 

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

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

2470 """ 

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

2472 factor = (factor, factor) 

2473 

2474 if factor == (1, 1): 

2475 return self.crop(box) 

2476 

2477 if box is None: 

2478 box = (0, 0, *self.size) 

2479 

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

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

2482 im = im.reduce(factor, box) 

2483 return im.convert(self.mode) 

2484 

2485 self.load() 

2486 

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

2488 

2489 def rotate( 

2490 self, 

2491 angle: float, 

2492 resample: Resampling = Resampling.NEAREST, 

2493 expand: int | bool = False, 

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

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

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

2497 ) -> Image: 

2498 """ 

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

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

2501 clockwise around its centre. 

2502 

2503 :param angle: In degrees counterclockwise. 

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

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

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

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

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

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

2510 See :ref:`concept-filters`. 

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

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

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

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

2515 the center and no translation. 

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

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

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

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

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

2521 """ 

2522 

2523 angle = angle % 360.0 

2524 

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

2526 # translating or changing the center. 

2527 if not (center or translate): 

2528 if angle == 0: 

2529 return self.copy() 

2530 if angle == 180: 

2531 return self.transpose(Transpose.ROTATE_180) 

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

2533 return self.transpose( 

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

2535 ) 

2536 

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

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

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

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

2541 

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

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

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

2545 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2546 

2547 # The reverse matrix is thus: 

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

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

2550 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2551 

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

2553 # compensate for the expand flag. 

2554 

2555 w, h = self.size 

2556 

2557 if translate is None: 

2558 post_trans = (0, 0) 

2559 else: 

2560 post_trans = translate 

2561 if center is None: 

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

2563 

2564 angle = -math.radians(angle) 

2565 matrix = [ 

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

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

2568 0.0, 

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

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

2571 0.0, 

2572 ] 

2573 

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

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

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

2577 

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

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

2580 ) 

2581 matrix[2] += center[0] 

2582 matrix[5] += center[1] 

2583 

2584 if expand: 

2585 # calculate output size 

2586 xx = [] 

2587 yy = [] 

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

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

2590 xx.append(transformed_x) 

2591 yy.append(transformed_y) 

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

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

2594 

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

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

2597 # translation vector as new translation vector. 

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

2599 w, h = nw, nh 

2600 

2601 return self.transform( 

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

2603 ) 

2604 

2605 def save( 

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

2607 ) -> None: 

2608 """ 

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

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

2611 extension, if possible. 

2612 

2613 Keyword options can be used to provide additional instructions 

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

2615 silently ignored. The available options are described in the 

2616 :doc:`image format documentation 

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

2618 

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

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

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

2622 methods, and be opened in binary mode. 

2623 

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

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

2626 format to use is determined from the filename extension. 

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

2628 parameter should always be used. 

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

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

2631 saving multiple images:: 

2632 

2633 # Saving XMP data to a single image 

2634 from PIL import Image 

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

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

2637 

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

2639 from PIL import Image 

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

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

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

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

2644 :returns: None 

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

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

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

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

2649 """ 

2650 

2651 filename: str | bytes = "" 

2652 open_fp = False 

2653 if is_path(fp): 

2654 filename = os.fspath(fp) 

2655 open_fp = True 

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

2657 fp = sys.stdout.buffer 

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

2659 # only set the name for metadata purposes 

2660 filename = os.fspath(fp.name) 

2661 

2662 if format: 

2663 preinit() 

2664 else: 

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

2666 ext = ( 

2667 filename_ext.decode() 

2668 if isinstance(filename_ext, bytes) 

2669 else filename_ext 

2670 ) 

2671 

2672 # Try importing only the plugin for this extension first 

2673 if not _import_plugin_for_extension(ext): 

2674 preinit() 

2675 

2676 if ext not in EXTENSION: 

2677 init() 

2678 try: 

2679 format = EXTENSION[ext] 

2680 except KeyError as e: 

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

2682 raise ValueError(msg) from e 

2683 

2684 from . import ImageFile 

2685 

2686 # may mutate self! 

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

2688 filename 

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

2690 self._ensure_mutable() 

2691 else: 

2692 self.load() 

2693 

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

2695 self._default_encoderinfo = params 

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

2697 self._attach_default_encoderinfo(self) 

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

2699 

2700 if format.upper() not in SAVE: 

2701 init() 

2702 if save_all or ( 

2703 save_all is None 

2704 and params.get("append_images") 

2705 and format.upper() in SAVE_ALL 

2706 ): 

2707 save_handler = SAVE_ALL[format.upper()] 

2708 else: 

2709 save_handler = SAVE[format.upper()] 

2710 

2711 created = False 

2712 if open_fp: 

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

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

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

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

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

2718 else: 

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

2720 else: 

2721 fp = cast("IO[bytes]", fp) 

2722 

2723 try: 

2724 save_handler(self, fp, filename) 

2725 except Exception: 

2726 if open_fp: 

2727 fp.close() 

2728 if created: 

2729 try: 

2730 os.remove(filename) 

2731 except PermissionError: 

2732 pass 

2733 raise 

2734 finally: 

2735 self.encoderinfo = encoderinfo 

2736 if open_fp: 

2737 fp.close() 

2738 

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

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

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

2742 return encoderinfo 

2743 

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

2745 """ 

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

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

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

2749 library automatically seeks to frame 0. 

2750 

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

2752 

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

2754 number of available frames. 

2755 

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

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

2758 of the sequence. 

2759 """ 

2760 

2761 # overridden by file handlers 

2762 if frame != 0: 

2763 msg = "no more images in file" 

2764 raise EOFError(msg) 

2765 

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

2767 """ 

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

2769 

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

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

2772 

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

2774 PNG format. 

2775 

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

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

2778 

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

2780 

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

2782 

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

2784 """ 

2785 

2786 from . import ImageShow 

2787 

2788 ImageShow.show(self, title) 

2789 

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

2791 """ 

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

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

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

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

2796 blue). 

2797 

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

2799 method can be more convenient and faster. 

2800 

2801 :returns: A tuple containing bands. 

2802 """ 

2803 

2804 self.load() 

2805 if self.im.bands == 1: 

2806 return (self.copy(),) 

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

2808 

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

2810 """ 

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

2812 

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

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

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

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

2817 

2818 .. versionadded:: 4.3.0 

2819 """ 

2820 self.load() 

2821 

2822 if isinstance(channel, str): 

2823 try: 

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

2825 except ValueError as e: 

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

2827 raise ValueError(msg) from e 

2828 

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

2830 

2831 def tell(self) -> int: 

2832 """ 

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

2834 

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

2836 number of available frames. 

2837 

2838 :returns: Frame number, starting with 0. 

2839 """ 

2840 return 0 

2841 

2842 def thumbnail( 

2843 self, 

2844 size: tuple[float, float], 

2845 resample: Resampling = Resampling.BICUBIC, 

2846 reducing_gap: float | None = 2.0, 

2847 ) -> None: 

2848 """ 

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

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

2851 the given size. This method calculates an appropriate thumbnail 

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

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

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

2855 

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

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

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

2859 image. 

2860 

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

2862 (width, height). 

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

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

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

2866 :py:data:`Resampling.BICUBIC`, :py:data:`Resampling.LANCZOS`, 

2867 :py:data:`Resampling.MKS2013`, or :py:data:`Resampling.MKS2021`. 

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

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

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

2871 :param reducing_gap: Apply optimization by resizing the image 

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

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

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

2875 Second, resizing using regular resampling. The last step 

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

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

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

2879 the closer the result to the fair resampling. 

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

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

2882 indistinguishable from fair resampling in most cases. 

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

2884 while still being faster in many cases). 

2885 :returns: None 

2886 """ 

2887 

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

2889 

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

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

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

2893 

2894 x, y = provided_size 

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

2896 return None 

2897 

2898 aspect = self.width / self.height 

2899 if x / y >= aspect: 

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

2901 else: 

2902 y = round_aspect( 

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

2904 ) 

2905 return x, y 

2906 

2907 preserved_size = preserve_aspect_ratio() 

2908 if preserved_size is None: 

2909 return 

2910 final_size = preserved_size 

2911 

2912 box = None 

2913 if reducing_gap is not None: 

2914 res = self.draft( 

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

2916 ) 

2917 if res is not None: 

2918 box = res[1] 

2919 

2920 if self.size != final_size: 

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

2922 

2923 self.im = im.im 

2924 self._size = final_size 

2925 self._mode = self.im.mode 

2926 

2927 self.readonly = 0 

2928 

2929 # FIXME: the different transform methods need further explanation 

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

2931 def transform( 

2932 self, 

2933 size: tuple[int, int], 

2934 method: Transform | ImageTransformHandler | SupportsGetData, 

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

2936 resample: int = Resampling.NEAREST, 

2937 fill: int = 1, 

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

2939 ) -> Image: 

2940 """ 

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

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

2943 to the new image using the given transform. 

2944 

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

2946 (width, height). 

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

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

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

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

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

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

2953 in one operation). 

2954 

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

2956 object:: 

2957 

2958 class Example(Image.ImageTransformHandler): 

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

2960 # Return result 

2961 

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

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

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

2965 

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

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

2968 

2969 class Example: 

2970 def getdata(self): 

2971 method = Image.Transform.EXTENT 

2972 data = (0, 0, 100, 100) 

2973 return method, data 

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

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

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

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

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

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

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

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

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

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

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

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

2986 transform in the output image. 

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

2988 """ 

2989 

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

2991 return ( 

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

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

2994 .convert(self.mode) 

2995 ) 

2996 

2997 if isinstance(method, ImageTransformHandler): 

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

2999 

3000 if hasattr(method, "getdata"): 

3001 # compatibility w. old-style transform objects 

3002 method, data = method.getdata() 

3003 

3004 if data is None: 

3005 msg = "missing method data" 

3006 raise ValueError(msg) 

3007 

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

3009 if self.mode in ("P", "PA") and self.palette: 

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

3011 im.info = self._copy_info() 

3012 if method == Transform.MESH: 

3013 # list of quads 

3014 for box, quad in data: 

3015 im.__transformer( 

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

3017 ) 

3018 else: 

3019 im.__transformer( 

3020 (0, 0, *size), self, method, data, resample, fillcolor is None 

3021 ) 

3022 

3023 return im 

3024 

3025 def __transformer( 

3026 self, 

3027 box: tuple[int, int, int, int], 

3028 image: Image, 

3029 method: Transform, 

3030 data: Sequence[float], 

3031 resample: int = Resampling.NEAREST, 

3032 fill: bool = True, 

3033 ) -> None: 

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

3035 h = box[3] - box[1] 

3036 

3037 if method == Transform.AFFINE: 

3038 data = data[:6] 

3039 

3040 elif method == Transform.EXTENT: 

3041 # convert extent to an affine transform 

3042 x0, y0, x1, y1 = data 

3043 xs = (x1 - x0) / w 

3044 ys = (y1 - y0) / h 

3045 method = Transform.AFFINE 

3046 data = (xs, 0, x0, 0, ys, y0) 

3047 

3048 elif method == Transform.PERSPECTIVE: 

3049 data = data[:8] 

3050 

3051 elif method == Transform.QUAD: 

3052 # quadrilateral warp. data specifies the four corners 

3053 # given as NW, SW, SE, and NE. 

3054 nw = data[:2] 

3055 sw = data[2:4] 

3056 se = data[4:6] 

3057 ne = data[6:8] 

3058 x0, y0 = nw 

3059 As = 1.0 / w 

3060 At = 1.0 / h 

3061 data = ( 

3062 x0, 

3063 (ne[0] - x0) * As, 

3064 (sw[0] - x0) * At, 

3065 (se[0] - sw[0] - ne[0] + x0) * As * At, 

3066 y0, 

3067 (ne[1] - y0) * As, 

3068 (sw[1] - y0) * At, 

3069 (se[1] - sw[1] - ne[1] + y0) * As * At, 

3070 ) 

3071 

3072 else: 

3073 msg = "unknown transformation method" 

3074 raise ValueError(msg) 

3075 

3076 if resample not in ( 

3077 Resampling.NEAREST, 

3078 Resampling.BILINEAR, 

3079 Resampling.BICUBIC, 

3080 ): 

3081 if resample in ( 

3082 Resampling.BOX, 

3083 Resampling.HAMMING, 

3084 Resampling.LANCZOS, 

3085 Resampling.MKS2013, 

3086 Resampling.MKS2021, 

3087 ): 

3088 unusable: dict[int, str] = { 

3089 Resampling.BOX: "Image.Resampling.BOX", 

3090 Resampling.HAMMING: "Image.Resampling.HAMMING", 

3091 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

3092 Resampling.MKS2013: "Image.Resampling.MKS2013", 

3093 Resampling.MKS2021: "Image.Resampling.MKS2021", 

3094 } 

3095 msg = unusable[resample] + f" ({resample}) cannot be used." 

3096 else: 

3097 msg = f"Unknown resampling filter ({resample})." 

3098 

3099 filters = [ 

3100 f"{filter[1]} ({filter[0]})" 

3101 for filter in ( 

3102 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

3103 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

3104 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

3105 ) 

3106 ] 

3107 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

3108 raise ValueError(msg) 

3109 

3110 image.load() 

3111 

3112 self.load() 

3113 

3114 if image.mode in ("1", "P"): 

3115 resample = Resampling.NEAREST 

3116 

3117 self.im.transform(box, image.im, method, data, resample, fill) 

3118 

3119 def transpose(self, method: Transpose) -> Image: 

3120 """ 

3121 Transpose image (flip or rotate in 90 degree steps) 

3122 

3123 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

3124 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

3125 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

3126 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

3127 :returns: Returns a flipped or rotated copy of this image. 

3128 """ 

3129 

3130 self.load() 

3131 return self._new(self.im.transpose(method)) 

3132 

3133 def effect_spread(self, distance: int) -> Image: 

3134 """ 

3135 Randomly spread pixels in an image. 

3136 

3137 :param distance: Distance to spread pixels. 

3138 """ 

3139 self.load() 

3140 return self._new(self.im.effect_spread(distance)) 

3141 

3142 def toqimage(self) -> ImageQt.ImageQt: 

3143 """Returns a QImage copy of this image""" 

3144 from . import ImageQt 

3145 

3146 if not ImageQt.qt_is_installed: 

3147 msg = "Qt bindings are not installed" 

3148 raise ImportError(msg) 

3149 return ImageQt.toqimage(self) 

3150 

3151 def toqpixmap(self) -> ImageQt.QPixmap: 

3152 """Returns a QPixmap copy of this image""" 

3153 from . import ImageQt 

3154 

3155 if not ImageQt.qt_is_installed: 

3156 msg = "Qt bindings are not installed" 

3157 raise ImportError(msg) 

3158 return ImageQt.toqpixmap(self) 

3159 

3160 

3161# -------------------------------------------------------------------- 

3162# Abstract handlers. 

3163 

3164 

3165class ImagePointHandler(abc.ABC): 

3166 """ 

3167 Used as a mixin by point transforms 

3168 (for use with :py:meth:`~PIL.Image.Image.point`) 

3169 """ 

3170 

3171 @abc.abstractmethod 

3172 def point(self, im: Image) -> Image: 

3173 pass 

3174 

3175 

3176class ImageTransformHandler(abc.ABC): 

3177 """ 

3178 Used as a mixin by geometry transforms 

3179 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3180 """ 

3181 

3182 @abc.abstractmethod 

3183 def transform( 

3184 self, 

3185 size: tuple[int, int], 

3186 image: Image, 

3187 **options: Any, 

3188 ) -> Image: 

3189 pass 

3190 

3191 

3192# -------------------------------------------------------------------- 

3193# Factories 

3194 

3195 

3196def _check_size(size: Any) -> None: 

3197 """ 

3198 Common check to enforce type and sanity check on size tuples 

3199 

3200 :param size: Should be a 2 tuple of (width, height) 

3201 :returns: None, or raises a ValueError 

3202 """ 

3203 

3204 if not isinstance(size, (list, tuple)): 

3205 msg = "Size must be a list or tuple" 

3206 raise ValueError(msg) 

3207 if len(size) != 2: 

3208 msg = "Size must be a sequence of length 2" 

3209 raise ValueError(msg) 

3210 if size[0] < 0 or size[1] < 0: 

3211 msg = "Width and height must be >= 0" 

3212 raise ValueError(msg) 

3213 

3214 

3215def new( 

3216 mode: str, 

3217 size: tuple[int, int] | list[int], 

3218 color: float | tuple[float, ...] | str | None = 0, 

3219) -> Image: 

3220 """ 

3221 Creates a new image with the given mode and size. 

3222 

3223 :param mode: The mode to use for the new image. See: :ref:`concept-modes`. 

3224 :param size: A 2-tuple, containing (width, height) in pixels. 

3225 :param color: What color to use for the image. If given, this should be a single 

3226 integer or floating point value for single-band modes, and a tuple for 

3227 multi-band modes (one value per band). When creating RGB or HSV images, you can 

3228 also use color strings as supported by the ImageColor module. See :ref:`colors` 

3229 for more information. The default color is zero, which appears as black in 

3230 single band or RGB-based images. ``None`` is also treated as zero. 

3231 :returns: An :py:class:`~PIL.Image.Image` object. 

3232 """ 

3233 

3234 _check_size(size) 

3235 

3236 if color is None: 

3237 # core.new() returns zeroed memory, so there is nothing to fill 

3238 return Image()._new(core.new(mode, size)) 

3239 

3240 if isinstance(color, str): 

3241 # css3-style specifier 

3242 

3243 from . import ImageColor 

3244 

3245 color = ImageColor.getcolor(color, mode) 

3246 

3247 im = Image() 

3248 if ( 

3249 mode == "P" 

3250 and isinstance(color, (list, tuple)) 

3251 and all(isinstance(i, int) for i in color) 

3252 ): 

3253 color_ints: tuple[int, ...] = cast("tuple[int, ...]", tuple(color)) 

3254 if len(color_ints) == 3 or len(color_ints) == 4: 

3255 # RGB or RGBA value for a P image 

3256 from . import ImagePalette 

3257 

3258 im.palette = ImagePalette.ImagePalette() 

3259 color = im.palette.getcolor(color_ints) 

3260 return im._new(core.fill(mode, size, color)) 

3261 

3262 

3263def frombytes( 

3264 mode: str, 

3265 size: tuple[int, int], 

3266 data: DecoderInput, 

3267 decoder_name: str = "raw", 

3268 *args: Any, 

3269) -> Image: 

3270 """ 

3271 Creates a copy of an image memory from pixel data in a buffer. 

3272 

3273 In its simplest form, this function takes three arguments 

3274 (mode, size, and unpacked pixel data). 

3275 

3276 You can also use any pixel decoder supported by PIL. For more 

3277 information on available decoders, see the section 

3278 :ref:`Writing Your Own File Codec <file-codecs>`. 

3279 

3280 Note that this function decodes pixel data only, not entire images. 

3281 If you have an entire image in a string, wrap it in a 

3282 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3283 it. 

3284 

3285 :param mode: The image mode. See: :ref:`concept-modes`. 

3286 :param size: The image size. 

3287 :param data: A byte buffer containing raw data for the given mode. 

3288 :param decoder_name: What decoder to use. 

3289 :param args: Additional parameters for the given decoder. 

3290 :returns: An :py:class:`~PIL.Image.Image` object. 

3291 """ 

3292 

3293 _check_size(size) 

3294 

3295 im = new(mode, size) 

3296 if im.width != 0 and im.height != 0: 

3297 decoder_args: Any = args 

3298 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3299 # may pass tuple instead of argument list 

3300 decoder_args = decoder_args[0] 

3301 

3302 if decoder_name == "raw" and decoder_args == (): 

3303 decoder_args = mode 

3304 

3305 im.frombytes(data, decoder_name, decoder_args) 

3306 return im 

3307 

3308 

3309def frombuffer( 

3310 mode: str, 

3311 size: tuple[int, int], 

3312 data: bytes | SupportsArrayInterface, 

3313 decoder_name: str = "raw", 

3314 *args: Any, 

3315) -> Image: 

3316 """ 

3317 Creates an image memory referencing pixel data in a byte buffer. 

3318 

3319 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3320 in the byte buffer, where possible. This means that changes to the 

3321 original buffer object are reflected in this image). Not all modes can 

3322 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3323 

3324 Note that this function decodes pixel data only, not entire images. 

3325 If you have an entire image file in a string, wrap it in a 

3326 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3327 

3328 The default parameters used for the "raw" decoder differs from that used for 

3329 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3330 future release. The current release issues a warning if you do this; to disable 

3331 the warning, you should provide the full set of parameters. See below for details. 

3332 

3333 :param mode: The image mode. See: :ref:`concept-modes`. 

3334 :param size: The image size. 

3335 :param data: A bytes or other buffer object containing raw 

3336 data for the given mode. 

3337 :param decoder_name: What decoder to use. 

3338 :param args: Additional parameters for the given decoder. For the 

3339 default encoder ("raw"), it's recommended that you provide the 

3340 full set of parameters:: 

3341 

3342 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3343 

3344 :returns: An :py:class:`~PIL.Image.Image` object. 

3345 

3346 .. versionadded:: 1.1.4 

3347 """ 

3348 

3349 _check_size(size) 

3350 

3351 # may pass tuple instead of argument list 

3352 if len(args) == 1 and isinstance(args[0], tuple): 

3353 args = args[0] 

3354 

3355 if decoder_name == "raw": 

3356 if args == (): 

3357 args = mode, 0, 1 

3358 if args[0] in _MAPMODES: 

3359 im = new(mode, (0, 0)) 

3360 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3361 if mode == "P": 

3362 from . import ImagePalette 

3363 

3364 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3365 im.readonly = 1 

3366 return im 

3367 

3368 return frombytes(mode, size, data, decoder_name, args) 

3369 

3370 

3371class SupportsArrayInterface(Protocol): 

3372 """ 

3373 An object that has an ``__array_interface__`` dictionary. 

3374 """ 

3375 

3376 @property 

3377 def __array_interface__(self) -> dict[str, Any]: 

3378 raise NotImplementedError() 

3379 

3380 def __len__(self) -> int: 

3381 raise NotImplementedError() 

3382 

3383 

3384DecoderInput = bytes | bytearray | memoryview | SupportsArrayInterface 

3385 

3386 

3387class SupportsArrowArrayInterface(Protocol): 

3388 """ 

3389 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3390 data interface. 

3391 """ 

3392 

3393 def __arrow_c_array__( 

3394 self, requested_schema: PyCapsule = None # type: ignore[name-defined] # noqa: F821 

3395 ) -> tuple[PyCapsule, PyCapsule]: # type: ignore[name-defined] # noqa: F821 

3396 raise NotImplementedError() 

3397 

3398 

3399def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3400 """ 

3401 Creates an image memory from an object exporting the array interface 

3402 (using the buffer protocol):: 

3403 

3404 from PIL import Image 

3405 import numpy as np 

3406 a = np.zeros((5, 5)) 

3407 im = Image.fromarray(a) 

3408 

3409 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3410 and :py:func:`~PIL.Image.frombuffer` is used. 

3411 

3412 In the case of NumPy, be aware that Pillow modes do not always correspond 

3413 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3414 32-bit signed integer pixels, and 32-bit floating point pixels. 

3415 

3416 Pillow images can also be converted to arrays:: 

3417 

3418 from PIL import Image 

3419 import numpy as np 

3420 im = Image.open("hopper.jpg") 

3421 a = np.asarray(im) 

3422 

3423 When converting Pillow images to arrays however, only pixel values are 

3424 transferred. This means that P and PA mode images will lose their palette. 

3425 

3426 :param obj: Object with array interface 

3427 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not 

3428 contain information about palettes or color spaces, this can be used to place 

3429 grayscale L mode data within a P mode image, or read RGB data as YCbCr for 

3430 example. 

3431 

3432 See: :ref:`concept-modes` for general information about modes. 

3433 :returns: An image object. 

3434 

3435 .. versionadded:: 1.1.6 

3436 """ 

3437 arr = obj.__array_interface__ 

3438 shape = arr["shape"] 

3439 ndim = len(shape) 

3440 strides = arr.get("strides", None) 

3441 try: 

3442 typekey = (1, 1) + shape[2:], arr["typestr"] 

3443 except KeyError as e: 

3444 if mode is not None: 

3445 typekey = None 

3446 color_modes: list[str] = [] 

3447 else: 

3448 msg = "Cannot handle this data type" 

3449 raise TypeError(msg) from e 

3450 if typekey is not None: 

3451 try: 

3452 typemode, rawmode, color_modes = _fromarray_typemap[typekey] 

3453 except KeyError as e: 

3454 typekey_shape, typestr = typekey 

3455 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3456 raise TypeError(msg) from e 

3457 if mode is not None: 

3458 if mode != typemode and mode not in color_modes: 

3459 msg = "Invalid mode for data type" 

3460 raise ValueError(msg) 

3461 rawmode = mode 

3462 else: 

3463 mode = typemode 

3464 if mode in ["1", "L", "I", "P", "F"]: 

3465 ndmax = 2 

3466 elif mode == "RGB": 

3467 ndmax = 3 

3468 else: 

3469 ndmax = 4 

3470 if ndim > ndmax: 

3471 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3472 raise ValueError(msg) 

3473 

3474 size = 1 if ndim == 1 else shape[1], shape[0] 

3475 if strides is not None: 

3476 if hasattr(obj, "tobytes"): 

3477 obj = obj.tobytes() 

3478 elif hasattr(obj, "tostring"): 

3479 obj = obj.tostring() 

3480 else: 

3481 msg = "'strides' requires either tobytes() or tostring()" 

3482 raise ValueError(msg) 

3483 

3484 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3485 

3486 

3487def fromarrow( 

3488 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3489) -> Image: 

3490 """Creates an image with zero-copy shared memory from an object exporting 

3491 the arrow_c_array interface protocol:: 

3492 

3493 from PIL import Image 

3494 import pyarrow as pa 

3495 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3496 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3497 

3498 If the data representation of the ``obj`` is not compatible with 

3499 Pillow internal storage, a ValueError is raised. 

3500 

3501 Pillow images can also be converted to Arrow objects:: 

3502 

3503 from PIL import Image 

3504 import pyarrow as pa 

3505 im = Image.open('hopper.jpg') 

3506 arr = pa.array(im) 

3507 

3508 As with array support, when converting Pillow images to arrays, 

3509 only pixel values are transferred. This means that P and PA mode 

3510 images will lose their palette. 

3511 

3512 :param obj: Object with an arrow_c_array interface 

3513 :param mode: Image mode. 

3514 :param size: Image size. This must match the storage of the arrow object. 

3515 :returns: An Image object 

3516 

3517 Note that according to the Arrow spec, both the producer and the 

3518 consumer should consider the exported array to be immutable, as 

3519 unsynchronized updates will potentially cause inconsistent data. 

3520 

3521 See: :ref:`arrow-support` for more detailed information 

3522 

3523 .. versionadded:: 11.2.1 

3524 

3525 """ 

3526 if not hasattr(obj, "__arrow_c_array__"): 

3527 msg = "arrow_c_array interface not found" 

3528 raise ValueError(msg) 

3529 

3530 schema_capsule, array_capsule = obj.__arrow_c_array__() 

3531 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3532 if _im: 

3533 return Image()._new(_im) 

3534 

3535 msg = "new_arrow returned None without an exception" 

3536 raise ValueError(msg) 

3537 

3538 

3539def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3540 """Creates an image instance from a QImage image""" 

3541 from . import ImageQt 

3542 

3543 if not ImageQt.qt_is_installed: 

3544 msg = "Qt bindings are not installed" 

3545 raise ImportError(msg) 

3546 return ImageQt.fromqimage(im) 

3547 

3548 

3549def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3550 """Creates an image instance from a QPixmap image""" 

3551 from . import ImageQt 

3552 

3553 if not ImageQt.qt_is_installed: 

3554 msg = "Qt bindings are not installed" 

3555 raise ImportError(msg) 

3556 return ImageQt.fromqpixmap(im) 

3557 

3558 

3559_fromarray_typemap = { 

3560 # (shape, typestr) => mode, rawmode, color modes 

3561 # first two members of shape are set to one 

3562 ((1, 1), "|b1"): ("1", "1;8", []), 

3563 ((1, 1), "|u1"): ("L", "L", ["P"]), 

3564 ((1, 1), "|i1"): ("I", "I;8", []), 

3565 ((1, 1), "<u2"): ("I", "I;16", []), 

3566 ((1, 1), ">u2"): ("I", "I;16B", []), 

3567 ((1, 1), "<i2"): ("I", "I;16S", []), 

3568 ((1, 1), ">i2"): ("I", "I;16BS", []), 

3569 ((1, 1), "<u4"): ("I", "I;32", []), 

3570 ((1, 1), ">u4"): ("I", "I;32B", []), 

3571 ((1, 1), "<i4"): ("I", "I;32S", []), 

3572 ((1, 1), ">i4"): ("I", "I;32BS", []), 

3573 ((1, 1), "<f4"): ("F", "F;32F", []), 

3574 ((1, 1), ">f4"): ("F", "F;32BF", []), 

3575 ((1, 1), "<f8"): ("F", "F;64F", []), 

3576 ((1, 1), ">f8"): ("F", "F;64BF", []), 

3577 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]), 

3578 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), 

3579 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), 

3580 # shortcuts: 

3581 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []), 

3582 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []), 

3583} 

3584 

3585 

3586def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3587 if MAX_IMAGE_PIXELS is None: 

3588 return 

3589 

3590 pixels = max(1, size[0]) * max(1, size[1]) 

3591 

3592 if pixels > 2 * MAX_IMAGE_PIXELS: 

3593 msg = ( 

3594 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3595 "pixels, could be decompression bomb DOS attack." 

3596 ) 

3597 raise DecompressionBombError(msg) 

3598 

3599 if pixels > MAX_IMAGE_PIXELS: 

3600 warnings.warn( 

3601 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3602 "could be decompression bomb DOS attack.", 

3603 DecompressionBombWarning, 

3604 ) 

3605 

3606 

3607def open( 

3608 fp: StrOrBytesPath | IO[bytes], 

3609 mode: Literal["r"] = "r", 

3610 formats: list[str] | tuple[str, ...] | None = None, 

3611) -> ImageFile.ImageFile: 

3612 """ 

3613 Opens and identifies the given image file. 

3614 

3615 This is a lazy operation; this function identifies the file, but 

3616 the file remains open and the actual image data is not read from 

3617 the file until you try to process the data (or call the 

3618 :py:meth:`~PIL.Image.Image.load` method). See 

3619 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3620 

3621 :param fp: A filename (string), os.PathLike object or a file object. 

3622 The file object must implement ``file.read``, 

3623 ``file.seek``, and ``file.tell`` methods, 

3624 and be opened in binary mode. The file object will also seek to zero 

3625 before reading. 

3626 :param mode: The mode. If given, this argument must be "r". 

3627 :param formats: A list or tuple of formats to attempt to load the file in. 

3628 This can be used to restrict the set of formats checked. 

3629 Pass ``None`` to try all supported formats. You can print the set of 

3630 available formats by running ``python3 -m PIL`` or using 

3631 the :py:func:`PIL.features.pilinfo` function. 

3632 :returns: An :py:class:`~PIL.Image.Image` object. 

3633 :exception FileNotFoundError: If the file cannot be found. 

3634 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3635 identified. 

3636 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3637 instance is used for ``fp``. 

3638 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3639 """ 

3640 

3641 if mode != "r": 

3642 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3643 raise ValueError(msg) 

3644 elif isinstance(fp, io.StringIO): 

3645 msg = ( # type: ignore[unreachable] 

3646 "StringIO cannot be used to open an image. " 

3647 "Binary data must be used instead." 

3648 ) 

3649 raise ValueError(msg) 

3650 

3651 if formats is None: 

3652 formats = ID 

3653 elif not isinstance(formats, (list, tuple)): 

3654 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3655 raise TypeError(msg) 

3656 

3657 exclusive_fp = False 

3658 filename: str | bytes = "" 

3659 if is_path(fp): 

3660 filename = os.fspath(fp) 

3661 fp = builtins.open(filename, "rb") 

3662 exclusive_fp = True 

3663 else: 

3664 fp = cast("IO[bytes]", fp) 

3665 

3666 try: 

3667 fp.seek(0) 

3668 except (AttributeError, io.UnsupportedOperation): 

3669 fp = io.BytesIO(fp.read()) 

3670 exclusive_fp = True 

3671 

3672 prefix = fp.read(16) 

3673 

3674 # Try to import just the plugin needed for this file extension 

3675 # before falling back to preinit() which imports common plugins 

3676 ext = os.path.splitext(filename)[1] if filename else "" 

3677 if not _import_plugin_for_extension(ext): 

3678 preinit() 

3679 

3680 warning_messages: list[str] = [] 

3681 

3682 def _open_core( 

3683 fp: IO[bytes], 

3684 filename: str | bytes, 

3685 prefix: bytes, 

3686 formats: list[str] | tuple[str, ...], 

3687 ) -> ImageFile.ImageFile | None: 

3688 for i in formats: 

3689 i = i.upper() 

3690 if i not in OPEN: 

3691 init() 

3692 try: 

3693 factory, accept = OPEN[i] 

3694 result = not accept or accept(prefix) 

3695 if isinstance(result, str): 

3696 warning_messages.append(result) 

3697 elif result: 

3698 fp.seek(0) 

3699 im = factory(fp, filename) 

3700 _decompression_bomb_check(im.size) 

3701 return im 

3702 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3703 if WARN_POSSIBLE_FORMATS: 

3704 warning_messages.append(i + " opening failed. " + str(e)) 

3705 except BaseException: 

3706 if exclusive_fp: 

3707 fp.close() 

3708 raise 

3709 return None 

3710 

3711 im = _open_core(fp, filename, prefix, formats) 

3712 

3713 if im is None and formats is ID: 

3714 # Try preinit (few common plugins) then init (all plugins) 

3715 for loader in (preinit, init): 

3716 checked_formats = ID.copy() 

3717 loader() 

3718 if formats != checked_formats: 

3719 im = _open_core( 

3720 fp, 

3721 filename, 

3722 prefix, 

3723 tuple(f for f in formats if f not in checked_formats), 

3724 ) 

3725 if im is not None: 

3726 break 

3727 

3728 if im: 

3729 im._exclusive_fp = exclusive_fp 

3730 return im 

3731 

3732 if exclusive_fp: 

3733 fp.close() 

3734 for message in warning_messages: 

3735 warnings.warn(message) 

3736 msg = "cannot identify image file %r" % (filename if filename else fp) 

3737 raise UnidentifiedImageError(msg) 

3738 

3739 

3740# 

3741# Image processing. 

3742 

3743 

3744def alpha_composite(im1: Image, im2: Image) -> Image: 

3745 """ 

3746 Alpha composite im2 over im1. 

3747 

3748 :param im1: The first image. Must have mode RGBA or LA. 

3749 :param im2: The second image. Must have the same mode and size as the first image. 

3750 :returns: An :py:class:`~PIL.Image.Image` object. 

3751 """ 

3752 

3753 im1.load() 

3754 im2.load() 

3755 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3756 

3757 

3758def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3759 """ 

3760 Creates a new image by interpolating between two input images, using 

3761 a constant alpha:: 

3762 

3763 out = image1 * (1.0 - alpha) + image2 * alpha 

3764 

3765 :param im1: The first image. 

3766 :param im2: The second image. Must have the same mode and size as 

3767 the first image. 

3768 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3769 copy of the first image is returned. If alpha is 1.0, a copy of 

3770 the second image is returned. There are no restrictions on the 

3771 alpha value. If necessary, the result is clipped to fit into 

3772 the allowed output range. 

3773 :returns: An :py:class:`~PIL.Image.Image` object. 

3774 """ 

3775 

3776 im1.load() 

3777 im2.load() 

3778 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3779 

3780 

3781def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3782 """ 

3783 Create composite image by blending images using a transparency mask. 

3784 

3785 :param image1: The first image. 

3786 :param image2: The second image. Must have the same mode and 

3787 size as the first image. 

3788 :param mask: A mask image. This image can have mode 

3789 "1", "L", or "RGBA", and must have the same size as the 

3790 other two images. 

3791 """ 

3792 

3793 image = image2.copy() 

3794 image.paste(image1, None, mask) 

3795 return image 

3796 

3797 

3798def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3799 """ 

3800 Applies the function (which should take one argument) to each pixel 

3801 in the given image. If the image has more than one band, the same 

3802 function is applied to each band. Note that the function is 

3803 evaluated once for each possible pixel value, so you cannot use 

3804 random components or other generators. 

3805 

3806 :param image: The input image. 

3807 :param function: A function object, taking one integer argument. 

3808 :returns: An :py:class:`~PIL.Image.Image` object. 

3809 """ 

3810 

3811 return image.point(args[0]) 

3812 

3813 

3814def merge(mode: str, bands: Sequence[Image]) -> Image: 

3815 """ 

3816 Merge a set of single band images into a new multiband image. 

3817 

3818 :param mode: The mode to use for the output image. See: 

3819 :ref:`concept-modes`. 

3820 :param bands: A sequence containing one single-band image for 

3821 each band in the output image. All bands must have the 

3822 same size. 

3823 :returns: An :py:class:`~PIL.Image.Image` object. 

3824 """ 

3825 

3826 if getmodebands(mode) != len(bands): 

3827 msg = "wrong number of bands" 

3828 raise ValueError(msg) 

3829 for band in bands[1:]: 

3830 if band.mode != getmodetype(mode): 

3831 msg = "mode mismatch" 

3832 raise ValueError(msg) 

3833 if band.size != bands[0].size: 

3834 msg = "size mismatch" 

3835 raise ValueError(msg) 

3836 for band in bands: 

3837 band.load() 

3838 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3839 

3840 

3841# -------------------------------------------------------------------- 

3842# Plugin registry 

3843 

3844 

3845def register_open( 

3846 id: str, 

3847 factory: ( 

3848 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3849 | type[ImageFile.ImageFile] 

3850 ), 

3851 accept: Callable[[bytes], bool | str] | None = None, 

3852) -> None: 

3853 """ 

3854 Register an image file plugin. This function should not be used 

3855 in application code. 

3856 

3857 :param id: An image format identifier. 

3858 :param factory: An image file factory method. 

3859 :param accept: An optional function that can be used to quickly 

3860 reject images having another format. 

3861 """ 

3862 id = id.upper() 

3863 if id not in ID: 

3864 ID.append(id) 

3865 OPEN[id] = factory, accept 

3866 

3867 

3868def register_mime(id: str, mimetype: str) -> None: 

3869 """ 

3870 Registers an image MIME type by populating ``Image.MIME``. This function 

3871 should not be used in application code. 

3872 

3873 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3874 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3875 provide a different result for specific images. 

3876 

3877 :param id: An image format identifier. 

3878 :param mimetype: The image MIME type for this format. 

3879 """ 

3880 MIME[id.upper()] = mimetype 

3881 

3882 

3883def register_save( 

3884 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3885) -> None: 

3886 """ 

3887 Registers an image save function. This function should not be 

3888 used in application code. 

3889 

3890 :param id: An image format identifier. 

3891 :param driver: A function to save images in this format. 

3892 """ 

3893 SAVE[id.upper()] = driver 

3894 

3895 

3896def register_save_all( 

3897 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3898) -> None: 

3899 """ 

3900 Registers an image function to save all the frames 

3901 of a multiframe format. This function should not be 

3902 used in application code. 

3903 

3904 :param id: An image format identifier. 

3905 :param driver: A function to save images in this format. 

3906 """ 

3907 SAVE_ALL[id.upper()] = driver 

3908 

3909 

3910def register_extension(id: str, extension: str) -> None: 

3911 """ 

3912 Registers an image extension. This function should not be 

3913 used in application code. 

3914 

3915 :param id: An image format identifier. 

3916 :param extension: An extension used for this format. 

3917 """ 

3918 EXTENSION[extension.lower()] = id.upper() 

3919 

3920 

3921def register_extensions(id: str, extensions: list[str]) -> None: 

3922 """ 

3923 Registers image extensions. This function should not be 

3924 used in application code. 

3925 

3926 :param id: An image format identifier. 

3927 :param extensions: A list of extensions used for this format. 

3928 """ 

3929 for extension in extensions: 

3930 register_extension(id, extension) 

3931 

3932 

3933def registered_extensions() -> dict[str, str]: 

3934 """ 

3935 Returns a dictionary containing all file extensions belonging 

3936 to registered plugins 

3937 """ 

3938 init() 

3939 return EXTENSION 

3940 

3941 

3942def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3943 """ 

3944 Registers an image decoder. This function should not be 

3945 used in application code. 

3946 

3947 :param name: The name of the decoder 

3948 :param decoder: An ImageFile.PyDecoder object 

3949 

3950 .. versionadded:: 4.1.0 

3951 """ 

3952 DECODERS[name] = decoder 

3953 

3954 

3955def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3956 """ 

3957 Registers an image encoder. This function should not be 

3958 used in application code. 

3959 

3960 :param name: The name of the encoder 

3961 :param encoder: An ImageFile.PyEncoder object 

3962 

3963 .. versionadded:: 4.1.0 

3964 """ 

3965 ENCODERS[name] = encoder 

3966 

3967 

3968# -------------------------------------------------------------------- 

3969# Effects 

3970 

3971 

3972def effect_mandelbrot( 

3973 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3974) -> Image: 

3975 """ 

3976 Generate a Mandelbrot set covering the given extent. 

3977 

3978 :param size: The requested size in pixels, as a 2-tuple: 

3979 (width, height). 

3980 :param extent: The extent to cover, as a 4-tuple: 

3981 (x0, y0, x1, y1). 

3982 :param quality: Quality. 

3983 """ 

3984 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3985 

3986 

3987def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3988 """ 

3989 Generate Gaussian noise centered around 128. 

3990 

3991 :param size: The requested size in pixels, as a 2-tuple: 

3992 (width, height). 

3993 :param sigma: Standard deviation of noise. 

3994 """ 

3995 return Image()._new(core.effect_noise(size, sigma)) 

3996 

3997 

3998def linear_gradient(mode: str) -> Image: 

3999 """ 

4000 Generate 256x256 linear gradient from black to white, top to bottom. 

4001 

4002 :param mode: Input mode. 

4003 """ 

4004 return Image()._new(core.linear_gradient(mode)) 

4005 

4006 

4007def radial_gradient(mode: str) -> Image: 

4008 """ 

4009 Generate 256x256 radial gradient from black to white, centre to edge. 

4010 

4011 :param mode: Input mode. 

4012 """ 

4013 return Image()._new(core.radial_gradient(mode)) 

4014 

4015 

4016# -------------------------------------------------------------------- 

4017# Resources 

4018 

4019 

4020def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

4021 env_dict = env if env is not None else os.environ 

4022 

4023 for var_name, setter in [ 

4024 ("PILLOW_ALIGNMENT", core.set_alignment), 

4025 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

4026 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

4027 ]: 

4028 if var_name not in env_dict: 

4029 continue 

4030 

4031 var = env_dict[var_name].lower() 

4032 

4033 units = 1 

4034 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

4035 if var.endswith(postfix): 

4036 units = mul 

4037 var = var[: -len(postfix)] 

4038 

4039 try: 

4040 var_int = int(var) * units 

4041 except ValueError: 

4042 warnings.warn(f"{var_name} is not int") 

4043 continue 

4044 

4045 try: 

4046 setter(var_int) 

4047 except ValueError as e: 

4048 warnings.warn(f"{var_name}: {e}") 

4049 

4050 

4051_apply_env_variables() 

4052atexit.register(core.clear_cache) 

4053 

4054 

4055if TYPE_CHECKING: 

4056 _ExifBase = MutableMapping[int, Any] 

4057else: 

4058 _ExifBase = MutableMapping 

4059 

4060 

4061class Exif(_ExifBase): 

4062 """ 

4063 This class provides read and write access to EXIF image data:: 

4064 

4065 from PIL import Image 

4066 im = Image.open("exif.png") 

4067 exif = im.getexif() # Returns an instance of this class 

4068 

4069 Information can be read and written, iterated over or deleted:: 

4070 

4071 print(exif[274]) # 1 

4072 exif[274] = 2 

4073 for k, v in exif.items(): 

4074 print("Tag", k, "Value", v) # Tag 274 Value 2 

4075 del exif[274] 

4076 

4077 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

4078 returns a dictionary:: 

4079 

4080 from PIL import ExifTags 

4081 im = Image.open("exif_gps.jpg") 

4082 exif = im.getexif() 

4083 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

4084 print(gps_ifd) 

4085 

4086 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

4087 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

4088 

4089 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

4090 

4091 print(exif[ExifTags.Base.Software]) # PIL 

4092 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

4093 """ 

4094 

4095 endian: str | None = None 

4096 bigtiff = False 

4097 _loaded = False 

4098 

4099 def __init__(self) -> None: 

4100 self._data: dict[int, Any] = {} 

4101 self._hidden_data: dict[int, Any] = {} 

4102 self._ifds: dict[int, dict[int, Any]] = {} 

4103 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

4104 self._loaded_exif: bytes | None = None 

4105 

4106 def _fixup(self, value: Any) -> Any: 

4107 try: 

4108 if len(value) == 1 and isinstance(value, tuple): 

4109 return value[0] 

4110 except Exception: 

4111 pass 

4112 return value 

4113 

4114 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

4115 # Helper function 

4116 # returns a dict with any single item tuples/lists as individual values 

4117 return {k: self._fixup(v) for k, v in src_dict.items()} 

4118 

4119 def _get_ifd_dict( 

4120 self, offset: int, group: int | None = None 

4121 ) -> dict[int, Any] | None: 

4122 try: 

4123 # an offset pointer to the location of the nested embedded IFD. 

4124 # It should be a long, but may be corrupted. 

4125 self.fp.seek(offset) 

4126 except (KeyError, TypeError): 

4127 return None 

4128 else: 

4129 from . import TiffImagePlugin 

4130 

4131 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

4132 info.load(self.fp) 

4133 return self._fixup_dict(dict(info)) 

4134 

4135 def _get_head(self) -> bytes: 

4136 version = b"\x2b" if self.bigtiff else b"\x2a" 

4137 if self.endian == "<": 

4138 head = b"II" + version + b"\x00" + o32le(8) 

4139 else: 

4140 head = b"MM\x00" + version + o32be(8) 

4141 if self.bigtiff: 

4142 head += o32le(8) if self.endian == "<" else o32be(8) 

4143 head += b"\x00\x00\x00\x00" 

4144 return head 

4145 

4146 def load(self, data: bytes) -> None: 

4147 # Extract EXIF information. This is highly experimental, 

4148 # and is likely to be replaced with something better in a future 

4149 # version. 

4150 

4151 # The EXIF record consists of a TIFF file embedded in a JPEG 

4152 # application marker (!). 

4153 if data == self._loaded_exif: 

4154 return 

4155 self._loaded_exif = data 

4156 self._data.clear() 

4157 self._hidden_data.clear() 

4158 self._ifds.clear() 

4159 while data and data.startswith(b"Exif\x00\x00"): 

4160 data = data[6:] 

4161 if not data: 

4162 self._info = None 

4163 return 

4164 

4165 self.fp: IO[bytes] = io.BytesIO(data) 

4166 self.head = self.fp.read(8) 

4167 # process dictionary 

4168 from . import TiffImagePlugin 

4169 

4170 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4171 self.endian = self._info._endian 

4172 self.fp.seek(self._info.next) 

4173 self._info.load(self.fp) 

4174 

4175 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4176 self._loaded_exif = None 

4177 self._data.clear() 

4178 self._hidden_data.clear() 

4179 self._ifds.clear() 

4180 

4181 # process dictionary 

4182 from . import TiffImagePlugin 

4183 

4184 self.fp = fp 

4185 if offset is not None: 

4186 self.head = self._get_head() 

4187 else: 

4188 self.head = self.fp.read(8) 

4189 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4190 if self.endian is None: 

4191 self.endian = self._info._endian 

4192 if offset is None: 

4193 offset = self._info.next 

4194 self.fp.tell() 

4195 self.fp.seek(offset) 

4196 self._info.load(self.fp) 

4197 

4198 def _get_merged_dict(self) -> dict[int, Any]: 

4199 merged_dict = dict(self) 

4200 

4201 # get EXIF extension 

4202 if ExifTags.IFD.Exif in self: 

4203 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4204 if ifd: 

4205 merged_dict.update(ifd) 

4206 

4207 # GPS 

4208 if ExifTags.IFD.GPSInfo in self: 

4209 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4210 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4211 ) 

4212 

4213 return merged_dict 

4214 

4215 def tobytes(self, offset: int = 8) -> bytes: 

4216 from . import TiffImagePlugin 

4217 

4218 head = self._get_head() 

4219 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4220 for tag, ifd_dict in self._ifds.items(): 

4221 if tag not in self: 

4222 ifd[tag] = ifd_dict 

4223 for tag, value in self.items(): 

4224 if tag in [ 

4225 ExifTags.IFD.Exif, 

4226 ExifTags.IFD.GPSInfo, 

4227 ] and not isinstance(value, dict): 

4228 value = self.get_ifd(tag) 

4229 if ( 

4230 tag == ExifTags.IFD.Exif 

4231 and ExifTags.IFD.Interop in value 

4232 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4233 ): 

4234 value = value.copy() 

4235 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4236 ifd[tag] = value 

4237 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4238 

4239 def get_ifd(self, tag: int) -> dict[int, Any]: 

4240 if tag not in self._ifds: 

4241 if tag == ExifTags.IFD.IFD1: 

4242 if self._info is not None and self._info.next != 0: 

4243 ifd = self._get_ifd_dict(self._info.next) 

4244 if ifd is not None: 

4245 self._ifds[tag] = ifd 

4246 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4247 offset = self._hidden_data.get(tag, self.get(tag)) 

4248 if offset is not None: 

4249 ifd = self._get_ifd_dict(offset, tag) 

4250 if ifd is not None: 

4251 self._ifds[tag] = ifd 

4252 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4253 if ExifTags.IFD.Exif not in self._ifds: 

4254 self.get_ifd(ExifTags.IFD.Exif) 

4255 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4256 if tag == ExifTags.IFD.MakerNote: 

4257 from .TiffImagePlugin import ImageFileDirectory_v2 

4258 

4259 try: 

4260 if tag_data.startswith(b"FUJIFILM"): 

4261 ifd_offset = i32le(tag_data, 8) 

4262 ifd_data = tag_data[ifd_offset:] 

4263 

4264 makernote = {} 

4265 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4266 ifd_tag, typ, count, data = struct.unpack( 

4267 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4268 ) 

4269 try: 

4270 ( 

4271 unit_size, 

4272 handler, 

4273 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4274 except KeyError: 

4275 continue 

4276 size = count * unit_size 

4277 if size > 4: 

4278 (offset,) = struct.unpack("<L", data) 

4279 data = ifd_data[offset - 12 : offset + size - 12] 

4280 else: 

4281 data = data[:size] 

4282 

4283 if len(data) != size: 

4284 warnings.warn( 

4285 "Possibly corrupt EXIF MakerNote data. " 

4286 f"Expecting to read {size} bytes but only got " 

4287 f"{len(data)}. Skipping tag {ifd_tag}" 

4288 ) 

4289 continue 

4290 

4291 if not data: 

4292 continue 

4293 

4294 makernote[ifd_tag] = handler( 

4295 ImageFileDirectory_v2(), data, False 

4296 ) 

4297 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4298 elif self.get(0x010F) == "Nintendo": 

4299 makernote = {} 

4300 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4301 ifd_tag, typ, count, data = struct.unpack( 

4302 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4303 ) 

4304 if ifd_tag == 0x1101: 

4305 # CameraInfo 

4306 (offset,) = struct.unpack(">L", data) 

4307 self.fp.seek(offset) 

4308 

4309 camerainfo: dict[str, int | bytes] = { 

4310 "ModelID": self.fp.read(4) 

4311 } 

4312 

4313 self.fp.read(4) 

4314 # Seconds since 2000 

4315 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4316 

4317 self.fp.read(4) 

4318 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4319 

4320 self.fp.read(12) 

4321 parallax = self.fp.read(4) 

4322 handler = ImageFileDirectory_v2._load_dispatch[ 

4323 TiffTags.FLOAT 

4324 ][1] 

4325 camerainfo["Parallax"] = handler( 

4326 ImageFileDirectory_v2(), parallax, False 

4327 )[0] 

4328 

4329 self.fp.read(4) 

4330 camerainfo["Category"] = self.fp.read(2) 

4331 

4332 makernote = {0x1101: camerainfo} 

4333 self._ifds[tag] = makernote 

4334 except struct.error: 

4335 pass 

4336 else: 

4337 # Interop 

4338 ifd = self._get_ifd_dict(tag_data, tag) 

4339 if ifd is not None: 

4340 self._ifds[tag] = ifd 

4341 ifd = self._ifds.setdefault(tag, {}) 

4342 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4343 ifd = { 

4344 k: v 

4345 for (k, v) in ifd.items() 

4346 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4347 } 

4348 return ifd 

4349 

4350 def hide_offsets(self) -> None: 

4351 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4352 if tag in self: 

4353 self._hidden_data[tag] = self[tag] 

4354 del self[tag] 

4355 

4356 def __str__(self) -> str: 

4357 if self._info is not None: 

4358 # Load all keys into self._data 

4359 for tag in self._info: 

4360 self[tag] 

4361 

4362 return str(self._data) 

4363 

4364 def __len__(self) -> int: 

4365 keys = set(self._data) 

4366 if self._info is not None: 

4367 keys.update(self._info) 

4368 return len(keys) 

4369 

4370 def __getitem__(self, tag: int) -> Any: 

4371 if self._info is not None and tag not in self._data and tag in self._info: 

4372 self._data[tag] = self._fixup(self._info[tag]) 

4373 del self._info[tag] 

4374 return self._data[tag] 

4375 

4376 def __contains__(self, tag: object) -> bool: 

4377 return tag in self._data or (self._info is not None and tag in self._info) 

4378 

4379 def __setitem__(self, tag: int, value: Any) -> None: 

4380 if self._info is not None and tag in self._info: 

4381 del self._info[tag] 

4382 self._data[tag] = value 

4383 

4384 def __delitem__(self, tag: int) -> None: 

4385 if self._info is not None and tag in self._info: 

4386 del self._info[tag] 

4387 else: 

4388 del self._data[tag] 

4389 if tag in self._ifds: 

4390 del self._ifds[tag] 

4391 

4392 def __iter__(self) -> Iterator[int]: 

4393 keys = set(self._data) 

4394 if self._info is not None: 

4395 keys.update(self._info) 

4396 return iter(keys)