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

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

1719 statements  

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# the Image class wrapper 

6# 

7# partial release history: 

8# 1995-09-09 fl Created 

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

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

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

12# 2000-06-07 fl PIL release 1.1 

13# 2000-10-20 fl PIL release 1.1.1 

14# 2001-05-07 fl PIL release 1.1.2 

15# 2002-03-15 fl PIL release 1.1.3 

16# 2003-05-10 fl PIL release 1.1.4 

17# 2005-03-28 fl PIL release 1.1.5 

18# 2006-12-02 fl PIL release 1.1.6 

19# 2009-11-15 fl PIL release 1.1.7 

20# 

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

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

23# 

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

25# 

26 

27from __future__ import annotations 

28 

29import abc 

30import atexit 

31import builtins 

32import io 

33import logging 

34import math 

35import os 

36import re 

37import struct 

38import sys 

39import tempfile 

40import warnings 

41from collections.abc import Callable, Iterator, MutableMapping, Sequence 

42from enum import IntEnum 

43from types import ModuleType 

44from typing import IO, Any, Literal, Protocol, cast 

45 

46# VERSION was removed in Pillow 6.0.0. 

47# PILLOW_VERSION was removed in Pillow 9.0.0. 

48# Use __version__ instead. 

49from . import ( 

50 ExifTags, 

51 ImageMode, 

52 TiffTags, 

53 UnidentifiedImageError, 

54 __version__, 

55 _plugins, 

56) 

57from ._binary import i32le, o32be, o32le 

58from ._deprecate import deprecate 

59from ._util import DeferredError, is_path 

60 

61ElementTree: ModuleType | None 

62try: 

63 from defusedxml import ElementTree 

64except ImportError: 

65 ElementTree = None 

66 

67logger = logging.getLogger(__name__) 

68 

69 

70class DecompressionBombWarning(RuntimeWarning): 

71 pass 

72 

73 

74class DecompressionBombError(Exception): 

75 pass 

76 

77 

78WARN_POSSIBLE_FORMATS: bool = False 

79 

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

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

82 

83 

84try: 

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

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

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

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

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

90 from . import _imaging as core 

91 

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

93 msg = ( 

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

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

96 f"Pillow version: {__version__}" 

97 ) 

98 raise ImportError(msg) 

99 

100except ImportError as v: 

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

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

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

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

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

106 # possible. 

107 warnings.warn( 

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

109 RuntimeWarning, 

110 ) 

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

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

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

114 # see docs/porting.rst 

115 raise 

116 

117 

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

119 """ 

120 Checks if an object is an image object. 

121 

122 .. warning:: 

123 

124 This function is for internal use only. 

125 

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

127 :returns: True if the object is an image 

128 """ 

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

130 return hasattr(t, "im") 

131 

132 

133# 

134# Constants 

135 

136 

137# transpose 

138class Transpose(IntEnum): 

139 FLIP_LEFT_RIGHT = 0 

140 FLIP_TOP_BOTTOM = 1 

141 ROTATE_90 = 2 

142 ROTATE_180 = 3 

143 ROTATE_270 = 4 

144 TRANSPOSE = 5 

145 TRANSVERSE = 6 

146 

147 

148# transforms (also defined in Imaging.h) 

149class Transform(IntEnum): 

150 AFFINE = 0 

151 EXTENT = 1 

152 PERSPECTIVE = 2 

153 QUAD = 3 

154 MESH = 4 

155 

156 

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

158class Resampling(IntEnum): 

159 NEAREST = 0 

160 BOX = 4 

161 BILINEAR = 2 

162 HAMMING = 5 

163 BICUBIC = 3 

164 LANCZOS = 1 

165 

166 

167_filters_support = { 

168 Resampling.BOX: 0.5, 

169 Resampling.BILINEAR: 1.0, 

170 Resampling.HAMMING: 1.0, 

171 Resampling.BICUBIC: 2.0, 

172 Resampling.LANCZOS: 3.0, 

173} 

174 

175 

176# dithers 

177class Dither(IntEnum): 

178 NONE = 0 

179 ORDERED = 1 # Not yet implemented 

180 RASTERIZE = 2 # Not yet implemented 

181 FLOYDSTEINBERG = 3 # default 

182 

183 

184# palettes/quantizers 

185class Palette(IntEnum): 

186 WEB = 0 

187 ADAPTIVE = 1 

188 

189 

190class Quantize(IntEnum): 

191 MEDIANCUT = 0 

192 MAXCOVERAGE = 1 

193 FASTOCTREE = 2 

194 LIBIMAGEQUANT = 3 

195 

196 

197module = sys.modules[__name__] 

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

199 for item in enum: 

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

201 

202 

203if hasattr(core, "DEFAULT_STRATEGY"): 

204 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY 

205 FILTERED = core.FILTERED 

206 HUFFMAN_ONLY = core.HUFFMAN_ONLY 

207 RLE = core.RLE 

208 FIXED = core.FIXED 

209 

210 

211# -------------------------------------------------------------------- 

212# Registries 

213 

214TYPE_CHECKING = False 

215if TYPE_CHECKING: 

216 import mmap 

217 from xml.etree.ElementTree import Element 

218 

219 from IPython.lib.pretty import PrettyPrinter 

220 

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

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

223ID: list[str] = [] 

224OPEN: dict[ 

225 str, 

226 tuple[ 

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

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

229 ], 

230] = {} 

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

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

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

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

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

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

237 

238# -------------------------------------------------------------------- 

239# Modes 

240 

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

242 

243 

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

245 m = ImageMode.getmode(im.mode) 

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

247 extra = len(m.bands) 

248 if extra != 1: 

249 shape += (extra,) 

250 return shape, m.typestr 

251 

252 

253MODES = [ 

254 "1", 

255 "CMYK", 

256 "F", 

257 "HSV", 

258 "I", 

259 "I;16", 

260 "I;16B", 

261 "I;16L", 

262 "I;16N", 

263 "L", 

264 "LA", 

265 "La", 

266 "LAB", 

267 "P", 

268 "PA", 

269 "RGB", 

270 "RGBA", 

271 "RGBa", 

272 "RGBX", 

273 "YCbCr", 

274] 

275 

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

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

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

279 

280 

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

282 """ 

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

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

285 contain color data. 

286 

287 :param mode: Input mode. 

288 :returns: "L" or "RGB". 

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

290 """ 

291 return ImageMode.getmode(mode).basemode 

292 

293 

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

295 """ 

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

297 single-layer mode suitable for storing individual bands. 

298 

299 :param mode: Input mode. 

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

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

302 """ 

303 return ImageMode.getmode(mode).basetype 

304 

305 

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

307 """ 

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

309 a tuple containing the names of individual bands (use 

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

311 individual band. 

312 

313 :param mode: Input mode. 

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

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

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

317 """ 

318 return ImageMode.getmode(mode).bands 

319 

320 

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

322 """ 

323 Gets the number of individual bands for this mode. 

324 

325 :param mode: Input mode. 

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

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

328 """ 

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

330 

331 

332# -------------------------------------------------------------------- 

333# Helpers 

334 

335_initialized = 0 

336 

337 

338def preinit() -> None: 

339 """ 

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

341 

342 It is called when opening or saving images. 

343 """ 

344 

345 global _initialized 

346 if _initialized >= 1: 

347 return 

348 

349 try: 

350 from . import BmpImagePlugin 

351 

352 assert BmpImagePlugin 

353 except ImportError: 

354 pass 

355 try: 

356 from . import GifImagePlugin 

357 

358 assert GifImagePlugin 

359 except ImportError: 

360 pass 

361 try: 

362 from . import JpegImagePlugin 

363 

364 assert JpegImagePlugin 

365 except ImportError: 

366 pass 

367 try: 

368 from . import PpmImagePlugin 

369 

370 assert PpmImagePlugin 

371 except ImportError: 

372 pass 

373 try: 

374 from . import PngImagePlugin 

375 

376 assert PngImagePlugin 

377 except ImportError: 

378 pass 

379 

380 _initialized = 1 

381 

382 

383def init() -> bool: 

384 """ 

385 Explicitly initializes the Python Imaging Library. This function 

386 loads all available file format drivers. 

387 

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

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

390 """ 

391 

392 global _initialized 

393 if _initialized >= 2: 

394 return False 

395 

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

397 for plugin in _plugins: 

398 try: 

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

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

401 except ImportError as e: 

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

403 

404 if OPEN or SAVE: 

405 _initialized = 2 

406 return True 

407 return False 

408 

409 

410# -------------------------------------------------------------------- 

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

412 

413 

414def _getdecoder( 

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

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

417 # tweak arguments 

418 if args is None: 

419 args = () 

420 elif not isinstance(args, tuple): 

421 args = (args,) 

422 

423 try: 

424 decoder = DECODERS[decoder_name] 

425 except KeyError: 

426 pass 

427 else: 

428 return decoder(mode, *args + extra) 

429 

430 try: 

431 # get decoder 

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

433 except AttributeError as e: 

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

435 raise OSError(msg) from e 

436 return decoder(mode, *args + extra) 

437 

438 

439def _getencoder( 

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

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

442 # tweak arguments 

443 if args is None: 

444 args = () 

445 elif not isinstance(args, tuple): 

446 args = (args,) 

447 

448 try: 

449 encoder = ENCODERS[encoder_name] 

450 except KeyError: 

451 pass 

452 else: 

453 return encoder(mode, *args + extra) 

454 

455 try: 

456 # get encoder 

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

458 except AttributeError as e: 

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

460 raise OSError(msg) from e 

461 return encoder(mode, *args + extra) 

462 

463 

464# -------------------------------------------------------------------- 

465# Simple expression analyzer 

466 

467 

468class ImagePointTransform: 

469 """ 

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

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

472 ``scale`` and ``offset`` is added. 

473 """ 

474 

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

476 self.scale = scale 

477 self.offset = offset 

478 

479 def __neg__(self) -> ImagePointTransform: 

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

481 

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

483 if isinstance(other, ImagePointTransform): 

484 return ImagePointTransform( 

485 self.scale + other.scale, self.offset + other.offset 

486 ) 

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

488 

489 __radd__ = __add__ 

490 

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

492 return self + -other 

493 

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

495 return other + -self 

496 

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

498 if isinstance(other, ImagePointTransform): 

499 return NotImplemented 

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

501 

502 __rmul__ = __mul__ 

503 

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

505 if isinstance(other, ImagePointTransform): 

506 return NotImplemented 

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

508 

509 

510def _getscaleoffset( 

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

512) -> tuple[float, float]: 

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

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

515 

516 

517# -------------------------------------------------------------------- 

518# Implementation wrapper 

519 

520 

521class SupportsGetData(Protocol): 

522 def getdata( 

523 self, 

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

525 

526 

527class Image: 

528 """ 

529 This class represents an image object. To create 

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

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

532 directly. 

533 

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

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

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

537 """ 

538 

539 format: str | None = None 

540 format_description: str | None = None 

541 _close_exclusive_fp_after_loading = True 

542 

543 def __init__(self) -> None: 

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

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

546 self._mode = "" 

547 self._size = (0, 0) 

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

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

550 self.readonly = 0 

551 self._exif: Exif | None = None 

552 

553 @property 

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

555 if isinstance(self._im, DeferredError): 

556 raise self._im.ex 

557 assert self._im is not None 

558 return self._im 

559 

560 @im.setter 

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

562 self._im = im 

563 

564 @property 

565 def width(self) -> int: 

566 return self.size[0] 

567 

568 @property 

569 def height(self) -> int: 

570 return self.size[1] 

571 

572 @property 

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

574 return self._size 

575 

576 @property 

577 def mode(self) -> str: 

578 return self._mode 

579 

580 @property 

581 def readonly(self) -> int: 

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

583 

584 @readonly.setter 

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

586 self._readonly = readonly 

587 

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

589 new = Image() 

590 new.im = im 

591 new._mode = im.mode 

592 new._size = im.size 

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

594 if self.palette: 

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

596 else: 

597 from . import ImagePalette 

598 

599 new.palette = ImagePalette.ImagePalette() 

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

601 return new 

602 

603 # Context manager support 

604 def __enter__(self): 

605 return self 

606 

607 def __exit__(self, *args): 

608 from . import ImageFile 

609 

610 if isinstance(self, ImageFile.ImageFile): 

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

612 self._close_fp() 

613 self.fp = None 

614 

615 def close(self) -> None: 

616 """ 

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

618 The image data will be unusable afterward. 

619 

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

621 have not had their file read and closed by the 

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

623 more information. 

624 """ 

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

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

627 self.map.close() 

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

629 

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

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

632 # object is gone. 

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

634 

635 def _copy(self) -> None: 

636 self.load() 

637 self.im = self.im.copy() 

638 self.readonly = 0 

639 

640 def _ensure_mutable(self) -> None: 

641 if self.readonly: 

642 self._copy() 

643 else: 

644 self.load() 

645 

646 def _dump( 

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

648 ) -> str: 

649 suffix = "" 

650 if format: 

651 suffix = f".{format}" 

652 

653 if not file: 

654 f, filename = tempfile.mkstemp(suffix) 

655 os.close(f) 

656 else: 

657 filename = file 

658 if not filename.endswith(suffix): 

659 filename = filename + suffix 

660 

661 self.load() 

662 

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

664 self.im.save_ppm(filename) 

665 else: 

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

667 

668 return filename 

669 

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

671 if self.__class__ is not other.__class__: 

672 return False 

673 assert isinstance(other, Image) 

674 return ( 

675 self.mode == other.mode 

676 and self.size == other.size 

677 and self.info == other.info 

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

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

680 ) 

681 

682 def __repr__(self) -> str: 

683 return ( 

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

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

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

687 ) 

688 

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

690 """IPython plain text display support""" 

691 

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

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

694 p.text( 

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

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

697 ) 

698 

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

700 """Helper function for iPython display hook. 

701 

702 :param image_format: Image format. 

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

704 """ 

705 b = io.BytesIO() 

706 try: 

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

708 except Exception: 

709 return None 

710 return b.getvalue() 

711 

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

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

714 

715 :returns: PNG version of the image as bytes 

716 """ 

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

718 

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

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

721 

722 :returns: JPEG version of the image as bytes 

723 """ 

724 return self._repr_image("JPEG") 

725 

726 @property 

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

728 # numpy array interface support 

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

730 if self.mode == "1": 

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

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

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

734 else: 

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

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

737 return new 

738 

739 def __arrow_c_schema__(self) -> object: 

740 self.load() 

741 return self.im.__arrow_c_schema__() 

742 

743 def __arrow_c_array__( 

744 self, requested_schema: object | None = None 

745 ) -> tuple[object, object]: 

746 self.load() 

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

748 

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

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

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

752 

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

754 Image.__init__(self) 

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

756 self.info = info 

757 self._mode = mode 

758 self._size = size 

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

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

761 self.putpalette(palette) 

762 self.frombytes(data) 

763 

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

765 """ 

766 Return image as a bytes object. 

767 

768 .. warning:: 

769 

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

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

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

773 

774 :param encoder_name: What encoder to use. 

775 

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

777 To see how this packs pixel data into the returned 

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

779 

780 A list of C encoders can be seen under codecs 

781 section of the function array in 

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

783 within the relevant plugins. 

784 :param args: Extra arguments to the encoder. 

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

786 """ 

787 

788 encoder_args: Any = args 

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

790 # may pass tuple instead of argument list 

791 encoder_args = encoder_args[0] 

792 

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

794 encoder_args = self.mode 

795 

796 self.load() 

797 

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

799 return b"" 

800 

801 # unpack data 

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

803 e.setimage(self.im) 

804 

805 from . import ImageFile 

806 

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

808 

809 output = [] 

810 while True: 

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

812 output.append(data) 

813 if errcode: 

814 break 

815 if errcode < 0: 

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

817 raise RuntimeError(msg) 

818 

819 return b"".join(output) 

820 

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

822 """ 

823 Returns the image converted to an X11 bitmap. 

824 

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

826 

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

828 :returns: A string containing an X11 bitmap. 

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

830 """ 

831 

832 self.load() 

833 if self.mode != "1": 

834 msg = "not a bitmap" 

835 raise ValueError(msg) 

836 data = self.tobytes("xbm") 

837 return b"".join( 

838 [ 

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

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

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

842 data, 

843 b"};", 

844 ] 

845 ) 

846 

847 def frombytes( 

848 self, 

849 data: bytes | bytearray | SupportsArrayInterface, 

850 decoder_name: str = "raw", 

851 *args: Any, 

852 ) -> None: 

853 """ 

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

855 

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

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

858 """ 

859 

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

861 return 

862 

863 decoder_args: Any = args 

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

865 # may pass tuple instead of argument list 

866 decoder_args = decoder_args[0] 

867 

868 # default format 

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

870 decoder_args = self.mode 

871 

872 # unpack data 

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

874 d.setimage(self.im) 

875 s = d.decode(data) 

876 

877 if s[0] >= 0: 

878 msg = "not enough image data" 

879 raise ValueError(msg) 

880 if s[1] != 0: 

881 msg = "cannot decode image data" 

882 raise ValueError(msg) 

883 

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

885 """ 

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

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

888 Image class automatically loads an opened image when it is 

889 accessed for the first time. 

890 

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

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

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

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

895 

896 :returns: An image access object. 

897 :rtype: :py:class:`.PixelAccess` 

898 """ 

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

900 # realize palette 

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

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

903 self.palette.dirty = 0 

904 self.palette.rawmode = None 

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

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

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

908 else: 

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

910 self.palette.mode = "RGBA" 

911 else: 

912 self.palette.palette = self.im.getpalette( 

913 self.palette.mode, self.palette.mode 

914 ) 

915 

916 if self._im is not None: 

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

918 return None 

919 

920 def verify(self) -> None: 

921 """ 

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

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

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

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

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

927 file. 

928 """ 

929 pass 

930 

931 def convert( 

932 self, 

933 mode: str | None = None, 

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

935 dither: Dither | None = None, 

936 palette: Palette = Palette.WEB, 

937 colors: int = 256, 

938 ) -> Image: 

939 """ 

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

941 method translates pixels through the palette. If mode is 

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

943 and the palette can be represented without a palette. 

944 

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

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

947 

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

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

950 

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

952 

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

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

955 dither to approximate the original image luminosity levels. If 

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

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

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

959 

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

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

962 and ``dither`` and ``palette`` are ignored. 

963 

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

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

966 

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

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

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

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

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

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

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

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

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

976 :data:`Palette.ADAPTIVE`. 

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

978 palette. Defaults to 256. 

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

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

981 """ 

982 

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

984 deprecate(mode, 12) 

985 

986 self.load() 

987 

988 has_transparency = "transparency" in self.info 

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

990 # determine default mode 

991 if self.palette: 

992 mode = self.palette.mode 

993 else: 

994 mode = "RGB" 

995 if mode == "RGB" and has_transparency: 

996 mode = "RGBA" 

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

998 return self.copy() 

999 

1000 if matrix: 

1001 # matrix conversion 

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

1003 msg = "illegal conversion" 

1004 raise ValueError(msg) 

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

1006 new_im = self._new(im) 

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

1008 transparency = new_im.info["transparency"] 

1009 

1010 def convert_transparency( 

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

1012 ) -> int: 

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

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

1015 

1016 if mode == "L": 

1017 transparency = convert_transparency(matrix, transparency) 

1018 elif len(mode) == 3: 

1019 transparency = tuple( 

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

1021 for i in range(len(transparency)) 

1022 ) 

1023 new_im.info["transparency"] = transparency 

1024 return new_im 

1025 

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

1027 return self.quantize(colors) 

1028 

1029 trns = None 

1030 delete_trns = False 

1031 # transparency handling 

1032 if has_transparency: 

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

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

1035 ): 

1036 # Use transparent conversion to promote from transparent 

1037 # color to an alpha channel. 

1038 new_im = self._new( 

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

1040 ) 

1041 del new_im.info["transparency"] 

1042 return new_im 

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

1044 t = self.info["transparency"] 

1045 if isinstance(t, bytes): 

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

1047 warnings.warn( 

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

1049 "converted to RGBA images" 

1050 ) 

1051 delete_trns = True 

1052 else: 

1053 # get the new transparency color. 

1054 # use existing conversions 

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

1056 if self.mode == "P": 

1057 assert self.palette is not None 

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

1059 if isinstance(t, tuple): 

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

1061 assert trns_im.palette is not None 

1062 try: 

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

1064 except ValueError as e: 

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

1066 # If all 256 colors are in use, 

1067 # then there is no need for transparency 

1068 t = None 

1069 else: 

1070 raise ValueError(err) from e 

1071 if t is None: 

1072 trns = None 

1073 else: 

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

1075 

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

1077 trns_im = trns_im.convert(mode) 

1078 else: 

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

1080 # after quantization. 

1081 trns_im = trns_im.convert("RGB") 

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

1083 

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

1085 t = self.info["transparency"] 

1086 delete_trns = True 

1087 

1088 if isinstance(t, bytes): 

1089 self.im.putpalettealphas(t) 

1090 elif isinstance(t, int): 

1091 self.im.putpalettealpha(t, 0) 

1092 else: 

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

1094 raise ValueError(msg) 

1095 

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

1097 im = self.im.quantize(colors) 

1098 new_im = self._new(im) 

1099 from . import ImagePalette 

1100 

1101 new_im.palette = ImagePalette.ImagePalette( 

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

1103 ) 

1104 if delete_trns: 

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

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

1107 del new_im.info["transparency"] 

1108 if trns is not None: 

1109 try: 

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

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

1112 new_im, 

1113 ) 

1114 except Exception: 

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

1116 # transparency hanging around to mess us up. 

1117 del new_im.info["transparency"] 

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

1119 return new_im 

1120 

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

1122 im = self 

1123 if mode == "LAB": 

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

1125 im = im.convert("RGBA") 

1126 other_mode = im.mode 

1127 else: 

1128 other_mode = mode 

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

1130 from . import ImageCms 

1131 

1132 srgb = ImageCms.createProfile("sRGB") 

1133 lab = ImageCms.createProfile("LAB") 

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

1135 transform = ImageCms.buildTransform( 

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

1137 ) 

1138 return transform.apply(im) 

1139 

1140 # colorspace conversion 

1141 if dither is None: 

1142 dither = Dither.FLOYDSTEINBERG 

1143 

1144 try: 

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

1146 except ValueError: 

1147 try: 

1148 # normalize source image and try again 

1149 modebase = getmodebase(self.mode) 

1150 if modebase == self.mode: 

1151 raise 

1152 im = self.im.convert(modebase) 

1153 im = im.convert(mode, dither) 

1154 except KeyError as e: 

1155 msg = "illegal conversion" 

1156 raise ValueError(msg) from e 

1157 

1158 new_im = self._new(im) 

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

1160 from . import ImagePalette 

1161 

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

1163 if delete_trns: 

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

1165 del new_im.info["transparency"] 

1166 if trns is not None: 

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

1168 try: 

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

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

1171 ) 

1172 except ValueError as e: 

1173 del new_im.info["transparency"] 

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

1175 # If all 256 colors are in use, 

1176 # then there is no need for transparency 

1177 warnings.warn( 

1178 "Couldn't allocate palette entry for transparency" 

1179 ) 

1180 else: 

1181 new_im.info["transparency"] = trns 

1182 return new_im 

1183 

1184 def quantize( 

1185 self, 

1186 colors: int = 256, 

1187 method: int | None = None, 

1188 kmeans: int = 0, 

1189 palette: Image | None = None, 

1190 dither: Dither = Dither.FLOYDSTEINBERG, 

1191 ) -> Image: 

1192 """ 

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

1194 of colors. 

1195 

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

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

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

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

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

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

1202 ``feature="libimagequant"``). 

1203 

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

1205 

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

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

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

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

1210 :param palette: Quantize to the palette of given 

1211 :py:class:`PIL.Image.Image`. 

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

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

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

1215 (default). 

1216 :returns: A new image 

1217 """ 

1218 

1219 self.load() 

1220 

1221 if method is None: 

1222 # defaults: 

1223 method = Quantize.MEDIANCUT 

1224 if self.mode == "RGBA": 

1225 method = Quantize.FASTOCTREE 

1226 

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

1228 Quantize.FASTOCTREE, 

1229 Quantize.LIBIMAGEQUANT, 

1230 ): 

1231 # Caller specified an invalid mode. 

1232 msg = ( 

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

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

1235 ) 

1236 raise ValueError(msg) 

1237 

1238 if palette: 

1239 # use palette from reference image 

1240 palette.load() 

1241 if palette.mode != "P": 

1242 msg = "bad mode for palette image" 

1243 raise ValueError(msg) 

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

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

1246 raise ValueError(msg) 

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

1248 new_im = self._new(im) 

1249 assert palette.palette is not None 

1250 new_im.palette = palette.palette.copy() 

1251 return new_im 

1252 

1253 if kmeans < 0: 

1254 msg = "kmeans must not be negative" 

1255 raise ValueError(msg) 

1256 

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

1258 

1259 from . import ImagePalette 

1260 

1261 mode = im.im.getpalettemode() 

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

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

1264 

1265 return im 

1266 

1267 def copy(self) -> Image: 

1268 """ 

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

1270 into an image, but still retain the original. 

1271 

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

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

1274 """ 

1275 self.load() 

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

1277 

1278 __copy__ = copy 

1279 

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

1281 """ 

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

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

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

1285 

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

1287 

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

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

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

1291 """ 

1292 

1293 if box is None: 

1294 return self.copy() 

1295 

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

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

1298 raise ValueError(msg) 

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

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

1301 raise ValueError(msg) 

1302 

1303 self.load() 

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

1305 

1306 def _crop( 

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

1308 ) -> core.ImagingCore: 

1309 """ 

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

1311 

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

1313 includes additional sanity checks. 

1314 

1315 :param im: a core image object 

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

1317 :returns: A core image object. 

1318 """ 

1319 

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

1321 

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

1323 

1324 _decompression_bomb_check(absolute_values) 

1325 

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

1327 

1328 def draft( 

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

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

1331 """ 

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

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

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

1335 JPEG to grayscale while loading it. 

1336 

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

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

1339 

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

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

1342 effect. 

1343 

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

1345 currently implemented only for JPEG and MPO images. 

1346 

1347 :param mode: The requested mode. 

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

1349 (width, height). 

1350 """ 

1351 pass 

1352 

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

1354 if ymargin is None: 

1355 ymargin = xmargin 

1356 self.load() 

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

1358 

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

1360 """ 

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

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

1363 

1364 :param filter: Filter kernel. 

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

1366 

1367 from . import ImageFilter 

1368 

1369 self.load() 

1370 

1371 if callable(filter): 

1372 filter = filter() 

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

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

1375 raise TypeError(msg) 

1376 

1377 multiband = isinstance(filter, ImageFilter.MultibandFilter) 

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

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

1380 

1381 ims = [ 

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

1383 ] 

1384 return merge(self.mode, ims) 

1385 

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

1387 """ 

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

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

1390 

1391 :returns: A tuple containing band names. 

1392 :rtype: tuple 

1393 """ 

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

1395 

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

1397 """ 

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

1399 image. 

1400 

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

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

1403 Otherwise, trim pixels when all channels are zero. 

1404 Keyword-only argument. 

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

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

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

1408 method returns None. 

1409 

1410 """ 

1411 

1412 self.load() 

1413 return self.im.getbbox(alpha_only) 

1414 

1415 def getcolors( 

1416 self, maxcolors: int = 256 

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

1418 """ 

1419 Returns a list of colors used in this image. 

1420 

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

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

1423 return the index of the color in the palette. 

1424 

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

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

1427 256 colors. 

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

1429 """ 

1430 

1431 self.load() 

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

1433 h = self.im.histogram() 

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

1435 if len(out) > maxcolors: 

1436 return None 

1437 return out 

1438 return self.im.getcolors(maxcolors) 

1439 

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

1441 """ 

1442 Returns the contents of this image as a sequence object 

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

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

1445 line zero, and so on. 

1446 

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

1448 internal PIL data type, which only supports certain sequence 

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

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

1451 

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

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

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

1455 :returns: A sequence-like object. 

1456 """ 

1457 

1458 self.load() 

1459 if band is not None: 

1460 return self.im.getband(band) 

1461 return self.im # could be abused 

1462 

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

1464 """ 

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

1466 the image. 

1467 

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

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

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

1471 """ 

1472 

1473 self.load() 

1474 if self.im.bands > 1: 

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

1476 return self.im.getextrema() 

1477 

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

1479 """ 

1480 Returns a dictionary containing the XMP tags. 

1481 Requires defusedxml to be installed. 

1482 

1483 :returns: XMP tags in a dictionary. 

1484 """ 

1485 

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

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

1488 

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

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

1491 children = list(element) 

1492 if children: 

1493 for child in children: 

1494 name = get_name(child.tag) 

1495 child_value = get_value(child) 

1496 if name in value: 

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

1498 value[name] = [value[name]] 

1499 value[name].append(child_value) 

1500 else: 

1501 value[name] = child_value 

1502 elif value: 

1503 if element.text: 

1504 value["text"] = element.text 

1505 else: 

1506 return element.text 

1507 return value 

1508 

1509 if ElementTree is None: 

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

1511 return {} 

1512 if "xmp" not in self.info: 

1513 return {} 

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

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

1516 

1517 def getexif(self) -> Exif: 

1518 """ 

1519 Gets EXIF data from the image. 

1520 

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

1522 """ 

1523 if self._exif is None: 

1524 self._exif = Exif() 

1525 elif self._exif._loaded: 

1526 return self._exif 

1527 self._exif._loaded = True 

1528 

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

1530 if exif_info is None: 

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

1532 exif_info = bytes.fromhex( 

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

1534 ) 

1535 elif hasattr(self, "tag_v2"): 

1536 self._exif.bigtiff = self.tag_v2._bigtiff 

1537 self._exif.endian = self.tag_v2._endian 

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

1539 if exif_info is not None: 

1540 self._exif.load(exif_info) 

1541 

1542 # XMP tags 

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

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

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

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

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

1548 if xmp_tags: 

1549 match = re.search(pattern, xmp_tags) 

1550 if match: 

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

1552 

1553 return self._exif 

1554 

1555 def _reload_exif(self) -> None: 

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

1557 return 

1558 self._exif._loaded = False 

1559 self.getexif() 

1560 

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

1562 from . import ImageFile 

1563 

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

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

1566 

1567 def getim(self) -> CapsuleType: 

1568 """ 

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

1570 

1571 :returns: A capsule object. 

1572 """ 

1573 

1574 self.load() 

1575 return self.im.ptr 

1576 

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

1578 """ 

1579 Returns the image palette as a list. 

1580 

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

1582 return the palette in its current mode. 

1583 

1584 .. versionadded:: 9.1.0 

1585 

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

1587 image has no palette. 

1588 """ 

1589 

1590 self.load() 

1591 try: 

1592 mode = self.im.getpalettemode() 

1593 except ValueError: 

1594 return None # no palette 

1595 if rawmode is None: 

1596 rawmode = mode 

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

1598 

1599 @property 

1600 def has_transparency_data(self) -> bool: 

1601 """ 

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

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

1604 in the info dictionary. 

1605 

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

1607 within are opaque. 

1608 

1609 :returns: A boolean. 

1610 """ 

1611 if ( 

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

1613 or "transparency" in self.info 

1614 ): 

1615 return True 

1616 if self.mode == "P": 

1617 assert self.palette is not None 

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

1619 return False 

1620 

1621 def apply_transparency(self) -> None: 

1622 """ 

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

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

1625 Otherwise, the image is unchanged. 

1626 """ 

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

1628 return 

1629 

1630 from . import ImagePalette 

1631 

1632 palette = self.getpalette("RGBA") 

1633 assert palette is not None 

1634 transparency = self.info["transparency"] 

1635 if isinstance(transparency, bytes): 

1636 for i, alpha in enumerate(transparency): 

1637 palette[i * 4 + 3] = alpha 

1638 else: 

1639 palette[transparency * 4 + 3] = 0 

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

1641 self.palette.dirty = 1 

1642 

1643 del self.info["transparency"] 

1644 

1645 def getpixel( 

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

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

1648 """ 

1649 Returns the pixel value at a given position. 

1650 

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

1652 :ref:`coordinate-system`. 

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

1654 this method returns a tuple. 

1655 """ 

1656 

1657 self.load() 

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

1659 

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

1661 """ 

1662 Get projection to x and y axes 

1663 

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

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

1666 """ 

1667 

1668 self.load() 

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

1670 return list(x), list(y) 

1671 

1672 def histogram( 

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

1674 ) -> list[int]: 

1675 """ 

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

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

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

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

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

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

1682 

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

1684 by this method. 

1685 

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

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

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

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

1690 

1691 :param mask: An optional mask. 

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

1693 :returns: A list containing pixel counts. 

1694 """ 

1695 self.load() 

1696 if mask: 

1697 mask.load() 

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

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

1700 return self.im.histogram( 

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

1702 ) 

1703 return self.im.histogram() 

1704 

1705 def entropy( 

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

1707 ) -> float: 

1708 """ 

1709 Calculates and returns the entropy for the image. 

1710 

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

1712 image by this method. 

1713 

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

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

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

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

1718 

1719 :param mask: An optional mask. 

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

1721 :returns: A float value representing the image entropy 

1722 """ 

1723 self.load() 

1724 if mask: 

1725 mask.load() 

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

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

1728 return self.im.entropy( 

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

1730 ) 

1731 return self.im.entropy() 

1732 

1733 def paste( 

1734 self, 

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

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

1737 mask: Image | None = None, 

1738 ) -> None: 

1739 """ 

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

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

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

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

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

1745 

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

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

1748 details). 

1749 

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

1751 containing pixel values. The method then fills the region 

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

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

1754 

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

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

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

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

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

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

1761 channels if they have them. 

1762 

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

1764 combine images with respect to their alpha channels. 

1765 

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

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

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

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

1770 upper left corner. 

1771 

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

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

1774 is interpreted as a mask image. 

1775 :param mask: An optional mask image. 

1776 """ 

1777 

1778 if isinstance(box, Image): 

1779 if mask is not None: 

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

1781 raise ValueError(msg) 

1782 # abbreviated paste(im, mask) syntax 

1783 mask = box 

1784 box = None 

1785 

1786 if box is None: 

1787 box = (0, 0) 

1788 

1789 if len(box) == 2: 

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

1791 if isinstance(im, Image): 

1792 size = im.size 

1793 elif isinstance(mask, Image): 

1794 size = mask.size 

1795 else: 

1796 # FIXME: use self.size here? 

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

1798 raise ValueError(msg) 

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

1800 

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

1802 if isinstance(im, str): 

1803 from . import ImageColor 

1804 

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

1806 elif isinstance(im, Image): 

1807 im.load() 

1808 if self.mode != im.mode: 

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

1810 # should use an adapter for this! 

1811 im = im.convert(self.mode) 

1812 source = im.im 

1813 else: 

1814 source = im 

1815 

1816 self._ensure_mutable() 

1817 

1818 if mask: 

1819 mask.load() 

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

1821 else: 

1822 self.im.paste(source, box) 

1823 

1824 def alpha_composite( 

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

1826 ) -> None: 

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

1828 onto this image. 

1829 

1830 :param im: image to composite over this one 

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

1832 left corner in this (destination) image. 

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

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

1835 bottom) for the bounds of the source rectangle 

1836 

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

1838 """ 

1839 

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

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

1842 raise ValueError(msg) 

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

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

1845 raise ValueError(msg) 

1846 

1847 if len(source) == 4: 

1848 overlay_crop_box = tuple(source) 

1849 elif len(source) == 2: 

1850 overlay_crop_box = tuple(source) + im.size 

1851 else: 

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

1853 raise ValueError(msg) 

1854 

1855 if not len(dest) == 2: 

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

1857 raise ValueError(msg) 

1858 if min(source) < 0: 

1859 msg = "Source must be non-negative" 

1860 raise ValueError(msg) 

1861 

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

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

1864 overlay = im 

1865 else: 

1866 overlay = im.crop(overlay_crop_box) 

1867 

1868 # target for the paste 

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

1870 

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

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

1873 background = self 

1874 else: 

1875 background = self.crop(box) 

1876 

1877 result = alpha_composite(background, overlay) 

1878 self.paste(result, box) 

1879 

1880 def point( 

1881 self, 

1882 lut: ( 

1883 Sequence[float] 

1884 | NumpyArray 

1885 | Callable[[int], float] 

1886 | Callable[[ImagePointTransform], ImagePointTransform | float] 

1887 | ImagePointHandler 

1888 ), 

1889 mode: str | None = None, 

1890 ) -> Image: 

1891 """ 

1892 Maps this image through a lookup table or function. 

1893 

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

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

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

1897 single argument. The function is called once for each 

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

1899 all bands of the image. 

1900 

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

1902 object:: 

1903 

1904 class Example(Image.ImagePointHandler): 

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

1906 # Return result 

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

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

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

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

1911 """ 

1912 

1913 self.load() 

1914 

1915 if isinstance(lut, ImagePointHandler): 

1916 return lut.point(self) 

1917 

1918 if callable(lut): 

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

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

1921 # check if the function can be used with point_transform 

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

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

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

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

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

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

1928 else: 

1929 flatLut = lut 

1930 

1931 if self.mode == "F": 

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

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

1934 raise ValueError(msg) 

1935 

1936 if mode != "F": 

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

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

1939 

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

1941 """ 

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

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

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

1945 

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

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

1948 """ 

1949 

1950 self._ensure_mutable() 

1951 

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

1953 # attempt to promote self to a matching alpha mode 

1954 try: 

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

1956 try: 

1957 self.im.setmode(mode) 

1958 except (AttributeError, ValueError) as e: 

1959 # do things the hard way 

1960 im = self.im.convert(mode) 

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

1962 msg = "alpha channel could not be added" 

1963 raise ValueError(msg) from e # sanity check 

1964 self.im = im 

1965 self._mode = self.im.mode 

1966 except KeyError as e: 

1967 msg = "illegal image mode" 

1968 raise ValueError(msg) from e 

1969 

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

1971 band = 1 

1972 else: 

1973 band = 3 

1974 

1975 if isinstance(alpha, Image): 

1976 # alpha layer 

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

1978 msg = "illegal image mode" 

1979 raise ValueError(msg) 

1980 alpha.load() 

1981 if alpha.mode == "1": 

1982 alpha = alpha.convert("L") 

1983 else: 

1984 # constant alpha 

1985 try: 

1986 self.im.fillband(band, alpha) 

1987 except (AttributeError, ValueError): 

1988 # do things the hard way 

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

1990 else: 

1991 return 

1992 

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

1994 

1995 def putdata( 

1996 self, 

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

1998 scale: float = 1.0, 

1999 offset: float = 0.0, 

2000 ) -> None: 

2001 """ 

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

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

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

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

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

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

2008 

2009 :param data: A flattened sequence object. 

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

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

2012 """ 

2013 

2014 self._ensure_mutable() 

2015 

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

2017 

2018 def putpalette( 

2019 self, 

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

2021 rawmode: str = "RGB", 

2022 ) -> None: 

2023 """ 

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

2025 or "LA" image. 

2026 

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

2028 integer value for each channel in the raw mode. 

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

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

2031 index in the 256 colors. 

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

2033 containing red, green, blue and alpha values. 

2034 

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

2036 

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

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

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

2040 """ 

2041 from . import ImagePalette 

2042 

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

2044 msg = "illegal image mode" 

2045 raise ValueError(msg) 

2046 if isinstance(data, ImagePalette.ImagePalette): 

2047 if data.rawmode is not None: 

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

2049 else: 

2050 palette = ImagePalette.ImagePalette(palette=data.palette) 

2051 palette.dirty = 1 

2052 else: 

2053 if not isinstance(data, bytes): 

2054 data = bytes(data) 

2055 palette = ImagePalette.raw(rawmode, data) 

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

2057 self.palette = palette 

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

2059 self.load() # install new palette 

2060 

2061 def putpixel( 

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

2063 ) -> None: 

2064 """ 

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

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

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

2068 accepted for P and PA images. 

2069 

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

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

2072 module instead. 

2073 

2074 See: 

2075 

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

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

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

2079 

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

2081 :ref:`coordinate-system`. 

2082 :param value: The pixel value. 

2083 """ 

2084 

2085 if self.readonly: 

2086 self._copy() 

2087 self.load() 

2088 

2089 if ( 

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

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

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

2093 ): 

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

2095 if self.mode == "PA": 

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

2097 value = value[:3] 

2098 assert self.palette is not None 

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

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

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

2102 

2103 def remap_palette( 

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

2105 ) -> Image: 

2106 """ 

2107 Rewrites the image to reorder the palette. 

2108 

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

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

2111 is the identity transform. 

2112 :param source_palette: Bytes or None. 

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

2114 

2115 """ 

2116 from . import ImagePalette 

2117 

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

2119 msg = "illegal image mode" 

2120 raise ValueError(msg) 

2121 

2122 bands = 3 

2123 palette_mode = "RGB" 

2124 if source_palette is None: 

2125 if self.mode == "P": 

2126 self.load() 

2127 palette_mode = self.im.getpalettemode() 

2128 if palette_mode == "RGBA": 

2129 bands = 4 

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

2131 else: # L-mode 

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

2133 elif len(source_palette) > 768: 

2134 bands = 4 

2135 palette_mode = "RGBA" 

2136 

2137 palette_bytes = b"" 

2138 new_positions = [0] * 256 

2139 

2140 # pick only the used colors from the palette 

2141 for i, oldPosition in enumerate(dest_map): 

2142 palette_bytes += source_palette[ 

2143 oldPosition * bands : oldPosition * bands + bands 

2144 ] 

2145 new_positions[oldPosition] = i 

2146 

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

2148 

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

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

2151 # from palette 1 to palette 2. New_positions is 

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

2153 # palette 1 with any holes removed. 

2154 

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

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

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

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

2159 # sans palette thus converting the image bytes, then 

2160 # assigning the optimized RGB palette. 

2161 

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

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

2164 

2165 mapping_palette = bytearray(new_positions) 

2166 

2167 m_im = self.copy() 

2168 m_im._mode = "P" 

2169 

2170 m_im.palette = ImagePalette.ImagePalette( 

2171 palette_mode, palette=mapping_palette * bands 

2172 ) 

2173 # possibly set palette dirty, then 

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

2175 # or just force it. 

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

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

2178 

2179 m_im = m_im.convert("L") 

2180 

2181 m_im.putpalette(palette_bytes, palette_mode) 

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

2183 

2184 if "transparency" in self.info: 

2185 try: 

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

2187 except ValueError: 

2188 if "transparency" in m_im.info: 

2189 del m_im.info["transparency"] 

2190 

2191 return m_im 

2192 

2193 def _get_safe_box( 

2194 self, 

2195 size: tuple[int, int], 

2196 resample: Resampling, 

2197 box: tuple[float, float, float, float], 

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

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

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

2201 """ 

2202 filter_support = _filters_support[resample] - 0.5 

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

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

2205 support_x = filter_support * scale_x 

2206 support_y = filter_support * scale_y 

2207 

2208 return ( 

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

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

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

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

2213 ) 

2214 

2215 def resize( 

2216 self, 

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

2218 resample: int | None = None, 

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

2220 reducing_gap: float | None = None, 

2221 ) -> Image: 

2222 """ 

2223 Returns a resized copy of this image. 

2224 

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

2226 (width, height). 

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

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

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

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

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

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

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

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

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

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

2237 the source image region to be scaled. 

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

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

2240 :param reducing_gap: Apply optimization by resizing the image 

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

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

2243 Second, resizing using regular resampling. The last step 

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

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

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

2247 the closer the result to the fair resampling. 

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

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

2250 indistinguishable from fair resampling in most cases. 

2251 The default value is None (no optimization). 

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

2253 """ 

2254 

2255 if resample is None: 

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

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

2258 elif resample not in ( 

2259 Resampling.NEAREST, 

2260 Resampling.BILINEAR, 

2261 Resampling.BICUBIC, 

2262 Resampling.LANCZOS, 

2263 Resampling.BOX, 

2264 Resampling.HAMMING, 

2265 ): 

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

2267 

2268 filters = [ 

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

2270 for filter in ( 

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

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

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

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

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

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

2277 ) 

2278 ] 

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

2280 raise ValueError(msg) 

2281 

2282 if reducing_gap is not None and reducing_gap < 1.0: 

2283 msg = "reducing_gap must be 1.0 or greater" 

2284 raise ValueError(msg) 

2285 

2286 if box is None: 

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

2288 

2289 size = tuple(size) 

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

2291 return self.copy() 

2292 

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

2294 resample = Resampling.NEAREST 

2295 

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

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

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

2299 return im.convert(self.mode) 

2300 

2301 self.load() 

2302 

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

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

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

2306 if factor_x > 1 or factor_y > 1: 

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

2308 factor = (factor_x, factor_y) 

2309 self = ( 

2310 self.reduce(factor, box=reduce_box) 

2311 if callable(self.reduce) 

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

2313 ) 

2314 box = ( 

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

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

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

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

2319 ) 

2320 

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

2322 

2323 def reduce( 

2324 self, 

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

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

2327 ) -> Image: 

2328 """ 

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

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

2331 the resulting size will be rounded up. 

2332 

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

2334 for width and height separately. 

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

2336 the source image region to be reduced. 

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

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

2339 """ 

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

2341 factor = (factor, factor) 

2342 

2343 if box is None: 

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

2345 

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

2347 return self.copy() 

2348 

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

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

2351 im = im.reduce(factor, box) 

2352 return im.convert(self.mode) 

2353 

2354 self.load() 

2355 

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

2357 

2358 def rotate( 

2359 self, 

2360 angle: float, 

2361 resample: Resampling = Resampling.NEAREST, 

2362 expand: int | bool = False, 

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

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

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

2366 ) -> Image: 

2367 """ 

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

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

2370 clockwise around its centre. 

2371 

2372 :param angle: In degrees counter clockwise. 

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

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

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

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

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

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

2379 See :ref:`concept-filters`. 

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

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

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

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

2384 the center and no translation. 

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

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

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

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

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

2390 """ 

2391 

2392 angle = angle % 360.0 

2393 

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

2395 # translating or changing the center. 

2396 if not (center or translate): 

2397 if angle == 0: 

2398 return self.copy() 

2399 if angle == 180: 

2400 return self.transpose(Transpose.ROTATE_180) 

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

2402 return self.transpose( 

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

2404 ) 

2405 

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

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

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

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

2410 

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

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

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

2414 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) 

2415 

2416 # The reverse matrix is thus: 

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

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

2419 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) 

2420 

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

2422 # compensate for the expand flag. 

2423 

2424 w, h = self.size 

2425 

2426 if translate is None: 

2427 post_trans = (0, 0) 

2428 else: 

2429 post_trans = translate 

2430 if center is None: 

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

2432 

2433 angle = -math.radians(angle) 

2434 matrix = [ 

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

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

2437 0.0, 

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

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

2440 0.0, 

2441 ] 

2442 

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

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

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

2446 

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

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

2449 ) 

2450 matrix[2] += center[0] 

2451 matrix[5] += center[1] 

2452 

2453 if expand: 

2454 # calculate output size 

2455 xx = [] 

2456 yy = [] 

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

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

2459 xx.append(transformed_x) 

2460 yy.append(transformed_y) 

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

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

2463 

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

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

2466 # translation vector as new translation vector. 

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

2468 w, h = nw, nh 

2469 

2470 return self.transform( 

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

2472 ) 

2473 

2474 def save( 

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

2476 ) -> None: 

2477 """ 

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

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

2480 extension, if possible. 

2481 

2482 Keyword options can be used to provide additional instructions 

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

2484 silently ignored. The available options are described in the 

2485 :doc:`image format documentation 

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

2487 

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

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

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

2491 methods, and be opened in binary mode. 

2492 

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

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

2495 format to use is determined from the filename extension. 

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

2497 parameter should always be used. 

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

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

2500 saving multiple images:: 

2501 

2502 # Saving XMP data to a single image 

2503 from PIL import Image 

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

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

2506 

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

2508 from PIL import Image 

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

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

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

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

2513 :returns: None 

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

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

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

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

2518 """ 

2519 

2520 filename: str | bytes = "" 

2521 open_fp = False 

2522 if is_path(fp): 

2523 filename = os.fspath(fp) 

2524 open_fp = True 

2525 elif fp == sys.stdout: 

2526 try: 

2527 fp = sys.stdout.buffer 

2528 except AttributeError: 

2529 pass 

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

2531 # only set the name for metadata purposes 

2532 filename = os.fspath(fp.name) 

2533 

2534 preinit() 

2535 

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

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

2538 

2539 if not format: 

2540 if ext not in EXTENSION: 

2541 init() 

2542 try: 

2543 format = EXTENSION[ext] 

2544 except KeyError as e: 

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

2546 raise ValueError(msg) from e 

2547 

2548 from . import ImageFile 

2549 

2550 # may mutate self! 

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

2552 filename 

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

2554 self._ensure_mutable() 

2555 else: 

2556 self.load() 

2557 

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

2559 self._default_encoderinfo = params 

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

2561 self._attach_default_encoderinfo(self) 

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

2563 

2564 if format.upper() not in SAVE: 

2565 init() 

2566 if save_all or ( 

2567 save_all is None 

2568 and params.get("append_images") 

2569 and format.upper() in SAVE_ALL 

2570 ): 

2571 save_handler = SAVE_ALL[format.upper()] 

2572 else: 

2573 save_handler = SAVE[format.upper()] 

2574 

2575 created = False 

2576 if open_fp: 

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

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

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

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

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

2582 else: 

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

2584 else: 

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

2586 

2587 try: 

2588 save_handler(self, fp, filename) 

2589 except Exception: 

2590 if open_fp: 

2591 fp.close() 

2592 if created: 

2593 try: 

2594 os.remove(filename) 

2595 except PermissionError: 

2596 pass 

2597 raise 

2598 finally: 

2599 self.encoderinfo = encoderinfo 

2600 if open_fp: 

2601 fp.close() 

2602 

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

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

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

2606 return encoderinfo 

2607 

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

2609 """ 

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

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

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

2613 library automatically seeks to frame 0. 

2614 

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

2616 

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

2618 number of available frames. 

2619 

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

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

2622 of the sequence. 

2623 """ 

2624 

2625 # overridden by file handlers 

2626 if frame != 0: 

2627 msg = "no more images in file" 

2628 raise EOFError(msg) 

2629 

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

2631 """ 

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

2633 

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

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

2636 

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

2638 PNG format. 

2639 

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

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

2642 

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

2644 

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

2646 

2647 :param title: Optional title to use for the image window, where possible. 

2648 """ 

2649 

2650 _show(self, title=title) 

2651 

2652 def split(self) -> tuple[Image, ...]: 

2653 """ 

2654 Split this image into individual bands. This method returns a 

2655 tuple of individual image bands from an image. For example, 

2656 splitting an "RGB" image creates three new images each 

2657 containing a copy of one of the original bands (red, green, 

2658 blue). 

2659 

2660 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel` 

2661 method can be more convenient and faster. 

2662 

2663 :returns: A tuple containing bands. 

2664 """ 

2665 

2666 self.load() 

2667 if self.im.bands == 1: 

2668 return (self.copy(),) 

2669 return tuple(map(self._new, self.im.split())) 

2670 

2671 def getchannel(self, channel: int | str) -> Image: 

2672 """ 

2673 Returns an image containing a single channel of the source image. 

2674 

2675 :param channel: What channel to return. Could be index 

2676 (0 for "R" channel of "RGB") or channel name 

2677 ("A" for alpha channel of "RGBA"). 

2678 :returns: An image in "L" mode. 

2679 

2680 .. versionadded:: 4.3.0 

2681 """ 

2682 self.load() 

2683 

2684 if isinstance(channel, str): 

2685 try: 

2686 channel = self.getbands().index(channel) 

2687 except ValueError as e: 

2688 msg = f'The image has no channel "{channel}"' 

2689 raise ValueError(msg) from e 

2690 

2691 return self._new(self.im.getband(channel)) 

2692 

2693 def tell(self) -> int: 

2694 """ 

2695 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. 

2696 

2697 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the 

2698 number of available frames. 

2699 

2700 :returns: Frame number, starting with 0. 

2701 """ 

2702 return 0 

2703 

2704 def thumbnail( 

2705 self, 

2706 size: tuple[float, float], 

2707 resample: Resampling = Resampling.BICUBIC, 

2708 reducing_gap: float | None = 2.0, 

2709 ) -> None: 

2710 """ 

2711 Make this image into a thumbnail. This method modifies the 

2712 image to contain a thumbnail version of itself, no larger than 

2713 the given size. This method calculates an appropriate thumbnail 

2714 size to preserve the aspect of the image, calls the 

2715 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader 

2716 (where applicable), and finally resizes the image. 

2717 

2718 Note that this function modifies the :py:class:`~PIL.Image.Image` 

2719 object in place. If you need to use the full resolution image as well, 

2720 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original 

2721 image. 

2722 

2723 :param size: The requested size in pixels, as a 2-tuple: 

2724 (width, height). 

2725 :param resample: Optional resampling filter. This can be one 

2726 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, 

2727 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, 

2728 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. 

2729 If omitted, it defaults to :py:data:`Resampling.BICUBIC`. 

2730 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0). 

2731 See: :ref:`concept-filters`. 

2732 :param reducing_gap: Apply optimization by resizing the image 

2733 in two steps. First, reducing the image by integer times 

2734 using :py:meth:`~PIL.Image.Image.reduce` or 

2735 :py:meth:`~PIL.Image.Image.draft` for JPEG images. 

2736 Second, resizing using regular resampling. The last step 

2737 changes size no less than by ``reducing_gap`` times. 

2738 ``reducing_gap`` may be None (no first step is performed) 

2739 or should be greater than 1.0. The bigger ``reducing_gap``, 

2740 the closer the result to the fair resampling. 

2741 The smaller ``reducing_gap``, the faster resizing. 

2742 With ``reducing_gap`` greater or equal to 3.0, the result is 

2743 indistinguishable from fair resampling in most cases. 

2744 The default value is 2.0 (very close to fair resampling 

2745 while still being faster in many cases). 

2746 :returns: None 

2747 """ 

2748 

2749 provided_size = tuple(map(math.floor, size)) 

2750 

2751 def preserve_aspect_ratio() -> tuple[int, int] | None: 

2752 def round_aspect(number: float, key: Callable[[int], float]) -> int: 

2753 return max(min(math.floor(number), math.ceil(number), key=key), 1) 

2754 

2755 x, y = provided_size 

2756 if x >= self.width and y >= self.height: 

2757 return None 

2758 

2759 aspect = self.width / self.height 

2760 if x / y >= aspect: 

2761 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) 

2762 else: 

2763 y = round_aspect( 

2764 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n) 

2765 ) 

2766 return x, y 

2767 

2768 preserved_size = preserve_aspect_ratio() 

2769 if preserved_size is None: 

2770 return 

2771 final_size = preserved_size 

2772 

2773 box = None 

2774 if reducing_gap is not None: 

2775 res = self.draft( 

2776 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) 

2777 ) 

2778 if res is not None: 

2779 box = res[1] 

2780 

2781 if self.size != final_size: 

2782 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) 

2783 

2784 self.im = im.im 

2785 self._size = final_size 

2786 self._mode = self.im.mode 

2787 

2788 self.readonly = 0 

2789 

2790 # FIXME: the different transform methods need further explanation 

2791 # instead of bloating the method docs, add a separate chapter. 

2792 def transform( 

2793 self, 

2794 size: tuple[int, int], 

2795 method: Transform | ImageTransformHandler | SupportsGetData, 

2796 data: Sequence[Any] | None = None, 

2797 resample: int = Resampling.NEAREST, 

2798 fill: int = 1, 

2799 fillcolor: float | tuple[float, ...] | str | None = None, 

2800 ) -> Image: 

2801 """ 

2802 Transforms this image. This method creates a new image with the 

2803 given size, and the same mode as the original, and copies data 

2804 to the new image using the given transform. 

2805 

2806 :param size: The output size in pixels, as a 2-tuple: 

2807 (width, height). 

2808 :param method: The transformation method. This is one of 

2809 :py:data:`Transform.EXTENT` (cut out a rectangular subregion), 

2810 :py:data:`Transform.AFFINE` (affine transform), 

2811 :py:data:`Transform.PERSPECTIVE` (perspective transform), 

2812 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or 

2813 :py:data:`Transform.MESH` (map a number of source quadrilaterals 

2814 in one operation). 

2815 

2816 It may also be an :py:class:`~PIL.Image.ImageTransformHandler` 

2817 object:: 

2818 

2819 class Example(Image.ImageTransformHandler): 

2820 def transform(self, size, data, resample, fill=1): 

2821 # Return result 

2822 

2823 Implementations of :py:class:`~PIL.Image.ImageTransformHandler` 

2824 for some of the :py:class:`Transform` methods are provided 

2825 in :py:mod:`~PIL.ImageTransform`. 

2826 

2827 It may also be an object with a ``method.getdata`` method 

2828 that returns a tuple supplying new ``method`` and ``data`` values:: 

2829 

2830 class Example: 

2831 def getdata(self): 

2832 method = Image.Transform.EXTENT 

2833 data = (0, 0, 100, 100) 

2834 return method, data 

2835 :param data: Extra data to the transformation method. 

2836 :param resample: Optional resampling filter. It can be one of 

2837 :py:data:`Resampling.NEAREST` (use nearest neighbour), 

2838 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 

2839 environment), or :py:data:`Resampling.BICUBIC` (cubic spline 

2840 interpolation in a 4x4 environment). If omitted, or if the image 

2841 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. 

2842 See: :ref:`concept-filters`. 

2843 :param fill: If ``method`` is an 

2844 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of 

2845 the arguments passed to it. Otherwise, it is unused. 

2846 :param fillcolor: Optional fill color for the area outside the 

2847 transform in the output image. 

2848 :returns: An :py:class:`~PIL.Image.Image` object. 

2849 """ 

2850 

2851 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: 

2852 return ( 

2853 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) 

2854 .transform(size, method, data, resample, fill, fillcolor) 

2855 .convert(self.mode) 

2856 ) 

2857 

2858 if isinstance(method, ImageTransformHandler): 

2859 return method.transform(size, self, resample=resample, fill=fill) 

2860 

2861 if hasattr(method, "getdata"): 

2862 # compatibility w. old-style transform objects 

2863 method, data = method.getdata() 

2864 

2865 if data is None: 

2866 msg = "missing method data" 

2867 raise ValueError(msg) 

2868 

2869 im = new(self.mode, size, fillcolor) 

2870 if self.mode == "P" and self.palette: 

2871 im.palette = self.palette.copy() 

2872 im.info = self.info.copy() 

2873 if method == Transform.MESH: 

2874 # list of quads 

2875 for box, quad in data: 

2876 im.__transformer( 

2877 box, self, Transform.QUAD, quad, resample, fillcolor is None 

2878 ) 

2879 else: 

2880 im.__transformer( 

2881 (0, 0) + size, self, method, data, resample, fillcolor is None 

2882 ) 

2883 

2884 return im 

2885 

2886 def __transformer( 

2887 self, 

2888 box: tuple[int, int, int, int], 

2889 image: Image, 

2890 method: Transform, 

2891 data: Sequence[float], 

2892 resample: int = Resampling.NEAREST, 

2893 fill: bool = True, 

2894 ) -> None: 

2895 w = box[2] - box[0] 

2896 h = box[3] - box[1] 

2897 

2898 if method == Transform.AFFINE: 

2899 data = data[:6] 

2900 

2901 elif method == Transform.EXTENT: 

2902 # convert extent to an affine transform 

2903 x0, y0, x1, y1 = data 

2904 xs = (x1 - x0) / w 

2905 ys = (y1 - y0) / h 

2906 method = Transform.AFFINE 

2907 data = (xs, 0, x0, 0, ys, y0) 

2908 

2909 elif method == Transform.PERSPECTIVE: 

2910 data = data[:8] 

2911 

2912 elif method == Transform.QUAD: 

2913 # quadrilateral warp. data specifies the four corners 

2914 # given as NW, SW, SE, and NE. 

2915 nw = data[:2] 

2916 sw = data[2:4] 

2917 se = data[4:6] 

2918 ne = data[6:8] 

2919 x0, y0 = nw 

2920 As = 1.0 / w 

2921 At = 1.0 / h 

2922 data = ( 

2923 x0, 

2924 (ne[0] - x0) * As, 

2925 (sw[0] - x0) * At, 

2926 (se[0] - sw[0] - ne[0] + x0) * As * At, 

2927 y0, 

2928 (ne[1] - y0) * As, 

2929 (sw[1] - y0) * At, 

2930 (se[1] - sw[1] - ne[1] + y0) * As * At, 

2931 ) 

2932 

2933 else: 

2934 msg = "unknown transformation method" 

2935 raise ValueError(msg) 

2936 

2937 if resample not in ( 

2938 Resampling.NEAREST, 

2939 Resampling.BILINEAR, 

2940 Resampling.BICUBIC, 

2941 ): 

2942 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): 

2943 unusable: dict[int, str] = { 

2944 Resampling.BOX: "Image.Resampling.BOX", 

2945 Resampling.HAMMING: "Image.Resampling.HAMMING", 

2946 Resampling.LANCZOS: "Image.Resampling.LANCZOS", 

2947 } 

2948 msg = unusable[resample] + f" ({resample}) cannot be used." 

2949 else: 

2950 msg = f"Unknown resampling filter ({resample})." 

2951 

2952 filters = [ 

2953 f"{filter[1]} ({filter[0]})" 

2954 for filter in ( 

2955 (Resampling.NEAREST, "Image.Resampling.NEAREST"), 

2956 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), 

2957 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), 

2958 ) 

2959 ] 

2960 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" 

2961 raise ValueError(msg) 

2962 

2963 image.load() 

2964 

2965 self.load() 

2966 

2967 if image.mode in ("1", "P"): 

2968 resample = Resampling.NEAREST 

2969 

2970 self.im.transform(box, image.im, method, data, resample, fill) 

2971 

2972 def transpose(self, method: Transpose) -> Image: 

2973 """ 

2974 Transpose image (flip or rotate in 90 degree steps) 

2975 

2976 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, 

2977 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, 

2978 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, 

2979 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. 

2980 :returns: Returns a flipped or rotated copy of this image. 

2981 """ 

2982 

2983 self.load() 

2984 return self._new(self.im.transpose(method)) 

2985 

2986 def effect_spread(self, distance: int) -> Image: 

2987 """ 

2988 Randomly spread pixels in an image. 

2989 

2990 :param distance: Distance to spread pixels. 

2991 """ 

2992 self.load() 

2993 return self._new(self.im.effect_spread(distance)) 

2994 

2995 def toqimage(self) -> ImageQt.ImageQt: 

2996 """Returns a QImage copy of this image""" 

2997 from . import ImageQt 

2998 

2999 if not ImageQt.qt_is_installed: 

3000 msg = "Qt bindings are not installed" 

3001 raise ImportError(msg) 

3002 return ImageQt.toqimage(self) 

3003 

3004 def toqpixmap(self) -> ImageQt.QPixmap: 

3005 """Returns a QPixmap copy of this image""" 

3006 from . import ImageQt 

3007 

3008 if not ImageQt.qt_is_installed: 

3009 msg = "Qt bindings are not installed" 

3010 raise ImportError(msg) 

3011 return ImageQt.toqpixmap(self) 

3012 

3013 

3014# -------------------------------------------------------------------- 

3015# Abstract handlers. 

3016 

3017 

3018class ImagePointHandler(abc.ABC): 

3019 """ 

3020 Used as a mixin by point transforms 

3021 (for use with :py:meth:`~PIL.Image.Image.point`) 

3022 """ 

3023 

3024 @abc.abstractmethod 

3025 def point(self, im: Image) -> Image: 

3026 pass 

3027 

3028 

3029class ImageTransformHandler(abc.ABC): 

3030 """ 

3031 Used as a mixin by geometry transforms 

3032 (for use with :py:meth:`~PIL.Image.Image.transform`) 

3033 """ 

3034 

3035 @abc.abstractmethod 

3036 def transform( 

3037 self, 

3038 size: tuple[int, int], 

3039 image: Image, 

3040 **options: Any, 

3041 ) -> Image: 

3042 pass 

3043 

3044 

3045# -------------------------------------------------------------------- 

3046# Factories 

3047 

3048 

3049def _check_size(size: Any) -> None: 

3050 """ 

3051 Common check to enforce type and sanity check on size tuples 

3052 

3053 :param size: Should be a 2 tuple of (width, height) 

3054 :returns: None, or raises a ValueError 

3055 """ 

3056 

3057 if not isinstance(size, (list, tuple)): 

3058 msg = "Size must be a list or tuple" 

3059 raise ValueError(msg) 

3060 if len(size) != 2: 

3061 msg = "Size must be a sequence of length 2" 

3062 raise ValueError(msg) 

3063 if size[0] < 0 or size[1] < 0: 

3064 msg = "Width and height must be >= 0" 

3065 raise ValueError(msg) 

3066 

3067 

3068def new( 

3069 mode: str, 

3070 size: tuple[int, int] | list[int], 

3071 color: float | tuple[float, ...] | str | None = 0, 

3072) -> Image: 

3073 """ 

3074 Creates a new image with the given mode and size. 

3075 

3076 :param mode: The mode to use for the new image. See: 

3077 :ref:`concept-modes`. 

3078 :param size: A 2-tuple, containing (width, height) in pixels. 

3079 :param color: What color to use for the image. Default is black. 

3080 If given, this should be a single integer or floating point value 

3081 for single-band modes, and a tuple for multi-band modes (one value 

3082 per band). When creating RGB or HSV images, you can also use color 

3083 strings as supported by the ImageColor module. If the color is 

3084 None, the image is not initialised. 

3085 :returns: An :py:class:`~PIL.Image.Image` object. 

3086 """ 

3087 

3088 if mode in ("BGR;15", "BGR;16", "BGR;24"): 

3089 deprecate(mode, 12) 

3090 

3091 _check_size(size) 

3092 

3093 if color is None: 

3094 # don't initialize 

3095 return Image()._new(core.new(mode, size)) 

3096 

3097 if isinstance(color, str): 

3098 # css3-style specifier 

3099 

3100 from . import ImageColor 

3101 

3102 color = ImageColor.getcolor(color, mode) 

3103 

3104 im = Image() 

3105 if ( 

3106 mode == "P" 

3107 and isinstance(color, (list, tuple)) 

3108 and all(isinstance(i, int) for i in color) 

3109 ): 

3110 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) 

3111 if len(color_ints) == 3 or len(color_ints) == 4: 

3112 # RGB or RGBA value for a P image 

3113 from . import ImagePalette 

3114 

3115 im.palette = ImagePalette.ImagePalette() 

3116 color = im.palette.getcolor(color_ints) 

3117 return im._new(core.fill(mode, size, color)) 

3118 

3119 

3120def frombytes( 

3121 mode: str, 

3122 size: tuple[int, int], 

3123 data: bytes | bytearray | SupportsArrayInterface, 

3124 decoder_name: str = "raw", 

3125 *args: Any, 

3126) -> Image: 

3127 """ 

3128 Creates a copy of an image memory from pixel data in a buffer. 

3129 

3130 In its simplest form, this function takes three arguments 

3131 (mode, size, and unpacked pixel data). 

3132 

3133 You can also use any pixel decoder supported by PIL. For more 

3134 information on available decoders, see the section 

3135 :ref:`Writing Your Own File Codec <file-codecs>`. 

3136 

3137 Note that this function decodes pixel data only, not entire images. 

3138 If you have an entire image in a string, wrap it in a 

3139 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load 

3140 it. 

3141 

3142 :param mode: The image mode. See: :ref:`concept-modes`. 

3143 :param size: The image size. 

3144 :param data: A byte buffer containing raw data for the given mode. 

3145 :param decoder_name: What decoder to use. 

3146 :param args: Additional parameters for the given decoder. 

3147 :returns: An :py:class:`~PIL.Image.Image` object. 

3148 """ 

3149 

3150 _check_size(size) 

3151 

3152 im = new(mode, size) 

3153 if im.width != 0 and im.height != 0: 

3154 decoder_args: Any = args 

3155 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): 

3156 # may pass tuple instead of argument list 

3157 decoder_args = decoder_args[0] 

3158 

3159 if decoder_name == "raw" and decoder_args == (): 

3160 decoder_args = mode 

3161 

3162 im.frombytes(data, decoder_name, decoder_args) 

3163 return im 

3164 

3165 

3166def frombuffer( 

3167 mode: str, 

3168 size: tuple[int, int], 

3169 data: bytes | SupportsArrayInterface, 

3170 decoder_name: str = "raw", 

3171 *args: Any, 

3172) -> Image: 

3173 """ 

3174 Creates an image memory referencing pixel data in a byte buffer. 

3175 

3176 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data 

3177 in the byte buffer, where possible. This means that changes to the 

3178 original buffer object are reflected in this image). Not all modes can 

3179 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". 

3180 

3181 Note that this function decodes pixel data only, not entire images. 

3182 If you have an entire image file in a string, wrap it in a 

3183 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. 

3184 

3185 The default parameters used for the "raw" decoder differs from that used for 

3186 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a 

3187 future release. The current release issues a warning if you do this; to disable 

3188 the warning, you should provide the full set of parameters. See below for details. 

3189 

3190 :param mode: The image mode. See: :ref:`concept-modes`. 

3191 :param size: The image size. 

3192 :param data: A bytes or other buffer object containing raw 

3193 data for the given mode. 

3194 :param decoder_name: What decoder to use. 

3195 :param args: Additional parameters for the given decoder. For the 

3196 default encoder ("raw"), it's recommended that you provide the 

3197 full set of parameters:: 

3198 

3199 frombuffer(mode, size, data, "raw", mode, 0, 1) 

3200 

3201 :returns: An :py:class:`~PIL.Image.Image` object. 

3202 

3203 .. versionadded:: 1.1.4 

3204 """ 

3205 

3206 _check_size(size) 

3207 

3208 # may pass tuple instead of argument list 

3209 if len(args) == 1 and isinstance(args[0], tuple): 

3210 args = args[0] 

3211 

3212 if decoder_name == "raw": 

3213 if args == (): 

3214 args = mode, 0, 1 

3215 if args[0] in _MAPMODES: 

3216 im = new(mode, (0, 0)) 

3217 im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) 

3218 if mode == "P": 

3219 from . import ImagePalette 

3220 

3221 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) 

3222 im.readonly = 1 

3223 return im 

3224 

3225 return frombytes(mode, size, data, decoder_name, args) 

3226 

3227 

3228class SupportsArrayInterface(Protocol): 

3229 """ 

3230 An object that has an ``__array_interface__`` dictionary. 

3231 """ 

3232 

3233 @property 

3234 def __array_interface__(self) -> dict[str, Any]: 

3235 raise NotImplementedError() 

3236 

3237 

3238class SupportsArrowArrayInterface(Protocol): 

3239 """ 

3240 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c 

3241 data interface. 

3242 """ 

3243 

3244 def __arrow_c_array__( 

3245 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 

3246 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 

3247 raise NotImplementedError() 

3248 

3249 

3250def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: 

3251 """ 

3252 Creates an image memory from an object exporting the array interface 

3253 (using the buffer protocol):: 

3254 

3255 from PIL import Image 

3256 import numpy as np 

3257 a = np.zeros((5, 5)) 

3258 im = Image.fromarray(a) 

3259 

3260 If ``obj`` is not contiguous, then the ``tobytes`` method is called 

3261 and :py:func:`~PIL.Image.frombuffer` is used. 

3262 

3263 In the case of NumPy, be aware that Pillow modes do not always correspond 

3264 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, 

3265 32-bit signed integer pixels, and 32-bit floating point pixels. 

3266 

3267 Pillow images can also be converted to arrays:: 

3268 

3269 from PIL import Image 

3270 import numpy as np 

3271 im = Image.open("hopper.jpg") 

3272 a = np.asarray(im) 

3273 

3274 When converting Pillow images to arrays however, only pixel values are 

3275 transferred. This means that P and PA mode images will lose their palette. 

3276 

3277 :param obj: Object with array interface 

3278 :param mode: Optional mode to use when reading ``obj``. Will be determined from 

3279 type if ``None``. Deprecated. 

3280 

3281 This will not be used to convert the data after reading, but will be used to 

3282 change how the data is read:: 

3283 

3284 from PIL import Image 

3285 import numpy as np 

3286 a = np.full((1, 1), 300) 

3287 im = Image.fromarray(a, mode="L") 

3288 im.getpixel((0, 0)) # 44 

3289 im = Image.fromarray(a, mode="RGB") 

3290 im.getpixel((0, 0)) # (44, 1, 0) 

3291 

3292 See: :ref:`concept-modes` for general information about modes. 

3293 :returns: An image object. 

3294 

3295 .. versionadded:: 1.1.6 

3296 """ 

3297 arr = obj.__array_interface__ 

3298 shape = arr["shape"] 

3299 ndim = len(shape) 

3300 strides = arr.get("strides", None) 

3301 if mode is None: 

3302 try: 

3303 typekey = (1, 1) + shape[2:], arr["typestr"] 

3304 except KeyError as e: 

3305 msg = "Cannot handle this data type" 

3306 raise TypeError(msg) from e 

3307 try: 

3308 mode, rawmode = _fromarray_typemap[typekey] 

3309 except KeyError as e: 

3310 typekey_shape, typestr = typekey 

3311 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" 

3312 raise TypeError(msg) from e 

3313 else: 

3314 deprecate("'mode' parameter", 13) 

3315 rawmode = mode 

3316 if mode in ["1", "L", "I", "P", "F"]: 

3317 ndmax = 2 

3318 elif mode == "RGB": 

3319 ndmax = 3 

3320 else: 

3321 ndmax = 4 

3322 if ndim > ndmax: 

3323 msg = f"Too many dimensions: {ndim} > {ndmax}." 

3324 raise ValueError(msg) 

3325 

3326 size = 1 if ndim == 1 else shape[1], shape[0] 

3327 if strides is not None: 

3328 if hasattr(obj, "tobytes"): 

3329 obj = obj.tobytes() 

3330 elif hasattr(obj, "tostring"): 

3331 obj = obj.tostring() 

3332 else: 

3333 msg = "'strides' requires either tobytes() or tostring()" 

3334 raise ValueError(msg) 

3335 

3336 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) 

3337 

3338 

3339def fromarrow( 

3340 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] 

3341) -> Image: 

3342 """Creates an image with zero-copy shared memory from an object exporting 

3343 the arrow_c_array interface protocol:: 

3344 

3345 from PIL import Image 

3346 import pyarrow as pa 

3347 arr = pa.array([0]*(5*5*4), type=pa.uint8()) 

3348 im = Image.fromarrow(arr, 'RGBA', (5, 5)) 

3349 

3350 If the data representation of the ``obj`` is not compatible with 

3351 Pillow internal storage, a ValueError is raised. 

3352 

3353 Pillow images can also be converted to Arrow objects:: 

3354 

3355 from PIL import Image 

3356 import pyarrow as pa 

3357 im = Image.open('hopper.jpg') 

3358 arr = pa.array(im) 

3359 

3360 As with array support, when converting Pillow images to arrays, 

3361 only pixel values are transferred. This means that P and PA mode 

3362 images will lose their palette. 

3363 

3364 :param obj: Object with an arrow_c_array interface 

3365 :param mode: Image mode. 

3366 :param size: Image size. This must match the storage of the arrow object. 

3367 :returns: An Image object 

3368 

3369 Note that according to the Arrow spec, both the producer and the 

3370 consumer should consider the exported array to be immutable, as 

3371 unsynchronized updates will potentially cause inconsistent data. 

3372 

3373 See: :ref:`arrow-support` for more detailed information 

3374 

3375 .. versionadded:: 11.2.1 

3376 

3377 """ 

3378 if not hasattr(obj, "__arrow_c_array__"): 

3379 msg = "arrow_c_array interface not found" 

3380 raise ValueError(msg) 

3381 

3382 (schema_capsule, array_capsule) = obj.__arrow_c_array__() 

3383 _im = core.new_arrow(mode, size, schema_capsule, array_capsule) 

3384 if _im: 

3385 return Image()._new(_im) 

3386 

3387 msg = "new_arrow returned None without an exception" 

3388 raise ValueError(msg) 

3389 

3390 

3391def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: 

3392 """Creates an image instance from a QImage image""" 

3393 from . import ImageQt 

3394 

3395 if not ImageQt.qt_is_installed: 

3396 msg = "Qt bindings are not installed" 

3397 raise ImportError(msg) 

3398 return ImageQt.fromqimage(im) 

3399 

3400 

3401def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: 

3402 """Creates an image instance from a QPixmap image""" 

3403 from . import ImageQt 

3404 

3405 if not ImageQt.qt_is_installed: 

3406 msg = "Qt bindings are not installed" 

3407 raise ImportError(msg) 

3408 return ImageQt.fromqpixmap(im) 

3409 

3410 

3411_fromarray_typemap = { 

3412 # (shape, typestr) => mode, rawmode 

3413 # first two members of shape are set to one 

3414 ((1, 1), "|b1"): ("1", "1;8"), 

3415 ((1, 1), "|u1"): ("L", "L"), 

3416 ((1, 1), "|i1"): ("I", "I;8"), 

3417 ((1, 1), "<u2"): ("I", "I;16"), 

3418 ((1, 1), ">u2"): ("I", "I;16B"), 

3419 ((1, 1), "<i2"): ("I", "I;16S"), 

3420 ((1, 1), ">i2"): ("I", "I;16BS"), 

3421 ((1, 1), "<u4"): ("I", "I;32"), 

3422 ((1, 1), ">u4"): ("I", "I;32B"), 

3423 ((1, 1), "<i4"): ("I", "I;32S"), 

3424 ((1, 1), ">i4"): ("I", "I;32BS"), 

3425 ((1, 1), "<f4"): ("F", "F;32F"), 

3426 ((1, 1), ">f4"): ("F", "F;32BF"), 

3427 ((1, 1), "<f8"): ("F", "F;64F"), 

3428 ((1, 1), ">f8"): ("F", "F;64BF"), 

3429 ((1, 1, 2), "|u1"): ("LA", "LA"), 

3430 ((1, 1, 3), "|u1"): ("RGB", "RGB"), 

3431 ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), 

3432 # shortcuts: 

3433 ((1, 1), f"{_ENDIAN}i4"): ("I", "I"), 

3434 ((1, 1), f"{_ENDIAN}f4"): ("F", "F"), 

3435} 

3436 

3437 

3438def _decompression_bomb_check(size: tuple[int, int]) -> None: 

3439 if MAX_IMAGE_PIXELS is None: 

3440 return 

3441 

3442 pixels = max(1, size[0]) * max(1, size[1]) 

3443 

3444 if pixels > 2 * MAX_IMAGE_PIXELS: 

3445 msg = ( 

3446 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " 

3447 "pixels, could be decompression bomb DOS attack." 

3448 ) 

3449 raise DecompressionBombError(msg) 

3450 

3451 if pixels > MAX_IMAGE_PIXELS: 

3452 warnings.warn( 

3453 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " 

3454 "could be decompression bomb DOS attack.", 

3455 DecompressionBombWarning, 

3456 ) 

3457 

3458 

3459def open( 

3460 fp: StrOrBytesPath | IO[bytes], 

3461 mode: Literal["r"] = "r", 

3462 formats: list[str] | tuple[str, ...] | None = None, 

3463) -> ImageFile.ImageFile: 

3464 """ 

3465 Opens and identifies the given image file. 

3466 

3467 This is a lazy operation; this function identifies the file, but 

3468 the file remains open and the actual image data is not read from 

3469 the file until you try to process the data (or call the 

3470 :py:meth:`~PIL.Image.Image.load` method). See 

3471 :py:func:`~PIL.Image.new`. See :ref:`file-handling`. 

3472 

3473 :param fp: A filename (string), os.PathLike object or a file object. 

3474 The file object must implement ``file.read``, 

3475 ``file.seek``, and ``file.tell`` methods, 

3476 and be opened in binary mode. The file object will also seek to zero 

3477 before reading. 

3478 :param mode: The mode. If given, this argument must be "r". 

3479 :param formats: A list or tuple of formats to attempt to load the file in. 

3480 This can be used to restrict the set of formats checked. 

3481 Pass ``None`` to try all supported formats. You can print the set of 

3482 available formats by running ``python3 -m PIL`` or using 

3483 the :py:func:`PIL.features.pilinfo` function. 

3484 :returns: An :py:class:`~PIL.Image.Image` object. 

3485 :exception FileNotFoundError: If the file cannot be found. 

3486 :exception PIL.UnidentifiedImageError: If the image cannot be opened and 

3487 identified. 

3488 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` 

3489 instance is used for ``fp``. 

3490 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. 

3491 """ 

3492 

3493 if mode != "r": 

3494 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] 

3495 raise ValueError(msg) 

3496 elif isinstance(fp, io.StringIO): 

3497 msg = ( # type: ignore[unreachable] 

3498 "StringIO cannot be used to open an image. " 

3499 "Binary data must be used instead." 

3500 ) 

3501 raise ValueError(msg) 

3502 

3503 if formats is None: 

3504 formats = ID 

3505 elif not isinstance(formats, (list, tuple)): 

3506 msg = "formats must be a list or tuple" # type: ignore[unreachable] 

3507 raise TypeError(msg) 

3508 

3509 exclusive_fp = False 

3510 filename: str | bytes = "" 

3511 if is_path(fp): 

3512 filename = os.fspath(fp) 

3513 fp = builtins.open(filename, "rb") 

3514 exclusive_fp = True 

3515 else: 

3516 fp = cast(IO[bytes], fp) 

3517 

3518 try: 

3519 fp.seek(0) 

3520 except (AttributeError, io.UnsupportedOperation): 

3521 fp = io.BytesIO(fp.read()) 

3522 exclusive_fp = True 

3523 

3524 prefix = fp.read(16) 

3525 

3526 preinit() 

3527 

3528 warning_messages: list[str] = [] 

3529 

3530 def _open_core( 

3531 fp: IO[bytes], 

3532 filename: str | bytes, 

3533 prefix: bytes, 

3534 formats: list[str] | tuple[str, ...], 

3535 ) -> ImageFile.ImageFile | None: 

3536 for i in formats: 

3537 i = i.upper() 

3538 if i not in OPEN: 

3539 init() 

3540 try: 

3541 factory, accept = OPEN[i] 

3542 result = not accept or accept(prefix) 

3543 if isinstance(result, str): 

3544 warning_messages.append(result) 

3545 elif result: 

3546 fp.seek(0) 

3547 im = factory(fp, filename) 

3548 _decompression_bomb_check(im.size) 

3549 return im 

3550 except (SyntaxError, IndexError, TypeError, struct.error) as e: 

3551 if WARN_POSSIBLE_FORMATS: 

3552 warning_messages.append(i + " opening failed. " + str(e)) 

3553 except BaseException: 

3554 if exclusive_fp: 

3555 fp.close() 

3556 raise 

3557 return None 

3558 

3559 im = _open_core(fp, filename, prefix, formats) 

3560 

3561 if im is None and formats is ID: 

3562 checked_formats = ID.copy() 

3563 if init(): 

3564 im = _open_core( 

3565 fp, 

3566 filename, 

3567 prefix, 

3568 tuple(format for format in formats if format not in checked_formats), 

3569 ) 

3570 

3571 if im: 

3572 im._exclusive_fp = exclusive_fp 

3573 return im 

3574 

3575 if exclusive_fp: 

3576 fp.close() 

3577 for message in warning_messages: 

3578 warnings.warn(message) 

3579 msg = "cannot identify image file %r" % (filename if filename else fp) 

3580 raise UnidentifiedImageError(msg) 

3581 

3582 

3583# 

3584# Image processing. 

3585 

3586 

3587def alpha_composite(im1: Image, im2: Image) -> Image: 

3588 """ 

3589 Alpha composite im2 over im1. 

3590 

3591 :param im1: The first image. Must have mode RGBA. 

3592 :param im2: The second image. Must have mode RGBA, and the same size as 

3593 the first image. 

3594 :returns: An :py:class:`~PIL.Image.Image` object. 

3595 """ 

3596 

3597 im1.load() 

3598 im2.load() 

3599 return im1._new(core.alpha_composite(im1.im, im2.im)) 

3600 

3601 

3602def blend(im1: Image, im2: Image, alpha: float) -> Image: 

3603 """ 

3604 Creates a new image by interpolating between two input images, using 

3605 a constant alpha:: 

3606 

3607 out = image1 * (1.0 - alpha) + image2 * alpha 

3608 

3609 :param im1: The first image. 

3610 :param im2: The second image. Must have the same mode and size as 

3611 the first image. 

3612 :param alpha: The interpolation alpha factor. If alpha is 0.0, a 

3613 copy of the first image is returned. If alpha is 1.0, a copy of 

3614 the second image is returned. There are no restrictions on the 

3615 alpha value. If necessary, the result is clipped to fit into 

3616 the allowed output range. 

3617 :returns: An :py:class:`~PIL.Image.Image` object. 

3618 """ 

3619 

3620 im1.load() 

3621 im2.load() 

3622 return im1._new(core.blend(im1.im, im2.im, alpha)) 

3623 

3624 

3625def composite(image1: Image, image2: Image, mask: Image) -> Image: 

3626 """ 

3627 Create composite image by blending images using a transparency mask. 

3628 

3629 :param image1: The first image. 

3630 :param image2: The second image. Must have the same mode and 

3631 size as the first image. 

3632 :param mask: A mask image. This image can have mode 

3633 "1", "L", or "RGBA", and must have the same size as the 

3634 other two images. 

3635 """ 

3636 

3637 image = image2.copy() 

3638 image.paste(image1, None, mask) 

3639 return image 

3640 

3641 

3642def eval(image: Image, *args: Callable[[int], float]) -> Image: 

3643 """ 

3644 Applies the function (which should take one argument) to each pixel 

3645 in the given image. If the image has more than one band, the same 

3646 function is applied to each band. Note that the function is 

3647 evaluated once for each possible pixel value, so you cannot use 

3648 random components or other generators. 

3649 

3650 :param image: The input image. 

3651 :param function: A function object, taking one integer argument. 

3652 :returns: An :py:class:`~PIL.Image.Image` object. 

3653 """ 

3654 

3655 return image.point(args[0]) 

3656 

3657 

3658def merge(mode: str, bands: Sequence[Image]) -> Image: 

3659 """ 

3660 Merge a set of single band images into a new multiband image. 

3661 

3662 :param mode: The mode to use for the output image. See: 

3663 :ref:`concept-modes`. 

3664 :param bands: A sequence containing one single-band image for 

3665 each band in the output image. All bands must have the 

3666 same size. 

3667 :returns: An :py:class:`~PIL.Image.Image` object. 

3668 """ 

3669 

3670 if getmodebands(mode) != len(bands) or "*" in mode: 

3671 msg = "wrong number of bands" 

3672 raise ValueError(msg) 

3673 for band in bands[1:]: 

3674 if band.mode != getmodetype(mode): 

3675 msg = "mode mismatch" 

3676 raise ValueError(msg) 

3677 if band.size != bands[0].size: 

3678 msg = "size mismatch" 

3679 raise ValueError(msg) 

3680 for band in bands: 

3681 band.load() 

3682 return bands[0]._new(core.merge(mode, *[b.im for b in bands])) 

3683 

3684 

3685# -------------------------------------------------------------------- 

3686# Plugin registry 

3687 

3688 

3689def register_open( 

3690 id: str, 

3691 factory: ( 

3692 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] 

3693 | type[ImageFile.ImageFile] 

3694 ), 

3695 accept: Callable[[bytes], bool | str] | None = None, 

3696) -> None: 

3697 """ 

3698 Register an image file plugin. This function should not be used 

3699 in application code. 

3700 

3701 :param id: An image format identifier. 

3702 :param factory: An image file factory method. 

3703 :param accept: An optional function that can be used to quickly 

3704 reject images having another format. 

3705 """ 

3706 id = id.upper() 

3707 if id not in ID: 

3708 ID.append(id) 

3709 OPEN[id] = factory, accept 

3710 

3711 

3712def register_mime(id: str, mimetype: str) -> None: 

3713 """ 

3714 Registers an image MIME type by populating ``Image.MIME``. This function 

3715 should not be used in application code. 

3716 

3717 ``Image.MIME`` provides a mapping from image format identifiers to mime 

3718 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can 

3719 provide a different result for specific images. 

3720 

3721 :param id: An image format identifier. 

3722 :param mimetype: The image MIME type for this format. 

3723 """ 

3724 MIME[id.upper()] = mimetype 

3725 

3726 

3727def register_save( 

3728 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3729) -> None: 

3730 """ 

3731 Registers an image save function. This function should not be 

3732 used in application code. 

3733 

3734 :param id: An image format identifier. 

3735 :param driver: A function to save images in this format. 

3736 """ 

3737 SAVE[id.upper()] = driver 

3738 

3739 

3740def register_save_all( 

3741 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] 

3742) -> None: 

3743 """ 

3744 Registers an image function to save all the frames 

3745 of a multiframe format. This function should not be 

3746 used in application code. 

3747 

3748 :param id: An image format identifier. 

3749 :param driver: A function to save images in this format. 

3750 """ 

3751 SAVE_ALL[id.upper()] = driver 

3752 

3753 

3754def register_extension(id: str, extension: str) -> None: 

3755 """ 

3756 Registers an image extension. This function should not be 

3757 used in application code. 

3758 

3759 :param id: An image format identifier. 

3760 :param extension: An extension used for this format. 

3761 """ 

3762 EXTENSION[extension.lower()] = id.upper() 

3763 

3764 

3765def register_extensions(id: str, extensions: list[str]) -> None: 

3766 """ 

3767 Registers image extensions. This function should not be 

3768 used in application code. 

3769 

3770 :param id: An image format identifier. 

3771 :param extensions: A list of extensions used for this format. 

3772 """ 

3773 for extension in extensions: 

3774 register_extension(id, extension) 

3775 

3776 

3777def registered_extensions() -> dict[str, str]: 

3778 """ 

3779 Returns a dictionary containing all file extensions belonging 

3780 to registered plugins 

3781 """ 

3782 init() 

3783 return EXTENSION 

3784 

3785 

3786def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: 

3787 """ 

3788 Registers an image decoder. This function should not be 

3789 used in application code. 

3790 

3791 :param name: The name of the decoder 

3792 :param decoder: An ImageFile.PyDecoder object 

3793 

3794 .. versionadded:: 4.1.0 

3795 """ 

3796 DECODERS[name] = decoder 

3797 

3798 

3799def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: 

3800 """ 

3801 Registers an image encoder. This function should not be 

3802 used in application code. 

3803 

3804 :param name: The name of the encoder 

3805 :param encoder: An ImageFile.PyEncoder object 

3806 

3807 .. versionadded:: 4.1.0 

3808 """ 

3809 ENCODERS[name] = encoder 

3810 

3811 

3812# -------------------------------------------------------------------- 

3813# Simple display support. 

3814 

3815 

3816def _show(image: Image, **options: Any) -> None: 

3817 from . import ImageShow 

3818 

3819 ImageShow.show(image, **options) 

3820 

3821 

3822# -------------------------------------------------------------------- 

3823# Effects 

3824 

3825 

3826def effect_mandelbrot( 

3827 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int 

3828) -> Image: 

3829 """ 

3830 Generate a Mandelbrot set covering the given extent. 

3831 

3832 :param size: The requested size in pixels, as a 2-tuple: 

3833 (width, height). 

3834 :param extent: The extent to cover, as a 4-tuple: 

3835 (x0, y0, x1, y1). 

3836 :param quality: Quality. 

3837 """ 

3838 return Image()._new(core.effect_mandelbrot(size, extent, quality)) 

3839 

3840 

3841def effect_noise(size: tuple[int, int], sigma: float) -> Image: 

3842 """ 

3843 Generate Gaussian noise centered around 128. 

3844 

3845 :param size: The requested size in pixels, as a 2-tuple: 

3846 (width, height). 

3847 :param sigma: Standard deviation of noise. 

3848 """ 

3849 return Image()._new(core.effect_noise(size, sigma)) 

3850 

3851 

3852def linear_gradient(mode: str) -> Image: 

3853 """ 

3854 Generate 256x256 linear gradient from black to white, top to bottom. 

3855 

3856 :param mode: Input mode. 

3857 """ 

3858 return Image()._new(core.linear_gradient(mode)) 

3859 

3860 

3861def radial_gradient(mode: str) -> Image: 

3862 """ 

3863 Generate 256x256 radial gradient from black to white, centre to edge. 

3864 

3865 :param mode: Input mode. 

3866 """ 

3867 return Image()._new(core.radial_gradient(mode)) 

3868 

3869 

3870# -------------------------------------------------------------------- 

3871# Resources 

3872 

3873 

3874def _apply_env_variables(env: dict[str, str] | None = None) -> None: 

3875 env_dict = env if env is not None else os.environ 

3876 

3877 for var_name, setter in [ 

3878 ("PILLOW_ALIGNMENT", core.set_alignment), 

3879 ("PILLOW_BLOCK_SIZE", core.set_block_size), 

3880 ("PILLOW_BLOCKS_MAX", core.set_blocks_max), 

3881 ]: 

3882 if var_name not in env_dict: 

3883 continue 

3884 

3885 var = env_dict[var_name].lower() 

3886 

3887 units = 1 

3888 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: 

3889 if var.endswith(postfix): 

3890 units = mul 

3891 var = var[: -len(postfix)] 

3892 

3893 try: 

3894 var_int = int(var) * units 

3895 except ValueError: 

3896 warnings.warn(f"{var_name} is not int") 

3897 continue 

3898 

3899 try: 

3900 setter(var_int) 

3901 except ValueError as e: 

3902 warnings.warn(f"{var_name}: {e}") 

3903 

3904 

3905_apply_env_variables() 

3906atexit.register(core.clear_cache) 

3907 

3908 

3909if TYPE_CHECKING: 

3910 _ExifBase = MutableMapping[int, Any] 

3911else: 

3912 _ExifBase = MutableMapping 

3913 

3914 

3915class Exif(_ExifBase): 

3916 """ 

3917 This class provides read and write access to EXIF image data:: 

3918 

3919 from PIL import Image 

3920 im = Image.open("exif.png") 

3921 exif = im.getexif() # Returns an instance of this class 

3922 

3923 Information can be read and written, iterated over or deleted:: 

3924 

3925 print(exif[274]) # 1 

3926 exif[274] = 2 

3927 for k, v in exif.items(): 

3928 print("Tag", k, "Value", v) # Tag 274 Value 2 

3929 del exif[274] 

3930 

3931 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` 

3932 returns a dictionary:: 

3933 

3934 from PIL import ExifTags 

3935 im = Image.open("exif_gps.jpg") 

3936 exif = im.getexif() 

3937 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) 

3938 print(gps_ifd) 

3939 

3940 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, 

3941 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. 

3942 

3943 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: 

3944 

3945 print(exif[ExifTags.Base.Software]) # PIL 

3946 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 

3947 """ 

3948 

3949 endian: str | None = None 

3950 bigtiff = False 

3951 _loaded = False 

3952 

3953 def __init__(self) -> None: 

3954 self._data: dict[int, Any] = {} 

3955 self._hidden_data: dict[int, Any] = {} 

3956 self._ifds: dict[int, dict[int, Any]] = {} 

3957 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None 

3958 self._loaded_exif: bytes | None = None 

3959 

3960 def _fixup(self, value: Any) -> Any: 

3961 try: 

3962 if len(value) == 1 and isinstance(value, tuple): 

3963 return value[0] 

3964 except Exception: 

3965 pass 

3966 return value 

3967 

3968 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: 

3969 # Helper function 

3970 # returns a dict with any single item tuples/lists as individual values 

3971 return {k: self._fixup(v) for k, v in src_dict.items()} 

3972 

3973 def _get_ifd_dict( 

3974 self, offset: int, group: int | None = None 

3975 ) -> dict[int, Any] | None: 

3976 try: 

3977 # an offset pointer to the location of the nested embedded IFD. 

3978 # It should be a long, but may be corrupted. 

3979 self.fp.seek(offset) 

3980 except (KeyError, TypeError): 

3981 return None 

3982 else: 

3983 from . import TiffImagePlugin 

3984 

3985 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) 

3986 info.load(self.fp) 

3987 return self._fixup_dict(dict(info)) 

3988 

3989 def _get_head(self) -> bytes: 

3990 version = b"\x2b" if self.bigtiff else b"\x2a" 

3991 if self.endian == "<": 

3992 head = b"II" + version + b"\x00" + o32le(8) 

3993 else: 

3994 head = b"MM\x00" + version + o32be(8) 

3995 if self.bigtiff: 

3996 head += o32le(8) if self.endian == "<" else o32be(8) 

3997 head += b"\x00\x00\x00\x00" 

3998 return head 

3999 

4000 def load(self, data: bytes) -> None: 

4001 # Extract EXIF information. This is highly experimental, 

4002 # and is likely to be replaced with something better in a future 

4003 # version. 

4004 

4005 # The EXIF record consists of a TIFF file embedded in a JPEG 

4006 # application marker (!). 

4007 if data == self._loaded_exif: 

4008 return 

4009 self._loaded_exif = data 

4010 self._data.clear() 

4011 self._hidden_data.clear() 

4012 self._ifds.clear() 

4013 while data and data.startswith(b"Exif\x00\x00"): 

4014 data = data[6:] 

4015 if not data: 

4016 self._info = None 

4017 return 

4018 

4019 self.fp: IO[bytes] = io.BytesIO(data) 

4020 self.head = self.fp.read(8) 

4021 # process dictionary 

4022 from . import TiffImagePlugin 

4023 

4024 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4025 self.endian = self._info._endian 

4026 self.fp.seek(self._info.next) 

4027 self._info.load(self.fp) 

4028 

4029 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: 

4030 self._loaded_exif = None 

4031 self._data.clear() 

4032 self._hidden_data.clear() 

4033 self._ifds.clear() 

4034 

4035 # process dictionary 

4036 from . import TiffImagePlugin 

4037 

4038 self.fp = fp 

4039 if offset is not None: 

4040 self.head = self._get_head() 

4041 else: 

4042 self.head = self.fp.read(8) 

4043 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) 

4044 if self.endian is None: 

4045 self.endian = self._info._endian 

4046 if offset is None: 

4047 offset = self._info.next 

4048 self.fp.tell() 

4049 self.fp.seek(offset) 

4050 self._info.load(self.fp) 

4051 

4052 def _get_merged_dict(self) -> dict[int, Any]: 

4053 merged_dict = dict(self) 

4054 

4055 # get EXIF extension 

4056 if ExifTags.IFD.Exif in self: 

4057 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) 

4058 if ifd: 

4059 merged_dict.update(ifd) 

4060 

4061 # GPS 

4062 if ExifTags.IFD.GPSInfo in self: 

4063 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( 

4064 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo 

4065 ) 

4066 

4067 return merged_dict 

4068 

4069 def tobytes(self, offset: int = 8) -> bytes: 

4070 from . import TiffImagePlugin 

4071 

4072 head = self._get_head() 

4073 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) 

4074 for tag, ifd_dict in self._ifds.items(): 

4075 if tag not in self: 

4076 ifd[tag] = ifd_dict 

4077 for tag, value in self.items(): 

4078 if tag in [ 

4079 ExifTags.IFD.Exif, 

4080 ExifTags.IFD.GPSInfo, 

4081 ] and not isinstance(value, dict): 

4082 value = self.get_ifd(tag) 

4083 if ( 

4084 tag == ExifTags.IFD.Exif 

4085 and ExifTags.IFD.Interop in value 

4086 and not isinstance(value[ExifTags.IFD.Interop], dict) 

4087 ): 

4088 value = value.copy() 

4089 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) 

4090 ifd[tag] = value 

4091 return b"Exif\x00\x00" + head + ifd.tobytes(offset) 

4092 

4093 def get_ifd(self, tag: int) -> dict[int, Any]: 

4094 if tag not in self._ifds: 

4095 if tag == ExifTags.IFD.IFD1: 

4096 if self._info is not None and self._info.next != 0: 

4097 ifd = self._get_ifd_dict(self._info.next) 

4098 if ifd is not None: 

4099 self._ifds[tag] = ifd 

4100 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: 

4101 offset = self._hidden_data.get(tag, self.get(tag)) 

4102 if offset is not None: 

4103 ifd = self._get_ifd_dict(offset, tag) 

4104 if ifd is not None: 

4105 self._ifds[tag] = ifd 

4106 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: 

4107 if ExifTags.IFD.Exif not in self._ifds: 

4108 self.get_ifd(ExifTags.IFD.Exif) 

4109 tag_data = self._ifds[ExifTags.IFD.Exif][tag] 

4110 if tag == ExifTags.IFD.MakerNote: 

4111 from .TiffImagePlugin import ImageFileDirectory_v2 

4112 

4113 if tag_data.startswith(b"FUJIFILM"): 

4114 ifd_offset = i32le(tag_data, 8) 

4115 ifd_data = tag_data[ifd_offset:] 

4116 

4117 makernote = {} 

4118 for i in range(struct.unpack("<H", ifd_data[:2])[0]): 

4119 ifd_tag, typ, count, data = struct.unpack( 

4120 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4121 ) 

4122 try: 

4123 ( 

4124 unit_size, 

4125 handler, 

4126 ) = ImageFileDirectory_v2._load_dispatch[typ] 

4127 except KeyError: 

4128 continue 

4129 size = count * unit_size 

4130 if size > 4: 

4131 (offset,) = struct.unpack("<L", data) 

4132 data = ifd_data[offset - 12 : offset + size - 12] 

4133 else: 

4134 data = data[:size] 

4135 

4136 if len(data) != size: 

4137 warnings.warn( 

4138 "Possibly corrupt EXIF MakerNote data. " 

4139 f"Expecting to read {size} bytes but only got " 

4140 f"{len(data)}. Skipping tag {ifd_tag}" 

4141 ) 

4142 continue 

4143 

4144 if not data: 

4145 continue 

4146 

4147 makernote[ifd_tag] = handler( 

4148 ImageFileDirectory_v2(), data, False 

4149 ) 

4150 self._ifds[tag] = dict(self._fixup_dict(makernote)) 

4151 elif self.get(0x010F) == "Nintendo": 

4152 makernote = {} 

4153 for i in range(struct.unpack(">H", tag_data[:2])[0]): 

4154 ifd_tag, typ, count, data = struct.unpack( 

4155 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] 

4156 ) 

4157 if ifd_tag == 0x1101: 

4158 # CameraInfo 

4159 (offset,) = struct.unpack(">L", data) 

4160 self.fp.seek(offset) 

4161 

4162 camerainfo: dict[str, int | bytes] = { 

4163 "ModelID": self.fp.read(4) 

4164 } 

4165 

4166 self.fp.read(4) 

4167 # Seconds since 2000 

4168 camerainfo["TimeStamp"] = i32le(self.fp.read(12)) 

4169 

4170 self.fp.read(4) 

4171 camerainfo["InternalSerialNumber"] = self.fp.read(4) 

4172 

4173 self.fp.read(12) 

4174 parallax = self.fp.read(4) 

4175 handler = ImageFileDirectory_v2._load_dispatch[ 

4176 TiffTags.FLOAT 

4177 ][1] 

4178 camerainfo["Parallax"] = handler( 

4179 ImageFileDirectory_v2(), parallax, False 

4180 )[0] 

4181 

4182 self.fp.read(4) 

4183 camerainfo["Category"] = self.fp.read(2) 

4184 

4185 makernote = {0x1101: camerainfo} 

4186 self._ifds[tag] = makernote 

4187 else: 

4188 # Interop 

4189 ifd = self._get_ifd_dict(tag_data, tag) 

4190 if ifd is not None: 

4191 self._ifds[tag] = ifd 

4192 ifd = self._ifds.setdefault(tag, {}) 

4193 if tag == ExifTags.IFD.Exif and self._hidden_data: 

4194 ifd = { 

4195 k: v 

4196 for (k, v) in ifd.items() 

4197 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) 

4198 } 

4199 return ifd 

4200 

4201 def hide_offsets(self) -> None: 

4202 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): 

4203 if tag in self: 

4204 self._hidden_data[tag] = self[tag] 

4205 del self[tag] 

4206 

4207 def __str__(self) -> str: 

4208 if self._info is not None: 

4209 # Load all keys into self._data 

4210 for tag in self._info: 

4211 self[tag] 

4212 

4213 return str(self._data) 

4214 

4215 def __len__(self) -> int: 

4216 keys = set(self._data) 

4217 if self._info is not None: 

4218 keys.update(self._info) 

4219 return len(keys) 

4220 

4221 def __getitem__(self, tag: int) -> Any: 

4222 if self._info is not None and tag not in self._data and tag in self._info: 

4223 self._data[tag] = self._fixup(self._info[tag]) 

4224 del self._info[tag] 

4225 return self._data[tag] 

4226 

4227 def __contains__(self, tag: object) -> bool: 

4228 return tag in self._data or (self._info is not None and tag in self._info) 

4229 

4230 def __setitem__(self, tag: int, value: Any) -> None: 

4231 if self._info is not None and tag in self._info: 

4232 del self._info[tag] 

4233 self._data[tag] = value 

4234 

4235 def __delitem__(self, tag: int) -> None: 

4236 if self._info is not None and tag in self._info: 

4237 del self._info[tag] 

4238 else: 

4239 del self._data[tag] 

4240 

4241 def __iter__(self) -> Iterator[int]: 

4242 keys = set(self._data) 

4243 if self._info is not None: 

4244 keys.update(self._info) 

4245 return iter(keys)