Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PIL/Image.py: 45%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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
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#
27from __future__ import annotations
29import abc
30import atexit
31import builtins
32import io
33import logging
34import math
35import os
36import re
37import struct
38import sys
39import tempfile
40import warnings
41from collections.abc import MutableMapping
42from enum import IntEnum
43from typing import IO, Protocol, cast
45# VERSION was removed in Pillow 6.0.0.
46# PILLOW_VERSION was removed in Pillow 9.0.0.
47# Use __version__ instead.
48from . import (
49 ExifTags,
50 ImageMode,
51 TiffTags,
52 UnidentifiedImageError,
53 __version__,
54 _plugins,
55)
56from ._binary import i32le, o32be, o32le
57from ._deprecate import deprecate
58from ._util import DeferredError, is_path
60ElementTree: ModuleType | None
61try:
62 from defusedxml import ElementTree
63except ImportError:
64 ElementTree = None
66TYPE_CHECKING = False
67if TYPE_CHECKING:
68 from collections.abc import Callable, Iterator, Sequence
69 from types import ModuleType
70 from typing import Any, Literal, Self
72logger = logging.getLogger(__name__)
75class DecompressionBombWarning(RuntimeWarning):
76 pass
79class DecompressionBombError(Exception):
80 pass
83WARN_POSSIBLE_FORMATS: bool = False
85# Limit to around a quarter gigabyte for a 24-bit (3 bpp) image
86MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3)
89try:
90 # If the _imaging C module is not present, Pillow will not load.
91 # Note that other modules should not refer to _imaging directly;
92 # import Image and use the Image.core variable instead.
93 # Also note that Image.core is not a publicly documented interface,
94 # and should be considered private and subject to change.
95 from . import _imaging as core
97 if __version__ != getattr(core, "PILLOW_VERSION", None):
98 msg = (
99 "The _imaging extension was built for another version of Pillow or PIL:\n"
100 f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n"
101 f"Pillow version: {__version__}"
102 )
103 raise ImportError(msg)
105except ImportError as v:
106 # Explanations for ways that we know we might have an import error
107 if str(v).startswith("Module use of python"):
108 # The _imaging C module is present, but not compiled for
109 # the right version (windows only). Print a warning, if
110 # possible.
111 warnings.warn(
112 "The _imaging extension was built for another version of Python.",
113 RuntimeWarning,
114 )
115 elif str(v).startswith("The _imaging extension"):
116 warnings.warn(str(v), RuntimeWarning)
117 # Fail here anyway. Don't let people run with a mostly broken Pillow.
118 # see docs/porting.rst
119 raise
122#
123# Constants
126# transpose
127class Transpose(IntEnum):
128 FLIP_LEFT_RIGHT = 0
129 FLIP_TOP_BOTTOM = 1
130 ROTATE_90 = 2
131 ROTATE_180 = 3
132 ROTATE_270 = 4
133 TRANSPOSE = 5
134 TRANSVERSE = 6
137# transforms (also defined in Imaging.h)
138class Transform(IntEnum):
139 AFFINE = 0
140 EXTENT = 1
141 PERSPECTIVE = 2
142 QUAD = 3
143 MESH = 4
146# resampling filters (also defined in Imaging.h)
147class Resampling(IntEnum):
148 NEAREST = 0
149 BOX = 4
150 BILINEAR = 2
151 HAMMING = 5
152 BICUBIC = 3
153 LANCZOS = 1
156_filters_support = {
157 Resampling.BOX: 0.5,
158 Resampling.BILINEAR: 1.0,
159 Resampling.HAMMING: 1.0,
160 Resampling.BICUBIC: 2.0,
161 Resampling.LANCZOS: 3.0,
162}
165# dithers
166class Dither(IntEnum):
167 NONE = 0
168 ORDERED = 1 # Not yet implemented
169 RASTERIZE = 2 # Not yet implemented
170 FLOYDSTEINBERG = 3 # default
173# palettes/quantizers
174class Palette(IntEnum):
175 WEB = 0
176 ADAPTIVE = 1
179class Quantize(IntEnum):
180 MEDIANCUT = 0
181 MAXCOVERAGE = 1
182 FASTOCTREE = 2
183 LIBIMAGEQUANT = 3
186module = sys.modules[__name__]
187for enum in (Transpose, Transform, Resampling, Dither, Palette, Quantize):
188 for item in enum:
189 setattr(module, item.name, item.value)
192if hasattr(core, "DEFAULT_STRATEGY"):
193 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY
194 FILTERED = core.FILTERED
195 HUFFMAN_ONLY = core.HUFFMAN_ONLY
196 RLE = core.RLE
197 FIXED = core.FIXED
200# --------------------------------------------------------------------
201# Registries
203TYPE_CHECKING = False
204if TYPE_CHECKING:
205 import mmap
206 from xml.etree.ElementTree import Element
208 from IPython.lib.pretty import PrettyPrinter
210 from . import ImageFile, ImageFilter, ImagePalette, ImageQt, TiffImagePlugin
211 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath
212ID: list[str] = []
213OPEN: dict[
214 str,
215 tuple[
216 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile],
217 Callable[[bytes], bool | str] | None,
218 ],
219] = {}
220MIME: dict[str, str] = {}
221SAVE: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
222SAVE_ALL: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
223EXTENSION: dict[str, str] = {}
224DECODERS: dict[str, type[ImageFile.PyDecoder]] = {}
225ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {}
227# --------------------------------------------------------------------
228# Modes
230_ENDIAN = "<" if sys.byteorder == "little" else ">"
233def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]:
234 m = ImageMode.getmode(im.mode)
235 shape: tuple[int, ...] = (im.height, im.width)
236 extra = len(m.bands)
237 if extra != 1:
238 shape += (extra,)
239 return shape, m.typestr
242MODES = [
243 "1",
244 "CMYK",
245 "F",
246 "HSV",
247 "I",
248 "I;16",
249 "I;16B",
250 "I;16L",
251 "I;16N",
252 "L",
253 "LA",
254 "La",
255 "LAB",
256 "P",
257 "PA",
258 "RGB",
259 "RGBA",
260 "RGBa",
261 "RGBX",
262 "YCbCr",
263]
265# raw modes that may be memory mapped. NOTE: if you change this, you
266# may have to modify the stride calculation in map.c too!
267_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")
270def getmodebase(mode: str) -> str:
271 """
272 Gets the "base" mode for given mode. This function returns "L" for
273 images that contain grayscale data, and "RGB" for images that
274 contain color data.
276 :param mode: Input mode.
277 :returns: "L" or "RGB".
278 :exception KeyError: If the input mode was not a standard mode.
279 """
280 return ImageMode.getmode(mode).basemode
283def getmodetype(mode: str) -> str:
284 """
285 Gets the storage type mode. Given a mode, this function returns a
286 single-layer mode suitable for storing individual bands.
288 :param mode: Input mode.
289 :returns: "L", "I", or "F".
290 :exception KeyError: If the input mode was not a standard mode.
291 """
292 return ImageMode.getmode(mode).basetype
295def getmodebandnames(mode: str) -> tuple[str, ...]:
296 """
297 Gets a list of individual band names. Given a mode, this function returns
298 a tuple containing the names of individual bands (use
299 :py:method:`~PIL.Image.getmodetype` to get the mode used to store each
300 individual band.
302 :param mode: Input mode.
303 :returns: A tuple containing band names. The length of the tuple
304 gives the number of bands in an image of the given mode.
305 :exception KeyError: If the input mode was not a standard mode.
306 """
307 return ImageMode.getmode(mode).bands
310def getmodebands(mode: str) -> int:
311 """
312 Gets the number of individual bands for this mode.
314 :param mode: Input mode.
315 :returns: The number of bands in this mode.
316 :exception KeyError: If the input mode was not a standard mode.
317 """
318 return len(ImageMode.getmode(mode).bands)
321# --------------------------------------------------------------------
322# Helpers
324_initialized = 0
326# Mapping from file extension to plugin module name for lazy importing
327_EXTENSION_PLUGIN: dict[str, str] = {
328 # Common formats (preinit)
329 ".bmp": "BmpImagePlugin",
330 ".dib": "BmpImagePlugin",
331 ".gif": "GifImagePlugin",
332 ".jfif": "JpegImagePlugin",
333 ".jpe": "JpegImagePlugin",
334 ".jpg": "JpegImagePlugin",
335 ".jpeg": "JpegImagePlugin",
336 ".pbm": "PpmImagePlugin",
337 ".pgm": "PpmImagePlugin",
338 ".pnm": "PpmImagePlugin",
339 ".ppm": "PpmImagePlugin",
340 ".pfm": "PpmImagePlugin",
341 ".png": "PngImagePlugin",
342 ".apng": "PngImagePlugin",
343 # Less common formats (init)
344 ".avif": "AvifImagePlugin",
345 ".avifs": "AvifImagePlugin",
346 ".blp": "BlpImagePlugin",
347 ".bufr": "BufrStubImagePlugin",
348 ".cur": "CurImagePlugin",
349 ".dcx": "DcxImagePlugin",
350 ".dds": "DdsImagePlugin",
351 ".ps": "EpsImagePlugin",
352 ".eps": "EpsImagePlugin",
353 ".fit": "FitsImagePlugin",
354 ".fits": "FitsImagePlugin",
355 ".fli": "FliImagePlugin",
356 ".flc": "FliImagePlugin",
357 ".fpx": "FpxImagePlugin",
358 ".ftc": "FtexImagePlugin",
359 ".ftu": "FtexImagePlugin",
360 ".gbr": "GbrImagePlugin",
361 ".grib": "GribStubImagePlugin",
362 ".h5": "Hdf5StubImagePlugin",
363 ".hdf": "Hdf5StubImagePlugin",
364 ".icns": "IcnsImagePlugin",
365 ".ico": "IcoImagePlugin",
366 ".im": "ImImagePlugin",
367 ".iim": "IptcImagePlugin",
368 ".jp2": "Jpeg2KImagePlugin",
369 ".j2k": "Jpeg2KImagePlugin",
370 ".jpc": "Jpeg2KImagePlugin",
371 ".jpf": "Jpeg2KImagePlugin",
372 ".jpx": "Jpeg2KImagePlugin",
373 ".j2c": "Jpeg2KImagePlugin",
374 ".mic": "MicImagePlugin",
375 ".mpg": "MpegImagePlugin",
376 ".mpeg": "MpegImagePlugin",
377 ".mpo": "MpoImagePlugin",
378 ".msp": "MspImagePlugin",
379 ".palm": "PalmImagePlugin",
380 ".pcd": "PcdImagePlugin",
381 ".pcx": "PcxImagePlugin",
382 ".pdf": "PdfImagePlugin",
383 ".pxr": "PixarImagePlugin",
384 ".psd": "PsdImagePlugin",
385 ".qoi": "QoiImagePlugin",
386 ".bw": "SgiImagePlugin",
387 ".rgb": "SgiImagePlugin",
388 ".rgba": "SgiImagePlugin",
389 ".sgi": "SgiImagePlugin",
390 ".ras": "SunImagePlugin",
391 ".tga": "TgaImagePlugin",
392 ".icb": "TgaImagePlugin",
393 ".vda": "TgaImagePlugin",
394 ".vst": "TgaImagePlugin",
395 ".tif": "TiffImagePlugin",
396 ".tiff": "TiffImagePlugin",
397 ".webp": "WebPImagePlugin",
398 ".wmf": "WmfImagePlugin",
399 ".emf": "WmfImagePlugin",
400 ".xbm": "XbmImagePlugin",
401 ".xpm": "XpmImagePlugin",
402}
405def _import_plugin_for_extension(ext: str | bytes) -> bool:
406 """Import only the plugin needed for a specific file extension."""
407 if not ext:
408 return False
410 if isinstance(ext, bytes):
411 ext = ext.decode()
412 ext = ext.lower()
413 if ext in EXTENSION:
414 return True
416 plugin = _EXTENSION_PLUGIN.get(ext)
417 if plugin is None:
418 return False
420 try:
421 logger.debug("Importing %s", plugin)
422 __import__(f"{__spec__.parent}.{plugin}", globals(), locals(), [])
423 return True
424 except ImportError as e:
425 logger.debug("Image: failed to import %s: %s", plugin, e)
426 return False
429def preinit() -> None:
430 """
431 Explicitly loads BMP, GIF, JPEG, PPM and PNG file format drivers.
433 It is called when opening or saving images.
434 """
436 global _initialized
437 if _initialized >= 1:
438 return
440 try:
441 from . import BmpImagePlugin
443 assert BmpImagePlugin
444 except ImportError:
445 pass
446 try:
447 from . import GifImagePlugin
449 assert GifImagePlugin
450 except ImportError:
451 pass
452 try:
453 from . import JpegImagePlugin
455 assert JpegImagePlugin
456 except ImportError:
457 pass
458 try:
459 from . import PpmImagePlugin
461 assert PpmImagePlugin
462 except ImportError:
463 pass
464 try:
465 from . import PngImagePlugin
467 assert PngImagePlugin
468 except ImportError:
469 pass
471 _initialized = 1
474def init() -> bool:
475 """
476 Explicitly initializes the Python Imaging Library. This function
477 loads all available file format drivers.
479 It is called when opening or saving images if :py:meth:`~preinit()` is
480 insufficient, and by :py:meth:`~PIL.features.pilinfo`.
481 """
483 global _initialized
484 if _initialized >= 2:
485 return False
487 for plugin in _plugins:
488 try:
489 logger.debug("Importing %s", plugin)
490 __import__(f"{__spec__.parent}.{plugin}", globals(), locals(), [])
491 except ImportError as e:
492 logger.debug("Image: failed to import %s: %s", plugin, e)
494 if OPEN or SAVE:
495 _initialized = 2
496 return True
497 return False
500# --------------------------------------------------------------------
501# Codec factories (used by tobytes/frombytes and ImageFile.load)
504def _getdecoder(
505 mode: str, decoder_name: str, args: Any, extra: tuple[Any, ...] = ()
506) -> core.ImagingDecoder | ImageFile.PyDecoder:
507 # tweak arguments
508 if args is None:
509 args = ()
510 elif not isinstance(args, tuple):
511 args = (args,)
513 try:
514 decoder = DECODERS[decoder_name]
515 except KeyError:
516 pass
517 else:
518 return decoder(mode, *args + extra)
520 try:
521 # get decoder
522 decoder = getattr(core, f"{decoder_name}_decoder")
523 except AttributeError as e:
524 msg = f"decoder {decoder_name} not available"
525 raise OSError(msg) from e
526 return decoder(mode, *args + extra)
529def _getencoder(
530 mode: str, encoder_name: str, args: Any, extra: tuple[Any, ...] = ()
531) -> core.ImagingEncoder | ImageFile.PyEncoder:
532 # tweak arguments
533 if args is None:
534 args = ()
535 elif not isinstance(args, tuple):
536 args = (args,)
538 try:
539 encoder = ENCODERS[encoder_name]
540 except KeyError:
541 pass
542 else:
543 return encoder(mode, *args + extra)
545 try:
546 # get encoder
547 encoder = getattr(core, f"{encoder_name}_encoder")
548 except AttributeError as e:
549 msg = f"encoder {encoder_name} not available"
550 raise OSError(msg) from e
551 return encoder(mode, *args + extra)
554# --------------------------------------------------------------------
555# Simple expression analyzer
558class ImagePointTransform:
559 """
560 Used with :py:meth:`~PIL.Image.Image.point` for single band images with more than
561 8 bits, this represents an affine transformation, where the value is multiplied by
562 ``scale`` and ``offset`` is added.
563 """
565 def __init__(self, scale: float, offset: float) -> None:
566 self.scale = scale
567 self.offset = offset
569 def __neg__(self) -> ImagePointTransform:
570 return ImagePointTransform(-self.scale, -self.offset)
572 def __add__(self, other: ImagePointTransform | float) -> ImagePointTransform:
573 if isinstance(other, ImagePointTransform):
574 return ImagePointTransform(
575 self.scale + other.scale, self.offset + other.offset
576 )
577 return ImagePointTransform(self.scale, self.offset + other)
579 __radd__ = __add__
581 def __sub__(self, other: ImagePointTransform | float) -> ImagePointTransform:
582 return self + -other
584 def __rsub__(self, other: ImagePointTransform | float) -> ImagePointTransform:
585 return other + -self
587 def __mul__(self, other: ImagePointTransform | float) -> ImagePointTransform:
588 if isinstance(other, ImagePointTransform):
589 return NotImplemented
590 return ImagePointTransform(self.scale * other, self.offset * other)
592 __rmul__ = __mul__
594 def __truediv__(self, other: ImagePointTransform | float) -> ImagePointTransform:
595 if isinstance(other, ImagePointTransform):
596 return NotImplemented
597 return ImagePointTransform(self.scale / other, self.offset / other)
600def _getscaleoffset(
601 expr: Callable[[ImagePointTransform], ImagePointTransform | float],
602) -> tuple[float, float]:
603 a = expr(ImagePointTransform(1, 0))
604 return (a.scale, a.offset) if isinstance(a, ImagePointTransform) else (0, a)
607# --------------------------------------------------------------------
608# Implementation wrapper
611class SupportsGetData(Protocol):
612 def getdata(
613 self,
614 ) -> tuple[Transform, Sequence[int]]: ...
617class Image:
618 """
619 This class represents an image object. To create
620 :py:class:`~PIL.Image.Image` objects, use the appropriate factory
621 functions. There's hardly ever any reason to call the Image constructor
622 directly.
624 * :py:func:`~PIL.Image.open`
625 * :py:func:`~PIL.Image.new`
626 * :py:func:`~PIL.Image.frombytes`
627 """
629 format: str | None = None
630 format_description: str | None = None
631 _close_exclusive_fp_after_loading = True
633 def __init__(self) -> None:
634 # FIXME: take "new" parameters / other image?
635 self._im: core.ImagingCore | DeferredError | None = None
636 self._mode = ""
637 self._size = (0, 0)
638 self.palette: ImagePalette.ImagePalette | None = None
639 self.info: dict[str | tuple[int, int], Any] = {}
640 self.readonly = 0
641 self._exif: Exif | None = None
643 @property
644 def im(self) -> core.ImagingCore:
645 if isinstance(self._im, DeferredError):
646 raise self._im.ex
647 assert self._im is not None
648 return self._im
650 @im.setter
651 def im(self, im: core.ImagingCore) -> None:
652 self._im = im
654 @property
655 def width(self) -> int:
656 return self.size[0]
658 @property
659 def height(self) -> int:
660 return self.size[1]
662 @property
663 def size(self) -> tuple[int, int]:
664 return self._size
666 @property
667 def mode(self) -> str:
668 return self._mode
670 @property
671 def readonly(self) -> int:
672 return (self._im and self._im.readonly) or self._readonly
674 @readonly.setter
675 def readonly(self, readonly: int) -> None:
676 self._readonly = readonly
678 def _new(self, im: core.ImagingCore) -> Image:
679 new = Image()
680 new.im = im
681 new._mode = im.mode
682 new._size = im.size
683 if im.mode in ("P", "PA"):
684 if self.palette:
685 new.palette = self.palette.copy()
686 else:
687 from . import ImagePalette
689 new.palette = ImagePalette.ImagePalette()
690 new.info = self.info.copy()
691 return new
693 # Context manager support
694 def __enter__(self) -> Self:
695 return self
697 def __exit__(self, *args: object) -> None:
698 pass
700 def close(self) -> None:
701 """
702 This operation will destroy the image core and release its memory.
703 The image data will be unusable afterward.
705 This function is required to close images that have multiple frames or
706 have not had their file read and closed by the
707 :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for
708 more information.
709 """
710 if getattr(self, "map", None):
711 if sys.platform == "win32" and hasattr(sys, "pypy_version_info"):
712 self.map.close()
713 self.map: mmap.mmap | None = None
715 # Instead of simply setting to None, we're setting up a
716 # deferred error that will better explain that the core image
717 # object is gone.
718 self._im = DeferredError(ValueError("Operation on closed image"))
720 def _copy(self) -> None:
721 self.load()
722 self.im = self.im.copy()
723 self.readonly = 0
725 def _ensure_mutable(self) -> None:
726 if self.readonly:
727 self._copy()
728 else:
729 self.load()
731 def _dump(
732 self, file: str | None = None, format: str | None = None, **options: Any
733 ) -> str:
734 suffix = f".{format}" if format else ""
736 if file:
737 filename = file
738 if not filename.endswith(suffix):
739 filename += suffix
740 else:
741 f, filename = tempfile.mkstemp(suffix)
742 os.close(f)
744 self.save(filename, format or "PPM", **options)
746 return filename
748 def __eq__(self, other: object) -> bool:
749 if self.__class__ is not other.__class__:
750 return False
751 assert isinstance(other, Image)
752 return (
753 self.mode == other.mode
754 and self.size == other.size
755 and self.info == other.info
756 and self.getpalette() == other.getpalette()
757 and self.tobytes() == other.tobytes()
758 )
760 def __repr__(self) -> str:
761 return (
762 f"<{self.__class__.__module__}.{self.__class__.__name__} "
763 f"image mode={self.mode} size={self.size[0]}x{self.size[1]} "
764 f"at 0x{id(self):X}>"
765 )
767 def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None:
768 """IPython plain text display support"""
770 # Same as __repr__ but without unpredictable id(self),
771 # to keep Jupyter notebook `text/plain` output stable.
772 p.text(
773 f"<{self.__class__.__module__}.{self.__class__.__name__} "
774 f"image mode={self.mode} size={self.size[0]}x{self.size[1]}>"
775 )
777 def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None:
778 """Helper function for iPython display hook.
780 :param image_format: Image format.
781 :returns: image as bytes, saved into the given format.
782 """
783 b = io.BytesIO()
784 try:
785 self.save(b, image_format, **kwargs)
786 except Exception:
787 return None
788 return b.getvalue()
790 def _repr_png_(self) -> bytes | None:
791 """iPython display hook support for PNG format.
793 :returns: PNG version of the image as bytes
794 """
795 return self._repr_image("PNG", compress_level=1)
797 def _repr_jpeg_(self) -> bytes | None:
798 """iPython display hook support for JPEG format.
800 :returns: JPEG version of the image as bytes
801 """
802 return self._repr_image("JPEG")
804 @property
805 def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]:
806 # numpy array interface support
807 new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3}
808 if self.mode == "1":
809 # Binary images need to be extended from bits to bytes
810 # See: https://github.com/python-pillow/Pillow/issues/350
811 new["data"] = self.tobytes("raw", "L")
812 else:
813 new["data"] = self.tobytes()
814 new["shape"], new["typestr"] = _conv_type_shape(self)
815 return new
817 def __arrow_c_schema__(self) -> object:
818 self.load()
819 return self.im.__arrow_c_schema__()
821 def __arrow_c_array__(
822 self, requested_schema: object | None = None
823 ) -> tuple[object, object]:
824 self.load()
825 return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__())
827 def __getstate__(self) -> list[Any]:
828 im_data = self.tobytes() # load image first
829 return [self.info, self.mode, self.size, self.getpalette(), im_data]
831 def __setstate__(self, state: list[Any]) -> None:
832 Image.__init__(self)
833 info, mode, size, palette, data = state[:5]
834 self.info = info
835 self._mode = mode
836 self._size = size
837 self.im = core.new(mode, size)
838 if mode in ("L", "LA", "P", "PA") and palette:
839 self.putpalette(palette)
840 self.frombytes(data)
842 def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes:
843 """
844 Return image as a bytes object.
846 .. warning::
848 This method returns raw image data derived from Pillow's internal
849 storage. For compressed image data (e.g. PNG, JPEG) use
850 :meth:`~.save`, with a BytesIO parameter for in-memory data.
852 :param encoder_name: What encoder to use.
854 The default is to use the standard "raw" encoder.
855 To see how this packs pixel data into the returned
856 bytes, see :file:`libImaging/Pack.c`.
858 A list of C encoders can be seen under codecs
859 section of the function array in
860 :file:`_imaging.c`. Python encoders are registered
861 within the relevant plugins.
862 :param args: Extra arguments to the encoder.
863 :returns: A :py:class:`bytes` object.
864 """
866 encoder_args: Any = args
867 if len(encoder_args) == 1 and isinstance(encoder_args[0], tuple):
868 # may pass tuple instead of argument list
869 encoder_args = encoder_args[0]
871 if encoder_name == "raw" and encoder_args == ():
872 encoder_args = self.mode
874 self.load()
876 if self.width == 0 or self.height == 0:
877 return b""
879 # unpack data
880 e = _getencoder(self.mode, encoder_name, encoder_args)
881 e.setimage(self.im, (0, 0) + self.size)
883 from . import ImageFile
885 bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c
887 output = []
888 while True:
889 bytes_consumed, errcode, data = e.encode(bufsize)
890 output.append(data)
891 if errcode:
892 break
893 if errcode < 0:
894 msg = f"encoder error {errcode} in tobytes"
895 raise RuntimeError(msg)
897 return b"".join(output)
899 def tobitmap(self, name: str = "image") -> bytes:
900 """
901 Returns the image converted to an X11 bitmap.
903 .. note:: This method only works for mode "1" images.
905 :param name: The name prefix to use for the bitmap variables.
906 :returns: A string containing an X11 bitmap.
907 :raises ValueError: If the mode is not "1"
908 """
910 self.load()
911 if self.mode != "1":
912 msg = "not a bitmap"
913 raise ValueError(msg)
914 data = self.tobytes("xbm")
915 return b"".join(
916 [
917 f"#define {name}_width {self.size[0]}\n".encode("ascii"),
918 f"#define {name}_height {self.size[1]}\n".encode("ascii"),
919 f"static char {name}_bits[] = {{\n".encode("ascii"),
920 data,
921 b"};",
922 ]
923 )
925 def frombytes(
926 self,
927 data: DecoderInput,
928 decoder_name: str = "raw",
929 *args: Any,
930 ) -> None:
931 """
932 Loads this image with pixel data from a bytes object.
934 This method is similar to the :py:func:`~PIL.Image.frombytes` function,
935 but loads data into this image instead of creating a new image object.
936 """
938 if self.width == 0 or self.height == 0:
939 return
941 decoder_args: Any = args
942 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
943 # may pass tuple instead of argument list
944 decoder_args = decoder_args[0]
946 if decoder_args and decoder_args[0] in {"P;2L", "P;4L"}:
947 multiple = 4 if decoder_args[0] == "P;2L" else 8
948 if len(data) % multiple:
949 msg = "not enough image data"
950 raise ValueError(msg)
952 # default format
953 if decoder_name == "raw" and decoder_args == ():
954 decoder_args = self.mode
956 # unpack data
957 d = _getdecoder(self.mode, decoder_name, decoder_args)
958 d.setimage(self.im, (0, 0) + self.size)
959 s = d.decode(data)
961 if s[0] >= 0:
962 msg = "not enough image data"
963 raise ValueError(msg)
964 if s[1] != 0:
965 msg = "cannot decode image data"
966 raise ValueError(msg)
968 def load(self) -> core.PixelAccess | None:
969 """
970 Allocates storage for the image and loads the pixel data. In
971 normal cases, you don't need to call this method, since the
972 Image class automatically loads an opened image when it is
973 accessed for the first time.
975 If the file associated with the image was opened by Pillow, then this
976 method will close it. The exception to this is if the image has
977 multiple frames, in which case the file will be left open for seek
978 operations. See :ref:`file-handling` for more information.
980 :returns: An image access object.
981 """
982 if self._im is not None and self.palette and self.palette.dirty:
983 # realize palette
984 mode, arr = self.palette.getdata()
985 self.im.putpalette(self.palette.mode, mode, arr)
986 self.palette.dirty = 0
987 self.palette.rawmode = None
988 if "transparency" in self.info and mode in ("LA", "PA"):
989 if isinstance(self.info["transparency"], int):
990 self.im.putpalettealpha(self.info["transparency"], 0)
991 else:
992 self.im.putpalettealphas(self.info["transparency"])
993 self.palette.mode = "RGBA"
994 elif self.palette.mode != mode:
995 # If the palette rawmode is different to the mode,
996 # then update the Python palette data
997 self.palette.palette = self.im.getpalette(self.palette.mode)
999 if self._im is not None:
1000 return self.im.pixel_access(self.readonly)
1001 return None
1003 def verify(self) -> None:
1004 """
1005 Verifies the contents of a file. For data read from a file, this
1006 method attempts to determine if the file is broken, without
1007 actually decoding the image data. If this method finds any
1008 problems, it raises suitable exceptions. If you need to load
1009 the image after using this method, you must reopen the image
1010 file.
1011 """
1012 pass
1014 def convert(
1015 self,
1016 mode: str | None = None,
1017 matrix: tuple[float, ...] | None = None,
1018 dither: Dither | None = None,
1019 palette: Palette = Palette.WEB,
1020 colors: int = 256,
1021 ) -> Image:
1022 """
1023 Returns a converted copy of this image. For the "P" mode, this
1024 method translates pixels through the palette. If mode is
1025 omitted, a mode is chosen so that all information in the image
1026 and the palette can be represented without a palette.
1028 This supports all possible conversions between "L", "RGB" and "CMYK". The
1029 ``matrix`` argument only supports "L" and "RGB".
1031 When translating a color image to grayscale (mode "L"),
1032 the library uses the ITU-R 601-2 luma transform::
1034 L = R * 299/1000 + G * 587/1000 + B * 114/1000
1036 The default method of converting a grayscale ("L") or "RGB"
1037 image into a bilevel (mode "1") image uses Floyd-Steinberg
1038 dither to approximate the original image luminosity levels. If
1039 dither is ``None``, all values larger than 127 are set to 255 (white),
1040 all other values to 0 (black). To use other thresholds, use the
1041 :py:meth:`~PIL.Image.Image.point` method.
1043 When converting from "RGBA" to "P" without a ``matrix`` argument,
1044 this passes the operation to :py:meth:`~PIL.Image.Image.quantize`,
1045 and ``dither`` and ``palette`` are ignored.
1047 When converting from "PA", if an "RGBA" palette is present, the alpha
1048 channel from the image will be used instead of the values from the palette.
1050 :param mode: The requested mode. See: :ref:`concept-modes`.
1051 :param matrix: An optional conversion matrix. If given, this
1052 should be 4- or 12-tuple containing floating point values.
1053 :param dither: Dithering method, used when converting from
1054 mode "RGB" to "P" or from "RGB" or "L" to "1".
1055 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1056 (default). Note that this is not used when ``matrix`` is supplied.
1057 :param palette: Palette to use when converting from mode "RGB"
1058 to "P". Available palettes are :data:`Palette.WEB` or
1059 :data:`Palette.ADAPTIVE`.
1060 :param colors: Number of colors to use for the :data:`Palette.ADAPTIVE`
1061 palette. Defaults to 256.
1062 :returns: An :py:class:`~PIL.Image.Image` object.
1063 """
1065 self.load()
1067 has_transparency = "transparency" in self.info
1068 if not mode and self.mode == "P":
1069 # determine default mode
1070 if self.palette:
1071 mode = self.palette.mode
1072 else:
1073 mode = "RGB"
1074 if mode == "RGB" and has_transparency:
1075 mode = "RGBA"
1076 if not mode or (mode == self.mode and not matrix):
1077 return self.copy()
1079 if matrix:
1080 # matrix conversion
1081 if mode not in ("L", "RGB"):
1082 msg = "illegal conversion"
1083 raise ValueError(msg)
1084 im = self.im.convert_matrix(mode, matrix)
1085 new_im = self._new(im)
1086 if has_transparency and self.im.bands == 3:
1087 transparency = new_im.info["transparency"]
1089 def convert_transparency(
1090 m: tuple[float, ...], v: tuple[int, int, int]
1091 ) -> int:
1092 value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5
1093 return max(0, min(255, int(value)))
1095 if mode == "L":
1096 transparency = convert_transparency(matrix, transparency)
1097 elif len(mode) == 3:
1098 transparency = tuple(
1099 convert_transparency(matrix[i * 4 : i * 4 + 4], transparency)
1100 for i in range(len(transparency))
1101 )
1102 new_im.info["transparency"] = transparency
1103 return new_im
1105 if self.mode == "RGBA":
1106 if mode == "P":
1107 return self.quantize(colors)
1108 elif mode == "PA":
1109 r, g, b, a = self.split()
1110 rgb = merge("RGB", (r, g, b))
1111 p = rgb.quantize(colors)
1112 return merge("PA", (p, a))
1114 trns = None
1115 delete_trns = False
1116 # transparency handling
1117 if has_transparency:
1118 if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or (
1119 self.mode == "RGB" and mode in ("La", "LA", "RGBa", "RGBA")
1120 ):
1121 # Use transparent conversion to promote from transparent
1122 # color to an alpha channel.
1123 new_im = self._new(
1124 self.im.convert_transparent(mode, self.info["transparency"])
1125 )
1126 del new_im.info["transparency"]
1127 return new_im
1128 elif self.mode in ("L", "RGB", "P") and mode in ("L", "RGB", "P"):
1129 t = self.info["transparency"]
1130 if isinstance(t, bytes):
1131 # Dragons. This can't be represented by a single color
1132 warnings.warn(
1133 "Palette images with Transparency expressed in bytes should be "
1134 "converted to RGBA images"
1135 )
1136 delete_trns = True
1137 else:
1138 # get the new transparency color.
1139 # use existing conversions
1140 trns_im = new(self.mode, (1, 1))
1141 if self.mode == "P":
1142 assert self.palette is not None
1143 trns_im.putpalette(self.palette, self.palette.mode)
1144 if isinstance(t, tuple):
1145 err = "Couldn't allocate a palette color for transparency"
1146 assert trns_im.palette is not None
1147 try:
1148 t = trns_im.palette.getcolor(t, self)
1149 except ValueError as e:
1150 if str(e) == "cannot allocate more than 256 colors":
1151 # If all 256 colors are in use,
1152 # then there is no need for transparency
1153 t = None
1154 else:
1155 raise ValueError(err) from e
1156 if t is None:
1157 trns = None
1158 else:
1159 trns_im.putpixel((0, 0), t)
1161 if mode in ("L", "RGB"):
1162 trns_im = trns_im.convert(mode)
1163 else:
1164 # can't just retrieve the palette number, got to do it
1165 # after quantization.
1166 trns_im = trns_im.convert("RGB")
1167 trns = trns_im.getpixel((0, 0))
1169 elif self.mode == "P" and mode in ("LA", "PA", "RGBA"):
1170 t = self.info["transparency"]
1171 delete_trns = True
1173 if isinstance(t, bytes):
1174 self.im.putpalettealphas(t)
1175 elif isinstance(t, int):
1176 self.im.putpalettealpha(t, 0)
1177 else:
1178 msg = "Transparency for P mode should be bytes or int"
1179 raise ValueError(msg)
1181 if mode == "P" and palette == Palette.ADAPTIVE:
1182 im = self.im.quantize(colors)
1183 new_im = self._new(im)
1184 from . import ImagePalette
1186 new_im.palette = ImagePalette.ImagePalette(
1187 "RGB", new_im.im.getpalette("RGB")
1188 )
1189 if delete_trns:
1190 # This could possibly happen if we requantize to fewer colors.
1191 # The transparency would be totally off in that case.
1192 del new_im.info["transparency"]
1193 if trns is not None:
1194 try:
1195 new_im.info["transparency"] = new_im.palette.getcolor(
1196 cast(tuple[int, ...], trns), # trns was converted to RGB
1197 new_im,
1198 )
1199 except Exception:
1200 # if we can't make a transparent color, don't leave the old
1201 # transparency hanging around to mess us up.
1202 del new_im.info["transparency"]
1203 warnings.warn("Couldn't allocate palette entry for transparency")
1204 return new_im
1206 if "LAB" in (self.mode, mode):
1207 im = self
1208 if mode == "LAB":
1209 if im.mode not in ("RGB", "RGBA", "RGBX"):
1210 im = im.convert("RGBA")
1211 other_mode = im.mode
1212 else:
1213 other_mode = mode
1214 if other_mode in ("RGB", "RGBA", "RGBX"):
1215 from . import ImageCms
1217 srgb = ImageCms.createProfile("sRGB")
1218 lab = ImageCms.createProfile("LAB")
1219 profiles = [lab, srgb] if im.mode == "LAB" else [srgb, lab]
1220 transform = ImageCms.buildTransform(
1221 profiles[0], profiles[1], im.mode, mode
1222 )
1223 return transform.apply(im)
1225 # colorspace conversion
1226 if dither is None:
1227 dither = Dither.FLOYDSTEINBERG
1229 try:
1230 im = self.im.convert(mode, dither)
1231 except ValueError:
1232 try:
1233 # normalize source image and try again
1234 modebase = getmodebase(self.mode)
1235 if modebase == self.mode:
1236 raise
1237 im = self.im.convert(modebase)
1238 im = im.convert(mode, dither)
1239 except KeyError as e:
1240 msg = "illegal conversion"
1241 raise ValueError(msg) from e
1243 new_im = self._new(im)
1244 if mode in ("P", "PA") and palette != Palette.ADAPTIVE:
1245 from . import ImagePalette
1247 new_im.palette = ImagePalette.ImagePalette("RGB", im.getpalette("RGB"))
1248 if delete_trns:
1249 # crash fail if we leave a bytes transparency in an rgb/l mode.
1250 del new_im.info["transparency"]
1251 if trns is not None:
1252 if new_im.mode == "P" and new_im.palette:
1253 try:
1254 new_im.info["transparency"] = new_im.palette.getcolor(
1255 cast(tuple[int, ...], trns), new_im # trns was converted to RGB
1256 )
1257 except ValueError as e:
1258 del new_im.info["transparency"]
1259 if str(e) != "cannot allocate more than 256 colors":
1260 # If all 256 colors are in use,
1261 # then there is no need for transparency
1262 warnings.warn(
1263 "Couldn't allocate palette entry for transparency"
1264 )
1265 else:
1266 new_im.info["transparency"] = trns
1267 return new_im
1269 def quantize(
1270 self,
1271 colors: int = 256,
1272 method: int | None = None,
1273 kmeans: int = 0,
1274 palette: Image | None = None,
1275 dither: Dither = Dither.FLOYDSTEINBERG,
1276 ) -> Image:
1277 """
1278 Convert the image to 'P' mode with the specified number
1279 of colors.
1281 :param colors: The desired number of colors, <= 256
1282 :param method: :data:`Quantize.MEDIANCUT` (median cut),
1283 :data:`Quantize.MAXCOVERAGE` (maximum coverage),
1284 :data:`Quantize.FASTOCTREE` (fast octree),
1285 :data:`Quantize.LIBIMAGEQUANT` (libimagequant; check support
1286 using :py:func:`PIL.features.check_feature` with
1287 ``feature="libimagequant"``).
1289 By default, :data:`Quantize.MEDIANCUT` will be used.
1291 The exception to this is RGBA images. :data:`Quantize.MEDIANCUT`
1292 and :data:`Quantize.MAXCOVERAGE` do not support RGBA images, so
1293 :data:`Quantize.FASTOCTREE` is used by default instead.
1294 :param kmeans: Integer greater than or equal to zero.
1295 :param palette: Quantize to the palette of given
1296 :py:class:`PIL.Image.Image`.
1297 :param dither: Dithering method, used when converting from
1298 mode "RGB" to "P" or from "RGB" or "L" to "1".
1299 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1300 (default).
1301 :returns: A new image
1302 """
1304 self.load()
1306 if method is None:
1307 # defaults:
1308 method = Quantize.MEDIANCUT
1309 if self.mode == "RGBA":
1310 method = Quantize.FASTOCTREE
1312 if self.mode == "RGBA" and method not in (
1313 Quantize.FASTOCTREE,
1314 Quantize.LIBIMAGEQUANT,
1315 ):
1316 # Caller specified an invalid mode.
1317 msg = (
1318 "Fast Octree (method == 2) and libimagequant (method == 3) "
1319 "are the only valid methods for quantizing RGBA images"
1320 )
1321 raise ValueError(msg)
1323 if palette:
1324 # use palette from reference image
1325 palette.load()
1326 if palette.mode != "P":
1327 msg = "bad mode for palette image"
1328 raise ValueError(msg)
1329 if self.mode not in {"RGB", "L"}:
1330 msg = "only RGB or L mode images can be quantized to a palette"
1331 raise ValueError(msg)
1332 im = self.im.convert("P", dither, palette.im)
1333 new_im = self._new(im)
1334 assert palette.palette is not None
1335 new_im.palette = palette.palette.copy()
1336 return new_im
1338 if kmeans < 0:
1339 msg = "kmeans must not be negative"
1340 raise ValueError(msg)
1342 im = self._new(self.im.quantize(colors, method, kmeans))
1344 from . import ImagePalette
1346 mode = im.im.getpalettemode()
1347 palette_data = im.im.getpalette(mode)[: colors * len(mode)]
1348 im.palette = ImagePalette.ImagePalette(mode, palette_data)
1350 return im
1352 def copy(self) -> Image:
1353 """
1354 Copies this image. Use this method if you wish to paste things
1355 into an image, but still retain the original.
1357 :returns: An :py:class:`~PIL.Image.Image` object.
1358 """
1359 self.load()
1360 return self._new(self.im.copy())
1362 __copy__ = copy
1364 def crop(self, box: tuple[float, float, float, float] | None = None) -> Image:
1365 """
1366 Returns a rectangular region from this image. The box is a
1367 4-tuple defining the left, upper, right, and lower pixel
1368 coordinate. See :ref:`coordinate-system`.
1370 Note: Prior to Pillow 3.4.0, this was a lazy operation.
1372 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1373 :returns: An :py:class:`~PIL.Image.Image` object.
1374 """
1376 if box is None:
1377 return self.copy()
1379 if box[2] < box[0]:
1380 msg = "Coordinate 'right' is less than 'left'"
1381 raise ValueError(msg)
1382 elif box[3] < box[1]:
1383 msg = "Coordinate 'lower' is less than 'upper'"
1384 raise ValueError(msg)
1386 self.load()
1387 return self._new(self._crop(self.im, box))
1389 def _crop(
1390 self, im: core.ImagingCore, box: tuple[float, float, float, float]
1391 ) -> core.ImagingCore:
1392 """
1393 Returns a rectangular region from the core image object im.
1395 This is equivalent to calling im.crop((x0, y0, x1, y1)), but
1396 includes additional sanity checks.
1398 :param im: a core image object
1399 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1400 :returns: A core image object.
1401 """
1403 x0, y0, x1, y1 = map(int, map(round, box))
1405 absolute_values = (abs(x1 - x0), abs(y1 - y0))
1407 _decompression_bomb_check(absolute_values)
1409 return im.crop((x0, y0, x1, y1))
1411 def draft(
1412 self, mode: str | None, size: tuple[int, int] | None
1413 ) -> tuple[str, tuple[int, int, float, float]] | None:
1414 """
1415 Configures the image file loader so it returns a version of the
1416 image that as closely as possible matches the given mode and
1417 size. For example, you can use this method to convert a color
1418 JPEG to grayscale while loading it.
1420 If any changes are made, returns a tuple with the chosen ``mode`` and
1421 ``box`` with coordinates of the original image within the altered one.
1423 Note that this method modifies the :py:class:`~PIL.Image.Image` object
1424 in place. If the image has already been loaded, this method has no
1425 effect.
1427 Note: This method is not implemented for most images. It is
1428 currently implemented only for JPEG and MPO images.
1430 :param mode: The requested mode.
1431 :param size: The requested size in pixels, as a 2-tuple:
1432 (width, height).
1433 """
1434 pass
1436 def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image:
1437 """
1438 Filters this image using the given filter. For a list of
1439 available filters, see the :py:mod:`~PIL.ImageFilter` module.
1441 :param filter: Filter kernel.
1442 :returns: An :py:class:`~PIL.Image.Image` object."""
1444 from . import ImageFilter
1446 self.load()
1448 if callable(filter):
1449 filter = filter()
1450 if not hasattr(filter, "filter"):
1451 msg = "filter argument should be ImageFilter.Filter instance or class"
1452 raise TypeError(msg)
1454 multiband = isinstance(filter, ImageFilter.MultibandFilter)
1455 if self.im.bands == 1 or multiband:
1456 return self._new(filter.filter(self.im))
1458 ims = [
1459 self._new(filter.filter(self.im.getband(c))) for c in range(self.im.bands)
1460 ]
1461 return merge(self.mode, ims)
1463 def getbands(self) -> tuple[str, ...]:
1464 """
1465 Returns a tuple containing the name of each band in this image.
1466 For example, ``getbands`` on an RGB image returns ("R", "G", "B").
1468 :returns: A tuple containing band names.
1469 """
1470 return ImageMode.getmode(self.mode).bands
1472 def getbbox(self, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None:
1473 """
1474 Calculates the bounding box of the non-zero regions in the
1475 image.
1477 :param alpha_only: Optional flag, defaulting to ``True``.
1478 If ``True`` and the image has an alpha channel, trim transparent pixels.
1479 Otherwise, trim pixels when all channels are zero.
1480 Keyword-only argument.
1481 :returns: The bounding box is returned as a 4-tuple defining the
1482 left, upper, right, and lower pixel coordinate. See
1483 :ref:`coordinate-system`. If the image is completely empty, this
1484 method returns None.
1486 """
1488 self.load()
1489 return self.im.getbbox(alpha_only)
1491 def getcolors(
1492 self, maxcolors: int = 256
1493 ) -> list[tuple[int, tuple[int, ...]]] | list[tuple[int, float]] | None:
1494 """
1495 Returns a list of colors used in this image.
1497 The colors will be in the image's mode. For example, an RGB image will
1498 return a tuple of (red, green, blue) color values, and a P image will
1499 return the index of the color in the palette.
1501 :param maxcolors: Maximum number of colors. If this number is
1502 exceeded, this method returns None. The default limit is
1503 256 colors.
1504 :returns: An unsorted list of (count, pixel) values.
1505 """
1507 self.load()
1508 if self.mode in ("1", "L", "P"):
1509 h = self.im.histogram()
1510 out: list[tuple[int, float]] = [(h[i], i) for i in range(256) if h[i]]
1511 if len(out) > maxcolors:
1512 return None
1513 return out
1514 return self.im.getcolors(maxcolors)
1516 def getdata(self, band: int | None = None) -> core.ImagingCore:
1517 """
1518 Returns the contents of this image as a sequence object
1519 containing pixel values. The sequence object is flattened, so
1520 that values for line one follow directly after the values of
1521 line zero, and so on.
1523 Note that the sequence object returned by this method is an
1524 internal PIL data type, which only supports certain sequence
1525 operations. To convert it to an ordinary sequence (e.g. for
1526 printing), use ``list(im.getdata())``.
1528 :param band: What band to return. The default is to return
1529 all bands. To return a single band, pass in the index
1530 value (e.g. 0 to get the "R" band from an "RGB" image).
1531 :returns: A sequence-like object.
1532 """
1533 deprecate("Image.Image.getdata", 14, "get_flattened_data")
1535 self.load()
1536 if band is not None:
1537 return self.im.getband(band)
1538 return self.im # could be abused
1540 def get_flattened_data(
1541 self, band: int | None = None
1542 ) -> tuple[tuple[int, ...], ...] | tuple[float, ...]:
1543 """
1544 Returns the contents of this image as a tuple containing pixel values.
1545 The sequence object is flattened, so that values for line one follow
1546 directly after the values of line zero, and so on.
1548 :param band: What band to return. The default is to return
1549 all bands. To return a single band, pass in the index
1550 value (e.g. 0 to get the "R" band from an "RGB" image).
1551 :returns: A tuple containing pixel values.
1552 """
1553 self.load()
1554 if band is not None:
1555 return tuple(self.im.getband(band))
1556 return tuple(self.im)
1558 def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]:
1559 """
1560 Gets the minimum and maximum pixel values for each band in
1561 the image.
1563 :returns: For a single-band image, a 2-tuple containing the
1564 minimum and maximum pixel value. For a multi-band image,
1565 a tuple containing one 2-tuple for each band.
1566 """
1568 self.load()
1569 if self.im.bands > 1:
1570 return tuple(self.im.getband(i).getextrema() for i in range(self.im.bands))
1571 return self.im.getextrema()
1573 def getxmp(self) -> dict[str, Any]:
1574 """
1575 Returns a dictionary containing the XMP tags.
1576 Requires defusedxml to be installed.
1578 :returns: XMP tags in a dictionary.
1579 """
1581 def get_name(tag: str) -> str:
1582 return re.sub("^{[^}]+}", "", tag)
1584 def get_value(element: Element) -> str | dict[str, Any] | None:
1585 value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()}
1586 children = list(element)
1587 if children:
1588 for child in children:
1589 name = get_name(child.tag)
1590 child_value = get_value(child)
1591 if name in value:
1592 if not isinstance(value[name], list):
1593 value[name] = [value[name]]
1594 value[name].append(child_value)
1595 else:
1596 value[name] = child_value
1597 elif value:
1598 if element.text:
1599 value["text"] = element.text
1600 else:
1601 return element.text
1602 return value
1604 if ElementTree is None:
1605 warnings.warn("XMP data cannot be read without defusedxml dependency")
1606 return {}
1607 if "xmp" not in self.info:
1608 return {}
1609 root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 "))
1610 return {get_name(root.tag): get_value(root)}
1612 def getexif(self) -> Exif:
1613 """
1614 Gets EXIF data from the image.
1616 :returns: an :py:class:`~PIL.Image.Exif` object.
1617 """
1618 if self._exif is None:
1619 self._exif = Exif()
1620 elif self._exif._loaded:
1621 return self._exif
1622 self._exif._loaded = True
1624 exif_info = self.info.get("exif")
1625 if exif_info is None:
1626 if "Raw profile type exif" in self.info:
1627 exif_info = bytes.fromhex(
1628 "".join(self.info["Raw profile type exif"].split("\n")[3:])
1629 )
1630 elif hasattr(self, "tag_v2"):
1631 from . import TiffImagePlugin
1633 assert isinstance(self, TiffImagePlugin.TiffImageFile)
1634 self._exif.bigtiff = self.tag_v2._bigtiff
1635 self._exif.endian = self.tag_v2._endian
1637 assert self.fp is not None
1638 self._exif.load_from_fp(self.fp, self.tag_v2._offset)
1639 if exif_info is not None:
1640 self._exif.load(exif_info)
1642 # XMP tags
1643 if ExifTags.Base.Orientation not in self._exif:
1644 xmp_tags = self.info.get("XML:com.adobe.xmp")
1645 pattern: str | bytes = r'tiff:Orientation(="|>)([0-9])'
1646 if not xmp_tags and (xmp_tags := self.info.get("xmp")):
1647 pattern = rb'tiff:Orientation(="|>)([0-9])'
1648 if xmp_tags:
1649 match = re.search(pattern, xmp_tags)
1650 if match:
1651 self._exif[ExifTags.Base.Orientation] = int(match[2])
1653 return self._exif
1655 def _reload_exif(self) -> None:
1656 if self._exif is None or not self._exif._loaded:
1657 return
1658 self._exif._loaded = False
1659 self.getexif()
1661 def getim(self) -> CapsuleType:
1662 """
1663 Returns a capsule that points to the internal image memory.
1665 :returns: A capsule object.
1666 """
1668 self.load()
1669 return self.im.ptr
1671 def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None:
1672 """
1673 Returns the image palette as a list.
1675 :param rawmode: The mode in which to return the palette. ``None`` will
1676 return the palette in its current mode.
1678 .. versionadded:: 9.1.0
1680 :returns: A list of color values [r, g, b, ...], or None if the
1681 image has no palette.
1682 """
1684 self.load()
1685 try:
1686 mode = self.im.getpalettemode()
1687 except ValueError:
1688 return None # no palette
1689 if rawmode is None:
1690 rawmode = mode
1691 return list(self.im.getpalette(mode, rawmode))
1693 @property
1694 def has_transparency_data(self) -> bool:
1695 """
1696 Determine if an image has transparency data, whether in the form of an
1697 alpha channel, a palette with an alpha channel, or a "transparency" key
1698 in the info dictionary.
1700 Note the image might still appear solid, if all of the values shown
1701 within are opaque.
1703 :returns: A boolean.
1704 """
1705 if (
1706 self.mode in ("LA", "La", "PA", "RGBA", "RGBa")
1707 or "transparency" in self.info
1708 ):
1709 return True
1710 if self.mode == "P":
1711 assert self.palette is not None
1712 return self.palette.mode.endswith("A")
1713 return False
1715 def apply_transparency(self) -> None:
1716 """
1717 If a P mode image has a "transparency" key in the info dictionary,
1718 remove the key and instead apply the transparency to the palette.
1719 Otherwise, the image is unchanged.
1720 """
1721 if self.mode != "P" or "transparency" not in self.info:
1722 return
1724 from . import ImagePalette
1726 palette = self.getpalette("RGBA")
1727 assert palette is not None
1728 transparency = self.info["transparency"]
1729 if isinstance(transparency, bytes):
1730 for i, alpha in enumerate(transparency):
1731 palette[i * 4 + 3] = alpha
1732 else:
1733 palette[transparency * 4 + 3] = 0
1734 self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette))
1735 self.palette.dirty = 1
1737 del self.info["transparency"]
1739 def getpixel(
1740 self, xy: tuple[int, int] | list[int]
1741 ) -> float | tuple[int, ...] | None:
1742 """
1743 Returns the pixel value at a given position.
1745 :param xy: The coordinate, given as (x, y). See
1746 :ref:`coordinate-system`.
1747 :returns: The pixel value. If the image is a multi-layer image,
1748 this method returns a tuple.
1749 """
1751 self.load()
1752 return self.im.getpixel(tuple(xy))
1754 def getprojection(self) -> tuple[list[int], list[int]]:
1755 """
1756 Get projection to x and y axes
1758 :returns: Two sequences, indicating where there are non-zero
1759 pixels along the X-axis and the Y-axis, respectively.
1760 """
1762 self.load()
1763 x, y = self.im.getprojection()
1764 return list(x), list(y)
1766 def histogram(
1767 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1768 ) -> list[int]:
1769 """
1770 Returns a histogram for the image. The histogram is returned as a
1771 list of pixel counts, one for each pixel value in the source
1772 image. Counts are grouped into 256 bins for each band, even if
1773 the image has more than 8 bits per band. If the image has more
1774 than one band, the histograms for all bands are concatenated (for
1775 example, the histogram for an "RGB" image contains 768 values).
1777 A bilevel image (mode "1") is treated as a grayscale ("L") image
1778 by this method.
1780 If a mask is provided, the method returns a histogram for those
1781 parts of the image where the mask image is non-zero. The mask
1782 image must have the same size as the image, and be either a
1783 bi-level image (mode "1") or a grayscale image ("L").
1785 :param mask: An optional mask.
1786 :param extrema: An optional tuple of manually-specified extrema.
1787 :returns: A list containing pixel counts.
1788 """
1789 self.load()
1790 if mask:
1791 mask.load()
1792 return self.im.histogram((0, 0), mask.im)
1793 if self.mode in ("I", "F"):
1794 return self.im.histogram(
1795 extrema if extrema is not None else self.getextrema()
1796 )
1797 return self.im.histogram()
1799 def entropy(
1800 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1801 ) -> float:
1802 """
1803 Calculates and returns the entropy for the image.
1805 A bilevel image (mode "1") is treated as a grayscale ("L")
1806 image by this method.
1808 If a mask is provided, the method employs the histogram for
1809 those parts of the image where the mask image is non-zero.
1810 The mask image must have the same size as the image, and be
1811 either a bi-level image (mode "1") or a grayscale image ("L").
1813 :param mask: An optional mask.
1814 :param extrema: An optional tuple of manually-specified extrema.
1815 :returns: A float value representing the image entropy
1816 """
1817 self.load()
1818 if mask:
1819 mask.load()
1820 return self.im.entropy((0, 0), mask.im)
1821 if self.mode in ("I", "F"):
1822 return self.im.entropy(
1823 extrema if extrema is not None else self.getextrema()
1824 )
1825 return self.im.entropy()
1827 def paste(
1828 self,
1829 im: Image | str | float | tuple[float, ...],
1830 box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None,
1831 mask: Image | None = None,
1832 ) -> None:
1833 """
1834 Pastes another image into this image. The box argument is either
1835 a 2-tuple giving the upper left corner, a 4-tuple defining the
1836 left, upper, right, and lower pixel coordinate, or None (same as
1837 (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size
1838 of the pasted image must match the size of the region.
1840 If the modes don't match, the pasted image is converted to the mode of
1841 this image (see the :py:meth:`~PIL.Image.Image.convert` method for
1842 details).
1844 Instead of an image, the source can be a integer or tuple
1845 containing pixel values. The method then fills the region
1846 with the given color. When creating RGB images, you can
1847 also use color strings as supported by the ImageColor module. See
1848 :ref:`colors` for more information.
1850 If a mask is given, this method updates only the regions
1851 indicated by the mask. You can use either "1", "L", "LA", "RGBA"
1852 or "RGBa" images (if present, the alpha band is used as mask).
1853 Where the mask is 255, the given image is copied as is. Where
1854 the mask is 0, the current value is preserved. Intermediate
1855 values will mix the two images together, including their alpha
1856 channels if they have them.
1858 See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
1859 combine images with respect to their alpha channels.
1861 :param im: Source image or pixel value (integer, float or tuple).
1862 :param box: An optional 4-tuple giving the region to paste into.
1863 If a 2-tuple is used instead, it's treated as the upper left
1864 corner. If omitted or None, the source is pasted into the
1865 upper left corner.
1867 If an image is given as the second argument and there is no
1868 third, the box defaults to (0, 0), and the second argument
1869 is interpreted as a mask image.
1870 :param mask: An optional mask image.
1871 """
1873 if isinstance(box, Image):
1874 if mask is not None:
1875 msg = "If using second argument as mask, third argument must be None"
1876 raise ValueError(msg)
1877 # abbreviated paste(im, mask) syntax
1878 mask = box
1879 box = None
1881 if box is None:
1882 box = (0, 0)
1884 if len(box) == 2:
1885 # upper left corner given; get size from image or mask
1886 if isinstance(im, Image):
1887 size = im.size
1888 elif isinstance(mask, Image):
1889 size = mask.size
1890 else:
1891 # FIXME: use self.size here?
1892 msg = "cannot determine region size; use 4-item box"
1893 raise ValueError(msg)
1894 box += (box[0] + size[0], box[1] + size[1])
1896 source: core.ImagingCore | str | float | tuple[float, ...]
1897 if isinstance(im, str):
1898 from . import ImageColor
1900 source = ImageColor.getcolor(im, self.mode)
1901 elif isinstance(im, Image):
1902 im.load()
1903 if self.mode != im.mode:
1904 if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"):
1905 # should use an adapter for this!
1906 im = im.convert(self.mode)
1907 source = im.im
1908 else:
1909 source = im
1911 self._ensure_mutable()
1913 if mask:
1914 mask.load()
1915 self.im.paste(source, box, mask.im)
1916 else:
1917 self.im.paste(source, box)
1919 def alpha_composite(
1920 self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0)
1921 ) -> None:
1922 """'In-place' analog of Image.alpha_composite. Composites an image
1923 onto this image.
1925 :param im: image to composite over this one
1926 :param dest: Optional 2 tuple (left, top) specifying the upper
1927 left corner in this (destination) image.
1928 :param source: Optional 2 (left, top) tuple for the upper left
1929 corner in the overlay source image, or 4 tuple (left, top, right,
1930 bottom) for the bounds of the source rectangle
1932 Performance Note: Not currently implemented in-place in the core layer.
1933 """
1935 if not isinstance(source, (list, tuple)):
1936 msg = "Source must be a list or tuple"
1937 raise ValueError(msg)
1938 if not isinstance(dest, (list, tuple)):
1939 msg = "Destination must be a list or tuple"
1940 raise ValueError(msg)
1942 if len(source) == 4:
1943 overlay_crop_box = tuple(source)
1944 elif len(source) == 2:
1945 overlay_crop_box = tuple(source) + im.size
1946 else:
1947 msg = "Source must be a sequence of length 2 or 4"
1948 raise ValueError(msg)
1950 if not len(dest) == 2:
1951 msg = "Destination must be a sequence of length 2"
1952 raise ValueError(msg)
1953 if min(source) < 0:
1954 msg = "Source must be non-negative"
1955 raise ValueError(msg)
1957 # over image, crop if it's not the whole image.
1958 if overlay_crop_box == (0, 0) + im.size:
1959 overlay = im
1960 else:
1961 overlay = im.crop(overlay_crop_box)
1963 # target for the paste
1964 box = tuple(dest) + (dest[0] + overlay.width, dest[1] + overlay.height)
1966 # destination image. don't copy if we're using the whole image.
1967 if box == (0, 0) + self.size:
1968 background = self
1969 else:
1970 background = self.crop(box)
1972 result = alpha_composite(background, overlay)
1973 self.paste(result, box)
1975 def point(
1976 self,
1977 lut: (
1978 Sequence[float]
1979 | NumpyArray
1980 | Callable[[int], float]
1981 | Callable[[ImagePointTransform], ImagePointTransform | float]
1982 | ImagePointHandler
1983 ),
1984 mode: str | None = None,
1985 ) -> Image:
1986 """
1987 Maps this image through a lookup table or function.
1989 :param lut: A lookup table, containing 256 (or 65536 if
1990 self.mode=="I" and mode == "L") values per band in the
1991 image. A function can be used instead, it should take a
1992 single argument. The function is called once for each
1993 possible pixel value, and the resulting table is applied to
1994 all bands of the image.
1996 It may also be an :py:class:`~PIL.Image.ImagePointHandler`
1997 object::
1999 class Example(Image.ImagePointHandler):
2000 def point(self, im: Image) -> Image:
2001 # Return result
2002 :param mode: Output mode (default is same as input). This can only be used if
2003 the source image has mode "L" or "P", and the output has mode "1" or the
2004 source image mode is "I" and the output mode is "L".
2005 :returns: An :py:class:`~PIL.Image.Image` object.
2006 """
2008 self.load()
2010 if isinstance(lut, ImagePointHandler):
2011 return lut.point(self)
2013 if callable(lut):
2014 # if it isn't a list, it should be a function
2015 if self.mode in ("I", "I;16", "F"):
2016 # check if the function can be used with point_transform
2017 # UNDONE wiredfool -- I think this prevents us from ever doing
2018 # a gamma function point transform on > 8bit images.
2019 scale, offset = _getscaleoffset(lut) # type: ignore[arg-type]
2020 return self._new(self.im.point_transform(scale, offset))
2021 # for other modes, convert the function to a table
2022 flatLut = [lut(i) for i in range(256)] * self.im.bands # type: ignore[arg-type]
2023 else:
2024 flatLut = lut
2026 if self.mode == "F":
2027 # FIXME: _imaging returns a confusing error message for this case
2028 msg = "point operation not supported for this mode"
2029 raise ValueError(msg)
2031 if mode != "F":
2032 flatLut = [round(i) for i in flatLut]
2033 return self._new(self.im.point(flatLut, mode))
2035 def putalpha(self, alpha: Image | int) -> None:
2036 """
2037 Adds or replaces the alpha layer in this image. If the image
2038 does not have an alpha layer, it's converted to "LA" or "RGBA".
2039 The new layer must be either "L" or "1".
2041 :param alpha: The new alpha layer. This can either be an "L" or "1"
2042 image having the same size as this image, or an integer.
2043 """
2045 self._ensure_mutable()
2047 if self.mode not in ("LA", "PA", "RGBA"):
2048 # attempt to promote self to a matching alpha mode
2049 try:
2050 mode = getmodebase(self.mode) + "A"
2051 try:
2052 self.im.setmode(mode)
2053 except (AttributeError, ValueError) as e:
2054 # do things the hard way
2055 im = self.im.convert(mode)
2056 if im.mode not in ("LA", "PA", "RGBA"):
2057 msg = "alpha channel could not be added"
2058 raise ValueError(msg) from e # sanity check
2059 self.im = im
2060 self._mode = self.im.mode
2061 except KeyError as e:
2062 msg = "illegal image mode"
2063 raise ValueError(msg) from e
2065 if self.mode in ("LA", "PA"):
2066 band = 1
2067 else:
2068 band = 3
2070 if isinstance(alpha, Image):
2071 # alpha layer
2072 if alpha.mode not in ("1", "L"):
2073 msg = "illegal image mode"
2074 raise ValueError(msg)
2075 alpha.load()
2076 if alpha.mode == "1":
2077 alpha = alpha.convert("L")
2078 else:
2079 # constant alpha
2080 try:
2081 self.im.fillband(band, alpha)
2082 except (AttributeError, ValueError):
2083 # do things the hard way
2084 alpha = new("L", self.size, alpha)
2085 else:
2086 return
2088 self.im.putband(alpha.im, band)
2090 def putdata(
2091 self,
2092 data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray,
2093 scale: float = 1.0,
2094 offset: float = 0.0,
2095 ) -> None:
2096 """
2097 Copies pixel data from a flattened sequence object into the image. The
2098 values should start at the upper left corner (0, 0), continue to the
2099 end of the line, followed directly by the first value of the second
2100 line, and so on. Data will be read until either the image or the
2101 sequence ends. The scale and offset values are used to adjust the
2102 sequence values: **pixel = value*scale + offset**.
2104 :param data: A flattened sequence object. See :ref:`colors` for more
2105 information about values.
2106 :param scale: An optional scale value. The default is 1.0.
2107 :param offset: An optional offset value. The default is 0.0.
2108 """
2110 self._ensure_mutable()
2112 self.im.putdata(data, scale, offset)
2114 def putpalette(
2115 self,
2116 data: ImagePalette.ImagePalette | bytes | Sequence[int],
2117 rawmode: str = "RGB",
2118 ) -> None:
2119 """
2120 Attaches a palette to this image. The image must be a "P", "PA", "L"
2121 or "LA" image.
2123 The palette sequence must contain at most 256 colors, made up of one
2124 integer value for each channel in the raw mode.
2125 For example, if the raw mode is "RGB", then it can contain at most 768
2126 values, made up of red, green and blue values for the corresponding pixel
2127 index in the 256 colors.
2128 If the raw mode is "RGBA", then it can contain at most 1024 values,
2129 containing red, green, blue and alpha values.
2131 Alternatively, an 8-bit string may be used instead of an integer sequence.
2133 :param data: A palette sequence (either a list or a string).
2134 :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", "CMYK", or a
2135 mode that can be transformed to one of those modes (e.g. "R", "RGBA;L").
2136 """
2137 from . import ImagePalette
2139 if self.mode not in ("L", "LA", "P", "PA"):
2140 msg = "illegal image mode"
2141 raise ValueError(msg)
2142 if isinstance(data, ImagePalette.ImagePalette):
2143 if data.rawmode is not None:
2144 palette = ImagePalette.raw(data.rawmode, data.palette)
2145 else:
2146 palette = ImagePalette.ImagePalette(palette=data.palette)
2147 palette.dirty = 1
2148 else:
2149 if not isinstance(data, bytes):
2150 data = bytes(data)
2151 palette = ImagePalette.raw(rawmode, data)
2152 self._mode = "PA" if "A" in self.mode else "P"
2153 self.palette = palette
2154 if rawmode.startswith("CMYK"):
2155 self.palette.mode = "CMYK"
2156 elif "A" in rawmode:
2157 self.palette.mode = "RGBA"
2158 else:
2159 self.palette.mode = "RGB"
2160 self.load() # install new palette
2162 def putpixel(
2163 self,
2164 xy: tuple[int, int] | list[int],
2165 value: float | tuple[int, ...] | list[int],
2166 ) -> None:
2167 """
2168 Modifies the pixel at the given position. The color is given as
2169 a single numerical value for single-band images, and a tuple for
2170 multi-band images. In addition to this, RGB and RGBA tuples are
2171 accepted for P and PA images. See :ref:`colors` for more information.
2173 Note that this method is relatively slow. For more extensive changes,
2174 use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
2175 module instead.
2177 See:
2179 * :py:meth:`~PIL.Image.Image.paste`
2180 * :py:meth:`~PIL.Image.Image.putdata`
2181 * :py:mod:`~PIL.ImageDraw`
2183 :param xy: The pixel coordinate, given as (x, y). See
2184 :ref:`coordinate-system`.
2185 :param value: The pixel value.
2186 """
2188 self._ensure_mutable()
2190 if (
2191 self.mode in ("P", "PA")
2192 and isinstance(value, (list, tuple))
2193 and len(value) in [3, 4]
2194 ):
2195 # RGB or RGBA value for a P or PA image
2196 if self.mode == "PA":
2197 alpha = value[3] if len(value) == 4 else 255
2198 value = value[:3]
2199 assert self.palette is not None
2200 palette_index = self.palette.getcolor(tuple(value), self)
2201 value = (palette_index, alpha) if self.mode == "PA" else palette_index
2202 return self.im.putpixel(xy, value)
2204 def remap_palette(
2205 self, dest_map: list[int], source_palette: bytes | bytearray | None = None
2206 ) -> Image:
2207 """
2208 Rewrites the image to reorder the palette.
2210 :param dest_map: A list of indexes into the original palette.
2211 e.g. ``[1,0]`` would swap a two item palette, and ``list(range(256))``
2212 is the identity transform.
2213 :param source_palette: Bytes or None.
2214 :returns: An :py:class:`~PIL.Image.Image` object.
2216 """
2217 from . import ImagePalette
2219 if self.mode not in ("L", "P"):
2220 msg = "illegal image mode"
2221 raise ValueError(msg)
2223 bands = 3
2224 palette_mode = "RGB"
2225 if source_palette is None:
2226 if self.mode == "P":
2227 self.load()
2228 palette_mode = self.im.getpalettemode()
2229 if palette_mode == "RGBA":
2230 bands = 4
2231 source_palette = self.im.getpalette(palette_mode)
2232 else: # L-mode
2233 source_palette = bytearray(i // 3 for i in range(768))
2234 elif len(source_palette) > 768:
2235 bands = 4
2236 palette_mode = "RGBA"
2238 palette_bytes = b""
2239 new_positions = [0] * 256
2241 # pick only the used colors from the palette
2242 for i, oldPosition in enumerate(dest_map):
2243 palette_bytes += source_palette[
2244 oldPosition * bands : oldPosition * bands + bands
2245 ]
2246 new_positions[oldPosition] = i
2248 # replace the palette color id of all pixel with the new id
2250 # Palette images are [0..255], mapped through a 1 or 3
2251 # byte/color map. We need to remap the whole image
2252 # from palette 1 to palette 2. New_positions is
2253 # an array of indexes into palette 1. Palette 2 is
2254 # palette 1 with any holes removed.
2256 # We're going to leverage the convert mechanism to use the
2257 # C code to remap the image from palette 1 to palette 2,
2258 # by forcing the source image into 'L' mode and adding a
2259 # mapping 'L' mode palette, then converting back to 'L'
2260 # sans palette thus converting the image bytes, then
2261 # assigning the optimized RGB palette.
2263 # perf reference, 9500x4000 gif, w/~135 colors
2264 # 14 sec prepatch, 1 sec postpatch with optimization forced.
2266 mapping_palette = bytearray(new_positions)
2268 m_im = self.copy()
2269 m_im._mode = "P"
2271 m_im.palette = ImagePalette.ImagePalette(
2272 palette_mode, palette=mapping_palette * bands
2273 )
2274 # possibly set palette dirty, then
2275 # m_im.putpalette(mapping_palette, 'L') # converts to 'P'
2276 # or just force it.
2277 # UNDONE -- this is part of the general issue with palettes
2278 m_im.im.putpalette(palette_mode, palette_mode + ";L", m_im.palette.tobytes())
2280 m_im = m_im.convert("L")
2282 m_im.putpalette(palette_bytes, palette_mode)
2283 m_im.palette = ImagePalette.ImagePalette(palette_mode, palette=palette_bytes)
2285 if "transparency" in self.info:
2286 try:
2287 m_im.info["transparency"] = dest_map.index(self.info["transparency"])
2288 except ValueError:
2289 if "transparency" in m_im.info:
2290 del m_im.info["transparency"]
2292 return m_im
2294 def _get_safe_box(
2295 self,
2296 size: tuple[int, int],
2297 resample: Resampling,
2298 box: tuple[float, float, float, float],
2299 ) -> tuple[int, int, int, int]:
2300 """Expands the box so it includes adjacent pixels
2301 that may be used by resampling with the given resampling filter.
2302 """
2303 filter_support = _filters_support[resample] - 0.5
2304 scale_x = (box[2] - box[0]) / size[0]
2305 scale_y = (box[3] - box[1]) / size[1]
2306 support_x = filter_support * scale_x
2307 support_y = filter_support * scale_y
2309 return (
2310 max(0, int(box[0] - support_x)),
2311 max(0, int(box[1] - support_y)),
2312 min(self.size[0], math.ceil(box[2] + support_x)),
2313 min(self.size[1], math.ceil(box[3] + support_y)),
2314 )
2316 def resize(
2317 self,
2318 size: tuple[int, int] | list[int] | NumpyArray,
2319 resample: int | None = None,
2320 box: tuple[float, float, float, float] | None = None,
2321 reducing_gap: float | None = None,
2322 ) -> Image:
2323 """
2324 Returns a resized copy of this image.
2326 :param size: The requested size in pixels, as a tuple or array:
2327 (width, height).
2328 :param resample: An optional resampling filter. This can be
2329 one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2330 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2331 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`.
2332 If the image has mode "1" or "P", it is always set to
2333 :py:data:`Resampling.NEAREST`. Otherwise, the default filter is
2334 :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`.
2335 :param box: An optional 4-tuple of floats providing
2336 the source image region to be scaled.
2337 The values must be within (0, 0, width, height) rectangle.
2338 If omitted or None, the entire source is used.
2339 :param reducing_gap: Apply optimization by resizing the image
2340 in two steps. First, reducing the image by integer times
2341 using :py:meth:`~PIL.Image.Image.reduce`.
2342 Second, resizing using regular resampling. The last step
2343 changes size no less than by ``reducing_gap`` times.
2344 ``reducing_gap`` may be None (no first step is performed)
2345 or should be greater than 1.0. The bigger ``reducing_gap``,
2346 the closer the result to the fair resampling.
2347 The smaller ``reducing_gap``, the faster resizing.
2348 With ``reducing_gap`` greater or equal to 3.0, the result is
2349 indistinguishable from fair resampling in most cases.
2350 The default value is None (no optimization).
2351 :returns: An :py:class:`~PIL.Image.Image` object.
2352 """
2354 if resample is None:
2355 resample = Resampling.BICUBIC
2356 elif resample not in (
2357 Resampling.NEAREST,
2358 Resampling.BILINEAR,
2359 Resampling.BICUBIC,
2360 Resampling.LANCZOS,
2361 Resampling.BOX,
2362 Resampling.HAMMING,
2363 ):
2364 msg = f"Unknown resampling filter ({resample})."
2366 filters = [
2367 f"{filter[1]} ({filter[0]})"
2368 for filter in (
2369 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
2370 (Resampling.LANCZOS, "Image.Resampling.LANCZOS"),
2371 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
2372 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
2373 (Resampling.BOX, "Image.Resampling.BOX"),
2374 (Resampling.HAMMING, "Image.Resampling.HAMMING"),
2375 )
2376 ]
2377 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
2378 raise ValueError(msg)
2380 if reducing_gap is not None and reducing_gap < 1.0:
2381 msg = "reducing_gap must be 1.0 or greater"
2382 raise ValueError(msg)
2384 if box is None:
2385 box = (0, 0) + self.size
2387 size = tuple(size)
2388 if self.size == size and box == (0, 0) + self.size:
2389 return self.copy()
2391 if self.mode in ("1", "P"):
2392 resample = Resampling.NEAREST
2394 if self.mode in ["LA", "RGBA"] and resample != Resampling.NEAREST:
2395 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2396 im = im.resize(size, resample, box)
2397 return im.convert(self.mode)
2399 self.load()
2401 if reducing_gap is not None and resample != Resampling.NEAREST:
2402 factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1
2403 factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1
2404 if factor_x > 1 or factor_y > 1:
2405 reduce_box = self._get_safe_box(size, cast(Resampling, resample), box)
2406 factor = (factor_x, factor_y)
2407 self = (
2408 self.reduce(factor, box=reduce_box)
2409 if callable(self.reduce)
2410 else Image.reduce(self, factor, box=reduce_box)
2411 )
2412 box = (
2413 (box[0] - reduce_box[0]) / factor_x,
2414 (box[1] - reduce_box[1]) / factor_y,
2415 (box[2] - reduce_box[0]) / factor_x,
2416 (box[3] - reduce_box[1]) / factor_y,
2417 )
2419 if self.size[1] > self.size[0] * 100 and size[1] < self.size[1]:
2420 im = self.im.resize(
2421 (self.size[0], size[1]), resample, (0, box[1], self.size[0], box[3])
2422 )
2423 im = im.resize(size, resample, (box[0], 0, box[2], size[1]))
2424 else:
2425 im = self.im.resize(size, resample, box)
2426 return self._new(im)
2428 def reduce(
2429 self,
2430 factor: int | tuple[int, int],
2431 box: tuple[int, int, int, int] | None = None,
2432 ) -> Image:
2433 """
2434 Returns a copy of the image reduced ``factor`` times.
2435 If the size of the image is not dividable by ``factor``,
2436 the resulting size will be rounded up.
2438 :param factor: A greater than 0 integer or tuple of two integers
2439 for width and height separately.
2440 :param box: An optional 4-tuple of ints providing
2441 the source image region to be reduced.
2442 The values must be within ``(0, 0, width, height)`` rectangle.
2443 If omitted or ``None``, the entire source is used.
2444 """
2445 if not isinstance(factor, (list, tuple)):
2446 factor = (factor, factor)
2448 if box is None:
2449 box = (0, 0) + self.size
2451 if factor == (1, 1) and box == (0, 0) + self.size:
2452 return self.copy()
2454 if self.mode in ["LA", "RGBA"]:
2455 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2456 im = im.reduce(factor, box)
2457 return im.convert(self.mode)
2459 self.load()
2461 return self._new(self.im.reduce(factor, box))
2463 def rotate(
2464 self,
2465 angle: float,
2466 resample: Resampling = Resampling.NEAREST,
2467 expand: int | bool = False,
2468 center: tuple[float, float] | None = None,
2469 translate: tuple[int, int] | None = None,
2470 fillcolor: float | tuple[float, ...] | str | None = None,
2471 ) -> Image:
2472 """
2473 Returns a rotated copy of this image. This method returns a
2474 copy of this image, rotated the given number of degrees counter
2475 clockwise around its centre.
2477 :param angle: In degrees counter clockwise.
2478 :param resample: An optional resampling filter. This can be
2479 one of :py:data:`Resampling.NEAREST` (use nearest neighbour),
2480 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2481 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2482 interpolation in a 4x4 environment). If omitted, or if the image has
2483 mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`.
2484 See :ref:`concept-filters`.
2485 :param expand: Optional expansion flag. If true, expands the output
2486 image to make it large enough to hold the entire rotated image.
2487 If false or omitted, make the output image the same size as the
2488 input image. Note that the expand flag assumes rotation around
2489 the center and no translation.
2490 :param center: Optional center of rotation (a 2-tuple). Origin is
2491 the upper left corner. Default is the center of the image.
2492 :param translate: An optional post-rotate translation (a 2-tuple).
2493 :param fillcolor: An optional color for area outside the rotated image.
2494 :returns: An :py:class:`~PIL.Image.Image` object.
2495 """
2497 angle = angle % 360.0
2499 # Fast paths regardless of filter, as long as we're not
2500 # translating or changing the center.
2501 if not (center or translate):
2502 if angle == 0:
2503 return self.copy()
2504 if angle == 180:
2505 return self.transpose(Transpose.ROTATE_180)
2506 if angle in (90, 270) and (expand or self.width == self.height):
2507 return self.transpose(
2508 Transpose.ROTATE_90 if angle == 90 else Transpose.ROTATE_270
2509 )
2511 # Calculate the affine matrix. Note that this is the reverse
2512 # transformation (from destination image to source) because we
2513 # want to interpolate the (discrete) destination pixel from
2514 # the local area around the (floating) source pixel.
2516 # The matrix we actually want (note that it operates from the right):
2517 # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx)
2518 # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
2519 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1)
2521 # The reverse matrix is thus:
2522 # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx)
2523 # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
2524 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1)
2526 # In any case, the final translation may be updated at the end to
2527 # compensate for the expand flag.
2529 w, h = self.size
2531 if translate is None:
2532 post_trans = (0, 0)
2533 else:
2534 post_trans = translate
2535 if center is None:
2536 center = (w / 2, h / 2)
2538 angle = -math.radians(angle)
2539 matrix = [
2540 round(math.cos(angle), 15),
2541 round(math.sin(angle), 15),
2542 0.0,
2543 round(-math.sin(angle), 15),
2544 round(math.cos(angle), 15),
2545 0.0,
2546 ]
2548 def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]:
2549 a, b, c, d, e, f = matrix
2550 return a * x + b * y + c, d * x + e * y + f
2552 matrix[2], matrix[5] = transform(
2553 -center[0] - post_trans[0], -center[1] - post_trans[1], matrix
2554 )
2555 matrix[2] += center[0]
2556 matrix[5] += center[1]
2558 if expand:
2559 # calculate output size
2560 xx = []
2561 yy = []
2562 for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
2563 transformed_x, transformed_y = transform(x, y, matrix)
2564 xx.append(transformed_x)
2565 yy.append(transformed_y)
2566 nw = math.ceil(max(xx)) - math.floor(min(xx))
2567 nh = math.ceil(max(yy)) - math.floor(min(yy))
2569 # We multiply a translation matrix from the right. Because of its
2570 # special form, this is the same as taking the image of the
2571 # translation vector as new translation vector.
2572 matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
2573 w, h = nw, nh
2575 return self.transform(
2576 (w, h), Transform.AFFINE, matrix, resample, fillcolor=fillcolor
2577 )
2579 def save(
2580 self, fp: StrOrBytesPath | IO[bytes], format: str | None = None, **params: Any
2581 ) -> None:
2582 """
2583 Saves this image under the given filename. If no format is
2584 specified, the format to use is determined from the filename
2585 extension, if possible.
2587 Keyword options can be used to provide additional instructions
2588 to the writer. If a writer doesn't recognise an option, it is
2589 silently ignored. The available options are described in the
2590 :doc:`image format documentation
2591 <../handbook/image-file-formats>` for each writer.
2593 You can use a file object instead of a filename. In this case,
2594 you must always specify the format. The file object must
2595 implement the ``seek``, ``tell``, and ``write``
2596 methods, and be opened in binary mode.
2598 :param fp: A filename (string), os.PathLike object or file object.
2599 :param format: Optional format override. If omitted, the
2600 format to use is determined from the filename extension.
2601 If a file object was used instead of a filename, this
2602 parameter should always be used.
2603 :param params: Extra parameters to the image writer. These can also be
2604 set on the image itself through ``encoderinfo``. This is useful when
2605 saving multiple images::
2607 # Saving XMP data to a single image
2608 from PIL import Image
2609 red = Image.new("RGB", (1, 1), "#f00")
2610 red.save("out.mpo", xmp=b"test")
2612 # Saving XMP data to the second frame of an image
2613 from PIL import Image
2614 black = Image.new("RGB", (1, 1))
2615 red = Image.new("RGB", (1, 1), "#f00")
2616 red.encoderinfo = {"xmp": b"test"}
2617 black.save("out.mpo", save_all=True, append_images=[red])
2618 :returns: None
2619 :exception ValueError: If the output format could not be determined
2620 from the file name. Use the format option to solve this.
2621 :exception OSError: If the file could not be written. The file
2622 may have been created, and may contain partial data.
2623 """
2625 filename: str | bytes = ""
2626 open_fp = False
2627 if is_path(fp):
2628 filename = os.fspath(fp)
2629 open_fp = True
2630 elif fp == sys.stdout and isinstance(sys.stdout, io.TextIOWrapper):
2631 fp = sys.stdout.buffer
2632 if not filename and hasattr(fp, "name") and is_path(fp.name):
2633 # only set the name for metadata purposes
2634 filename = os.fspath(fp.name)
2636 if format:
2637 preinit()
2638 else:
2639 filename_ext = os.path.splitext(filename)[1].lower()
2640 ext = (
2641 filename_ext.decode()
2642 if isinstance(filename_ext, bytes)
2643 else filename_ext
2644 )
2646 # Try importing only the plugin for this extension first
2647 if not _import_plugin_for_extension(ext):
2648 preinit()
2650 if ext not in EXTENSION:
2651 init()
2652 try:
2653 format = EXTENSION[ext]
2654 except KeyError as e:
2655 msg = f"unknown file extension: {ext}"
2656 raise ValueError(msg) from e
2658 from . import ImageFile
2660 # may mutate self!
2661 if isinstance(self, ImageFile.ImageFile) and os.path.abspath(
2662 filename
2663 ) == os.path.abspath(self.filename):
2664 self._ensure_mutable()
2665 else:
2666 self.load()
2668 save_all = params.pop("save_all", None)
2669 self._default_encoderinfo = params
2670 encoderinfo = getattr(self, "encoderinfo", {})
2671 self._attach_default_encoderinfo(self)
2672 self.encoderconfig: tuple[Any, ...] = ()
2674 if format.upper() not in SAVE:
2675 init()
2676 if save_all or (
2677 save_all is None
2678 and params.get("append_images")
2679 and format.upper() in SAVE_ALL
2680 ):
2681 save_handler = SAVE_ALL[format.upper()]
2682 else:
2683 save_handler = SAVE[format.upper()]
2685 created = False
2686 if open_fp:
2687 created = not os.path.exists(filename)
2688 if params.get("append", False):
2689 # Open also for reading ("+"), because TIFF save_all
2690 # writer needs to go back and edit the written data.
2691 fp = builtins.open(filename, "r+b")
2692 else:
2693 fp = builtins.open(filename, "w+b")
2694 else:
2695 fp = cast(IO[bytes], fp)
2697 try:
2698 save_handler(self, fp, filename)
2699 except Exception:
2700 if open_fp:
2701 fp.close()
2702 if created:
2703 try:
2704 os.remove(filename)
2705 except PermissionError:
2706 pass
2707 raise
2708 finally:
2709 self.encoderinfo = encoderinfo
2710 if open_fp:
2711 fp.close()
2713 def _attach_default_encoderinfo(self, im: Image) -> dict[str, Any]:
2714 encoderinfo = getattr(self, "encoderinfo", {})
2715 self.encoderinfo = {**im._default_encoderinfo, **encoderinfo}
2716 return encoderinfo
2718 def seek(self, frame: int) -> None:
2719 """
2720 Seeks to the given frame in this sequence file. If you seek
2721 beyond the end of the sequence, the method raises an
2722 ``EOFError`` exception. When a sequence file is opened, the
2723 library automatically seeks to frame 0.
2725 See :py:meth:`~PIL.Image.Image.tell`.
2727 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2728 number of available frames.
2730 :param frame: Frame number, starting at 0.
2731 :exception EOFError: If the call attempts to seek beyond the end
2732 of the sequence.
2733 """
2735 # overridden by file handlers
2736 if frame != 0:
2737 msg = "no more images in file"
2738 raise EOFError(msg)
2740 def show(self, title: str | None = None) -> None:
2741 """
2742 Displays this image. This method is mainly intended for debugging purposes.
2744 This method calls :py:func:`PIL.ImageShow.show` internally. You can use
2745 :py:func:`PIL.ImageShow.register` to override its default behaviour.
2747 The image is first saved to a temporary file. By default, it will be in
2748 PNG format.
2750 On Unix, the image is then opened using the **xdg-open**, **display**,
2751 **gm**, **eog** or **xv** utility, depending on which one can be found.
2753 On macOS, the image is opened with the native Preview application.
2755 On Windows, the image is opened with the standard PNG display utility.
2757 :param title: Optional title to use for the image window, where possible.
2758 """
2760 from . import ImageShow
2762 ImageShow.show(self, title)
2764 def split(self) -> tuple[Image, ...]:
2765 """
2766 Split this image into individual bands. This method returns a
2767 tuple of individual image bands from an image. For example,
2768 splitting an "RGB" image creates three new images each
2769 containing a copy of one of the original bands (red, green,
2770 blue).
2772 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel`
2773 method can be more convenient and faster.
2775 :returns: A tuple containing bands.
2776 """
2778 self.load()
2779 if self.im.bands == 1:
2780 return (self.copy(),)
2781 return tuple(map(self._new, self.im.split()))
2783 def getchannel(self, channel: int | str) -> Image:
2784 """
2785 Returns an image containing a single channel of the source image.
2787 :param channel: What channel to return. Could be index
2788 (0 for "R" channel of "RGB") or channel name
2789 ("A" for alpha channel of "RGBA").
2790 :returns: An image in "L" mode.
2792 .. versionadded:: 4.3.0
2793 """
2794 self.load()
2796 if isinstance(channel, str):
2797 try:
2798 channel = self.getbands().index(channel)
2799 except ValueError as e:
2800 msg = f'The image has no channel "{channel}"'
2801 raise ValueError(msg) from e
2803 return self._new(self.im.getband(channel))
2805 def tell(self) -> int:
2806 """
2807 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
2809 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2810 number of available frames.
2812 :returns: Frame number, starting with 0.
2813 """
2814 return 0
2816 def thumbnail(
2817 self,
2818 size: tuple[float, float],
2819 resample: Resampling = Resampling.BICUBIC,
2820 reducing_gap: float | None = 2.0,
2821 ) -> None:
2822 """
2823 Make this image into a thumbnail. This method modifies the
2824 image to contain a thumbnail version of itself, no larger than
2825 the given size. This method calculates an appropriate thumbnail
2826 size to preserve the aspect of the image, calls the
2827 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader
2828 (where applicable), and finally resizes the image.
2830 Note that this function modifies the :py:class:`~PIL.Image.Image`
2831 object in place. If you need to use the full resolution image as well,
2832 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
2833 image.
2835 :param size: The requested size in pixels, as a 2-tuple:
2836 (width, height).
2837 :param resample: Optional resampling filter. This can be one
2838 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2839 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2840 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`.
2841 If omitted, it defaults to :py:data:`Resampling.BICUBIC`.
2842 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0).
2843 See: :ref:`concept-filters`.
2844 :param reducing_gap: Apply optimization by resizing the image
2845 in two steps. First, reducing the image by integer times
2846 using :py:meth:`~PIL.Image.Image.reduce` or
2847 :py:meth:`~PIL.Image.Image.draft` for JPEG images.
2848 Second, resizing using regular resampling. The last step
2849 changes size no less than by ``reducing_gap`` times.
2850 ``reducing_gap`` may be None (no first step is performed)
2851 or should be greater than 1.0. The bigger ``reducing_gap``,
2852 the closer the result to the fair resampling.
2853 The smaller ``reducing_gap``, the faster resizing.
2854 With ``reducing_gap`` greater or equal to 3.0, the result is
2855 indistinguishable from fair resampling in most cases.
2856 The default value is 2.0 (very close to fair resampling
2857 while still being faster in many cases).
2858 :returns: None
2859 """
2861 provided_size = tuple(map(math.floor, size))
2863 def preserve_aspect_ratio() -> tuple[int, int] | None:
2864 def round_aspect(number: float, key: Callable[[int], float]) -> int:
2865 return max(min(math.floor(number), math.ceil(number), key=key), 1)
2867 x, y = provided_size
2868 if x >= self.width and y >= self.height:
2869 return None
2871 aspect = self.width / self.height
2872 if x / y >= aspect:
2873 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y))
2874 else:
2875 y = round_aspect(
2876 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n)
2877 )
2878 return x, y
2880 preserved_size = preserve_aspect_ratio()
2881 if preserved_size is None:
2882 return
2883 final_size = preserved_size
2885 box = None
2886 if reducing_gap is not None:
2887 res = self.draft(
2888 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
2889 )
2890 if res is not None:
2891 box = res[1]
2893 if self.size != final_size:
2894 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap)
2896 self.im = im.im
2897 self._size = final_size
2898 self._mode = self.im.mode
2900 self.readonly = 0
2902 # FIXME: the different transform methods need further explanation
2903 # instead of bloating the method docs, add a separate chapter.
2904 def transform(
2905 self,
2906 size: tuple[int, int],
2907 method: Transform | ImageTransformHandler | SupportsGetData,
2908 data: Sequence[Any] | None = None,
2909 resample: int = Resampling.NEAREST,
2910 fill: int = 1,
2911 fillcolor: float | tuple[float, ...] | str | None = None,
2912 ) -> Image:
2913 """
2914 Transforms this image. This method creates a new image with the
2915 given size, and the same mode as the original, and copies data
2916 to the new image using the given transform.
2918 :param size: The output size in pixels, as a 2-tuple:
2919 (width, height).
2920 :param method: The transformation method. This is one of
2921 :py:data:`Transform.EXTENT` (cut out a rectangular subregion),
2922 :py:data:`Transform.AFFINE` (affine transform),
2923 :py:data:`Transform.PERSPECTIVE` (perspective transform),
2924 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or
2925 :py:data:`Transform.MESH` (map a number of source quadrilaterals
2926 in one operation).
2928 It may also be an :py:class:`~PIL.Image.ImageTransformHandler`
2929 object::
2931 class Example(Image.ImageTransformHandler):
2932 def transform(self, size, data, resample, fill=1):
2933 # Return result
2935 Implementations of :py:class:`~PIL.Image.ImageTransformHandler`
2936 for some of the :py:class:`Transform` methods are provided
2937 in :py:mod:`~PIL.ImageTransform`.
2939 It may also be an object with a ``method.getdata`` method
2940 that returns a tuple supplying new ``method`` and ``data`` values::
2942 class Example:
2943 def getdata(self):
2944 method = Image.Transform.EXTENT
2945 data = (0, 0, 100, 100)
2946 return method, data
2947 :param data: Extra data to the transformation method.
2948 :param resample: Optional resampling filter. It can be one of
2949 :py:data:`Resampling.NEAREST` (use nearest neighbour),
2950 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2951 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2952 interpolation in a 4x4 environment). If omitted, or if the image
2953 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`.
2954 See: :ref:`concept-filters`.
2955 :param fill: If ``method`` is an
2956 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of
2957 the arguments passed to it. Otherwise, it is unused.
2958 :param fillcolor: Optional fill color for the area outside the
2959 transform in the output image.
2960 :returns: An :py:class:`~PIL.Image.Image` object.
2961 """
2963 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST:
2964 return (
2965 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2966 .transform(size, method, data, resample, fill, fillcolor)
2967 .convert(self.mode)
2968 )
2970 if isinstance(method, ImageTransformHandler):
2971 return method.transform(size, self, resample=resample, fill=fill)
2973 if hasattr(method, "getdata"):
2974 # compatibility w. old-style transform objects
2975 method, data = method.getdata()
2977 if data is None:
2978 msg = "missing method data"
2979 raise ValueError(msg)
2981 im = new(self.mode, size, fillcolor)
2982 if self.mode == "P" and self.palette:
2983 im.palette = self.palette.copy()
2984 im.info = self.info.copy()
2985 if method == Transform.MESH:
2986 # list of quads
2987 for box, quad in data:
2988 im.__transformer(
2989 box, self, Transform.QUAD, quad, resample, fillcolor is None
2990 )
2991 else:
2992 im.__transformer(
2993 (0, 0) + size, self, method, data, resample, fillcolor is None
2994 )
2996 return im
2998 def __transformer(
2999 self,
3000 box: tuple[int, int, int, int],
3001 image: Image,
3002 method: Transform,
3003 data: Sequence[float],
3004 resample: int = Resampling.NEAREST,
3005 fill: bool = True,
3006 ) -> None:
3007 w = box[2] - box[0]
3008 h = box[3] - box[1]
3010 if method == Transform.AFFINE:
3011 data = data[:6]
3013 elif method == Transform.EXTENT:
3014 # convert extent to an affine transform
3015 x0, y0, x1, y1 = data
3016 xs = (x1 - x0) / w
3017 ys = (y1 - y0) / h
3018 method = Transform.AFFINE
3019 data = (xs, 0, x0, 0, ys, y0)
3021 elif method == Transform.PERSPECTIVE:
3022 data = data[:8]
3024 elif method == Transform.QUAD:
3025 # quadrilateral warp. data specifies the four corners
3026 # given as NW, SW, SE, and NE.
3027 nw = data[:2]
3028 sw = data[2:4]
3029 se = data[4:6]
3030 ne = data[6:8]
3031 x0, y0 = nw
3032 As = 1.0 / w
3033 At = 1.0 / h
3034 data = (
3035 x0,
3036 (ne[0] - x0) * As,
3037 (sw[0] - x0) * At,
3038 (se[0] - sw[0] - ne[0] + x0) * As * At,
3039 y0,
3040 (ne[1] - y0) * As,
3041 (sw[1] - y0) * At,
3042 (se[1] - sw[1] - ne[1] + y0) * As * At,
3043 )
3045 else:
3046 msg = "unknown transformation method"
3047 raise ValueError(msg)
3049 if resample not in (
3050 Resampling.NEAREST,
3051 Resampling.BILINEAR,
3052 Resampling.BICUBIC,
3053 ):
3054 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS):
3055 unusable: dict[int, str] = {
3056 Resampling.BOX: "Image.Resampling.BOX",
3057 Resampling.HAMMING: "Image.Resampling.HAMMING",
3058 Resampling.LANCZOS: "Image.Resampling.LANCZOS",
3059 }
3060 msg = unusable[resample] + f" ({resample}) cannot be used."
3061 else:
3062 msg = f"Unknown resampling filter ({resample})."
3064 filters = [
3065 f"{filter[1]} ({filter[0]})"
3066 for filter in (
3067 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
3068 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
3069 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
3070 )
3071 ]
3072 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
3073 raise ValueError(msg)
3075 image.load()
3077 self.load()
3079 if image.mode in ("1", "P"):
3080 resample = Resampling.NEAREST
3082 self.im.transform(box, image.im, method, data, resample, fill)
3084 def transpose(self, method: Transpose) -> Image:
3085 """
3086 Transpose image (flip or rotate in 90 degree steps)
3088 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`,
3089 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`,
3090 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`,
3091 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`.
3092 :returns: Returns a flipped or rotated copy of this image.
3093 """
3095 self.load()
3096 return self._new(self.im.transpose(method))
3098 def effect_spread(self, distance: int) -> Image:
3099 """
3100 Randomly spread pixels in an image.
3102 :param distance: Distance to spread pixels.
3103 """
3104 self.load()
3105 return self._new(self.im.effect_spread(distance))
3107 def toqimage(self) -> ImageQt.ImageQt:
3108 """Returns a QImage copy of this image"""
3109 from . import ImageQt
3111 if not ImageQt.qt_is_installed:
3112 msg = "Qt bindings are not installed"
3113 raise ImportError(msg)
3114 return ImageQt.toqimage(self)
3116 def toqpixmap(self) -> ImageQt.QPixmap:
3117 """Returns a QPixmap copy of this image"""
3118 from . import ImageQt
3120 if not ImageQt.qt_is_installed:
3121 msg = "Qt bindings are not installed"
3122 raise ImportError(msg)
3123 return ImageQt.toqpixmap(self)
3126# --------------------------------------------------------------------
3127# Abstract handlers.
3130class ImagePointHandler(abc.ABC):
3131 """
3132 Used as a mixin by point transforms
3133 (for use with :py:meth:`~PIL.Image.Image.point`)
3134 """
3136 @abc.abstractmethod
3137 def point(self, im: Image) -> Image:
3138 pass
3141class ImageTransformHandler(abc.ABC):
3142 """
3143 Used as a mixin by geometry transforms
3144 (for use with :py:meth:`~PIL.Image.Image.transform`)
3145 """
3147 @abc.abstractmethod
3148 def transform(
3149 self,
3150 size: tuple[int, int],
3151 image: Image,
3152 **options: Any,
3153 ) -> Image:
3154 pass
3157# --------------------------------------------------------------------
3158# Factories
3161def _check_size(size: Any) -> None:
3162 """
3163 Common check to enforce type and sanity check on size tuples
3165 :param size: Should be a 2 tuple of (width, height)
3166 :returns: None, or raises a ValueError
3167 """
3169 if not isinstance(size, (list, tuple)):
3170 msg = "Size must be a list or tuple"
3171 raise ValueError(msg)
3172 if len(size) != 2:
3173 msg = "Size must be a sequence of length 2"
3174 raise ValueError(msg)
3175 if size[0] < 0 or size[1] < 0:
3176 msg = "Width and height must be >= 0"
3177 raise ValueError(msg)
3180def new(
3181 mode: str,
3182 size: tuple[int, int] | list[int],
3183 color: float | tuple[float, ...] | str | None = 0,
3184) -> Image:
3185 """
3186 Creates a new image with the given mode and size.
3188 :param mode: The mode to use for the new image. See:
3189 :ref:`concept-modes`.
3190 :param size: A 2-tuple, containing (width, height) in pixels.
3191 :param color: What color to use for the image. Default is black. If given,
3192 this should be a single integer or floating point value for single-band
3193 modes, and a tuple for multi-band modes (one value per band). When
3194 creating RGB or HSV images, you can also use color strings as supported
3195 by the ImageColor module. See :ref:`colors` for more information. If the
3196 color is None, the image is not initialised.
3197 :returns: An :py:class:`~PIL.Image.Image` object.
3198 """
3200 _check_size(size)
3202 if color is None:
3203 # don't initialize
3204 return Image()._new(core.new(mode, size))
3206 if isinstance(color, str):
3207 # css3-style specifier
3209 from . import ImageColor
3211 color = ImageColor.getcolor(color, mode)
3213 im = Image()
3214 if (
3215 mode == "P"
3216 and isinstance(color, (list, tuple))
3217 and all(isinstance(i, int) for i in color)
3218 ):
3219 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color))
3220 if len(color_ints) == 3 or len(color_ints) == 4:
3221 # RGB or RGBA value for a P image
3222 from . import ImagePalette
3224 im.palette = ImagePalette.ImagePalette()
3225 color = im.palette.getcolor(color_ints)
3226 return im._new(core.fill(mode, size, color))
3229def frombytes(
3230 mode: str,
3231 size: tuple[int, int],
3232 data: DecoderInput,
3233 decoder_name: str = "raw",
3234 *args: Any,
3235) -> Image:
3236 """
3237 Creates a copy of an image memory from pixel data in a buffer.
3239 In its simplest form, this function takes three arguments
3240 (mode, size, and unpacked pixel data).
3242 You can also use any pixel decoder supported by PIL. For more
3243 information on available decoders, see the section
3244 :ref:`Writing Your Own File Codec <file-codecs>`.
3246 Note that this function decodes pixel data only, not entire images.
3247 If you have an entire image in a string, wrap it in a
3248 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load
3249 it.
3251 :param mode: The image mode. See: :ref:`concept-modes`.
3252 :param size: The image size.
3253 :param data: A byte buffer containing raw data for the given mode.
3254 :param decoder_name: What decoder to use.
3255 :param args: Additional parameters for the given decoder.
3256 :returns: An :py:class:`~PIL.Image.Image` object.
3257 """
3259 _check_size(size)
3261 im = new(mode, size)
3262 if im.width != 0 and im.height != 0:
3263 decoder_args: Any = args
3264 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
3265 # may pass tuple instead of argument list
3266 decoder_args = decoder_args[0]
3268 if decoder_name == "raw" and decoder_args == ():
3269 decoder_args = mode
3271 im.frombytes(data, decoder_name, decoder_args)
3272 return im
3275def frombuffer(
3276 mode: str,
3277 size: tuple[int, int],
3278 data: bytes | SupportsArrayInterface,
3279 decoder_name: str = "raw",
3280 *args: Any,
3281) -> Image:
3282 """
3283 Creates an image memory referencing pixel data in a byte buffer.
3285 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data
3286 in the byte buffer, where possible. This means that changes to the
3287 original buffer object are reflected in this image). Not all modes can
3288 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK".
3290 Note that this function decodes pixel data only, not entire images.
3291 If you have an entire image file in a string, wrap it in a
3292 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it.
3294 The default parameters used for the "raw" decoder differs from that used for
3295 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a
3296 future release. The current release issues a warning if you do this; to disable
3297 the warning, you should provide the full set of parameters. See below for details.
3299 :param mode: The image mode. See: :ref:`concept-modes`.
3300 :param size: The image size.
3301 :param data: A bytes or other buffer object containing raw
3302 data for the given mode.
3303 :param decoder_name: What decoder to use.
3304 :param args: Additional parameters for the given decoder. For the
3305 default encoder ("raw"), it's recommended that you provide the
3306 full set of parameters::
3308 frombuffer(mode, size, data, "raw", mode, 0, 1)
3310 :returns: An :py:class:`~PIL.Image.Image` object.
3312 .. versionadded:: 1.1.4
3313 """
3315 _check_size(size)
3317 # may pass tuple instead of argument list
3318 if len(args) == 1 and isinstance(args[0], tuple):
3319 args = args[0]
3321 if decoder_name == "raw":
3322 if args == ():
3323 args = mode, 0, 1
3324 if args[0] in _MAPMODES:
3325 im = new(mode, (0, 0))
3326 im = im._new(core.map_buffer(data, size, decoder_name, 0, args))
3327 if mode == "P":
3328 from . import ImagePalette
3330 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB"))
3331 im.readonly = 1
3332 return im
3334 return frombytes(mode, size, data, decoder_name, args)
3337class SupportsArrayInterface(Protocol):
3338 """
3339 An object that has an ``__array_interface__`` dictionary.
3340 """
3342 @property
3343 def __array_interface__(self) -> dict[str, Any]:
3344 raise NotImplementedError()
3346 def __len__(self) -> int:
3347 raise NotImplementedError()
3350DecoderInput = bytes | bytearray | memoryview | SupportsArrayInterface
3353class SupportsArrowArrayInterface(Protocol):
3354 """
3355 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c
3356 data interface.
3357 """
3359 def __arrow_c_array__(
3360 self, requested_schema: PyCapsule = None # type: ignore[name-defined] # noqa: F821
3361 ) -> tuple[PyCapsule, PyCapsule]: # type: ignore[name-defined] # noqa: F821
3362 raise NotImplementedError()
3365def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
3366 """
3367 Creates an image memory from an object exporting the array interface
3368 (using the buffer protocol)::
3370 from PIL import Image
3371 import numpy as np
3372 a = np.zeros((5, 5))
3373 im = Image.fromarray(a)
3375 If ``obj`` is not contiguous, then the ``tobytes`` method is called
3376 and :py:func:`~PIL.Image.frombuffer` is used.
3378 In the case of NumPy, be aware that Pillow modes do not always correspond
3379 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels,
3380 32-bit signed integer pixels, and 32-bit floating point pixels.
3382 Pillow images can also be converted to arrays::
3384 from PIL import Image
3385 import numpy as np
3386 im = Image.open("hopper.jpg")
3387 a = np.asarray(im)
3389 When converting Pillow images to arrays however, only pixel values are
3390 transferred. This means that P and PA mode images will lose their palette.
3392 :param obj: Object with array interface
3393 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not
3394 contain information about palettes or color spaces, this can be used to place
3395 grayscale L mode data within a P mode image, or read RGB data as YCbCr for
3396 example.
3398 See: :ref:`concept-modes` for general information about modes.
3399 :returns: An image object.
3401 .. versionadded:: 1.1.6
3402 """
3403 arr = obj.__array_interface__
3404 shape = arr["shape"]
3405 ndim = len(shape)
3406 strides = arr.get("strides", None)
3407 try:
3408 typekey = (1, 1) + shape[2:], arr["typestr"]
3409 except KeyError as e:
3410 if mode is not None:
3411 typekey = None
3412 color_modes: list[str] = []
3413 else:
3414 msg = "Cannot handle this data type"
3415 raise TypeError(msg) from e
3416 if typekey is not None:
3417 try:
3418 typemode, rawmode, color_modes = _fromarray_typemap[typekey]
3419 except KeyError as e:
3420 typekey_shape, typestr = typekey
3421 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}"
3422 raise TypeError(msg) from e
3423 if mode is not None:
3424 if mode != typemode and mode not in color_modes:
3425 msg = "Invalid mode for data type"
3426 raise ValueError(msg)
3427 rawmode = mode
3428 else:
3429 mode = typemode
3430 if mode in ["1", "L", "I", "P", "F"]:
3431 ndmax = 2
3432 elif mode == "RGB":
3433 ndmax = 3
3434 else:
3435 ndmax = 4
3436 if ndim > ndmax:
3437 msg = f"Too many dimensions: {ndim} > {ndmax}."
3438 raise ValueError(msg)
3440 size = 1 if ndim == 1 else shape[1], shape[0]
3441 if strides is not None:
3442 if hasattr(obj, "tobytes"):
3443 obj = obj.tobytes()
3444 elif hasattr(obj, "tostring"):
3445 obj = obj.tostring()
3446 else:
3447 msg = "'strides' requires either tobytes() or tostring()"
3448 raise ValueError(msg)
3450 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
3453def fromarrow(
3454 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int]
3455) -> Image:
3456 """Creates an image with zero-copy shared memory from an object exporting
3457 the arrow_c_array interface protocol::
3459 from PIL import Image
3460 import pyarrow as pa
3461 arr = pa.array([0]*(5*5*4), type=pa.uint8())
3462 im = Image.fromarrow(arr, 'RGBA', (5, 5))
3464 If the data representation of the ``obj`` is not compatible with
3465 Pillow internal storage, a ValueError is raised.
3467 Pillow images can also be converted to Arrow objects::
3469 from PIL import Image
3470 import pyarrow as pa
3471 im = Image.open('hopper.jpg')
3472 arr = pa.array(im)
3474 As with array support, when converting Pillow images to arrays,
3475 only pixel values are transferred. This means that P and PA mode
3476 images will lose their palette.
3478 :param obj: Object with an arrow_c_array interface
3479 :param mode: Image mode.
3480 :param size: Image size. This must match the storage of the arrow object.
3481 :returns: An Image object
3483 Note that according to the Arrow spec, both the producer and the
3484 consumer should consider the exported array to be immutable, as
3485 unsynchronized updates will potentially cause inconsistent data.
3487 See: :ref:`arrow-support` for more detailed information
3489 .. versionadded:: 11.2.1
3491 """
3492 if not hasattr(obj, "__arrow_c_array__"):
3493 msg = "arrow_c_array interface not found"
3494 raise ValueError(msg)
3496 schema_capsule, array_capsule = obj.__arrow_c_array__()
3497 _im = core.new_arrow(mode, size, schema_capsule, array_capsule)
3498 if _im:
3499 return Image()._new(_im)
3501 msg = "new_arrow returned None without an exception"
3502 raise ValueError(msg)
3505def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile:
3506 """Creates an image instance from a QImage image"""
3507 from . import ImageQt
3509 if not ImageQt.qt_is_installed:
3510 msg = "Qt bindings are not installed"
3511 raise ImportError(msg)
3512 return ImageQt.fromqimage(im)
3515def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile:
3516 """Creates an image instance from a QPixmap image"""
3517 from . import ImageQt
3519 if not ImageQt.qt_is_installed:
3520 msg = "Qt bindings are not installed"
3521 raise ImportError(msg)
3522 return ImageQt.fromqpixmap(im)
3525_fromarray_typemap = {
3526 # (shape, typestr) => mode, rawmode, color modes
3527 # first two members of shape are set to one
3528 ((1, 1), "|b1"): ("1", "1;8", []),
3529 ((1, 1), "|u1"): ("L", "L", ["P"]),
3530 ((1, 1), "|i1"): ("I", "I;8", []),
3531 ((1, 1), "<u2"): ("I", "I;16", []),
3532 ((1, 1), ">u2"): ("I", "I;16B", []),
3533 ((1, 1), "<i2"): ("I", "I;16S", []),
3534 ((1, 1), ">i2"): ("I", "I;16BS", []),
3535 ((1, 1), "<u4"): ("I", "I;32", []),
3536 ((1, 1), ">u4"): ("I", "I;32B", []),
3537 ((1, 1), "<i4"): ("I", "I;32S", []),
3538 ((1, 1), ">i4"): ("I", "I;32BS", []),
3539 ((1, 1), "<f4"): ("F", "F;32F", []),
3540 ((1, 1), ">f4"): ("F", "F;32BF", []),
3541 ((1, 1), "<f8"): ("F", "F;64F", []),
3542 ((1, 1), ">f8"): ("F", "F;64BF", []),
3543 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]),
3544 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]),
3545 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]),
3546 # shortcuts:
3547 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []),
3548 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []),
3549}
3552def _decompression_bomb_check(size: tuple[int, int]) -> None:
3553 if MAX_IMAGE_PIXELS is None:
3554 return
3556 pixels = max(1, size[0]) * max(1, size[1])
3558 if pixels > 2 * MAX_IMAGE_PIXELS:
3559 msg = (
3560 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} "
3561 "pixels, could be decompression bomb DOS attack."
3562 )
3563 raise DecompressionBombError(msg)
3565 if pixels > MAX_IMAGE_PIXELS:
3566 warnings.warn(
3567 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, "
3568 "could be decompression bomb DOS attack.",
3569 DecompressionBombWarning,
3570 )
3573def open(
3574 fp: StrOrBytesPath | IO[bytes],
3575 mode: Literal["r"] = "r",
3576 formats: list[str] | tuple[str, ...] | None = None,
3577) -> ImageFile.ImageFile:
3578 """
3579 Opens and identifies the given image file.
3581 This is a lazy operation; this function identifies the file, but
3582 the file remains open and the actual image data is not read from
3583 the file until you try to process the data (or call the
3584 :py:meth:`~PIL.Image.Image.load` method). See
3585 :py:func:`~PIL.Image.new`. See :ref:`file-handling`.
3587 :param fp: A filename (string), os.PathLike object or a file object.
3588 The file object must implement ``file.read``,
3589 ``file.seek``, and ``file.tell`` methods,
3590 and be opened in binary mode. The file object will also seek to zero
3591 before reading.
3592 :param mode: The mode. If given, this argument must be "r".
3593 :param formats: A list or tuple of formats to attempt to load the file in.
3594 This can be used to restrict the set of formats checked.
3595 Pass ``None`` to try all supported formats. You can print the set of
3596 available formats by running ``python3 -m PIL`` or using
3597 the :py:func:`PIL.features.pilinfo` function.
3598 :returns: An :py:class:`~PIL.Image.Image` object.
3599 :exception FileNotFoundError: If the file cannot be found.
3600 :exception PIL.UnidentifiedImageError: If the image cannot be opened and
3601 identified.
3602 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO``
3603 instance is used for ``fp``.
3604 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple.
3605 """
3607 if mode != "r":
3608 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
3609 raise ValueError(msg)
3610 elif isinstance(fp, io.StringIO):
3611 msg = ( # type: ignore[unreachable]
3612 "StringIO cannot be used to open an image. "
3613 "Binary data must be used instead."
3614 )
3615 raise ValueError(msg)
3617 if formats is None:
3618 formats = ID
3619 elif not isinstance(formats, (list, tuple)):
3620 msg = "formats must be a list or tuple" # type: ignore[unreachable]
3621 raise TypeError(msg)
3623 exclusive_fp = False
3624 filename: str | bytes = ""
3625 if is_path(fp):
3626 filename = os.fspath(fp)
3627 fp = builtins.open(filename, "rb")
3628 exclusive_fp = True
3629 else:
3630 fp = cast(IO[bytes], fp)
3632 try:
3633 fp.seek(0)
3634 except (AttributeError, io.UnsupportedOperation):
3635 fp = io.BytesIO(fp.read())
3636 exclusive_fp = True
3638 prefix = fp.read(16)
3640 # Try to import just the plugin needed for this file extension
3641 # before falling back to preinit() which imports common plugins
3642 ext = os.path.splitext(filename)[1] if filename else ""
3643 if not _import_plugin_for_extension(ext):
3644 preinit()
3646 warning_messages: list[str] = []
3648 def _open_core(
3649 fp: IO[bytes],
3650 filename: str | bytes,
3651 prefix: bytes,
3652 formats: list[str] | tuple[str, ...],
3653 ) -> ImageFile.ImageFile | None:
3654 for i in formats:
3655 i = i.upper()
3656 if i not in OPEN:
3657 init()
3658 try:
3659 factory, accept = OPEN[i]
3660 result = not accept or accept(prefix)
3661 if isinstance(result, str):
3662 warning_messages.append(result)
3663 elif result:
3664 fp.seek(0)
3665 im = factory(fp, filename)
3666 _decompression_bomb_check(im.size)
3667 return im
3668 except (SyntaxError, IndexError, TypeError, struct.error) as e:
3669 if WARN_POSSIBLE_FORMATS:
3670 warning_messages.append(i + " opening failed. " + str(e))
3671 except BaseException:
3672 if exclusive_fp:
3673 fp.close()
3674 raise
3675 return None
3677 im = _open_core(fp, filename, prefix, formats)
3679 if im is None and formats is ID:
3680 # Try preinit (few common plugins) then init (all plugins)
3681 for loader in (preinit, init):
3682 checked_formats = ID.copy()
3683 loader()
3684 if formats != checked_formats:
3685 im = _open_core(
3686 fp,
3687 filename,
3688 prefix,
3689 tuple(f for f in formats if f not in checked_formats),
3690 )
3691 if im is not None:
3692 break
3694 if im:
3695 im._exclusive_fp = exclusive_fp
3696 return im
3698 if exclusive_fp:
3699 fp.close()
3700 for message in warning_messages:
3701 warnings.warn(message)
3702 msg = "cannot identify image file %r" % (filename if filename else fp)
3703 raise UnidentifiedImageError(msg)
3706#
3707# Image processing.
3710def alpha_composite(im1: Image, im2: Image) -> Image:
3711 """
3712 Alpha composite im2 over im1.
3714 :param im1: The first image. Must have mode RGBA or LA.
3715 :param im2: The second image. Must have the same mode and size as the first image.
3716 :returns: An :py:class:`~PIL.Image.Image` object.
3717 """
3719 im1.load()
3720 im2.load()
3721 return im1._new(core.alpha_composite(im1.im, im2.im))
3724def blend(im1: Image, im2: Image, alpha: float) -> Image:
3725 """
3726 Creates a new image by interpolating between two input images, using
3727 a constant alpha::
3729 out = image1 * (1.0 - alpha) + image2 * alpha
3731 :param im1: The first image.
3732 :param im2: The second image. Must have the same mode and size as
3733 the first image.
3734 :param alpha: The interpolation alpha factor. If alpha is 0.0, a
3735 copy of the first image is returned. If alpha is 1.0, a copy of
3736 the second image is returned. There are no restrictions on the
3737 alpha value. If necessary, the result is clipped to fit into
3738 the allowed output range.
3739 :returns: An :py:class:`~PIL.Image.Image` object.
3740 """
3742 im1.load()
3743 im2.load()
3744 return im1._new(core.blend(im1.im, im2.im, alpha))
3747def composite(image1: Image, image2: Image, mask: Image) -> Image:
3748 """
3749 Create composite image by blending images using a transparency mask.
3751 :param image1: The first image.
3752 :param image2: The second image. Must have the same mode and
3753 size as the first image.
3754 :param mask: A mask image. This image can have mode
3755 "1", "L", or "RGBA", and must have the same size as the
3756 other two images.
3757 """
3759 image = image2.copy()
3760 image.paste(image1, None, mask)
3761 return image
3764def eval(image: Image, *args: Callable[[int], float]) -> Image:
3765 """
3766 Applies the function (which should take one argument) to each pixel
3767 in the given image. If the image has more than one band, the same
3768 function is applied to each band. Note that the function is
3769 evaluated once for each possible pixel value, so you cannot use
3770 random components or other generators.
3772 :param image: The input image.
3773 :param function: A function object, taking one integer argument.
3774 :returns: An :py:class:`~PIL.Image.Image` object.
3775 """
3777 return image.point(args[0])
3780def merge(mode: str, bands: Sequence[Image]) -> Image:
3781 """
3782 Merge a set of single band images into a new multiband image.
3784 :param mode: The mode to use for the output image. See:
3785 :ref:`concept-modes`.
3786 :param bands: A sequence containing one single-band image for
3787 each band in the output image. All bands must have the
3788 same size.
3789 :returns: An :py:class:`~PIL.Image.Image` object.
3790 """
3792 if getmodebands(mode) != len(bands) or "*" in mode:
3793 msg = "wrong number of bands"
3794 raise ValueError(msg)
3795 for band in bands[1:]:
3796 if band.mode != getmodetype(mode):
3797 msg = "mode mismatch"
3798 raise ValueError(msg)
3799 if band.size != bands[0].size:
3800 msg = "size mismatch"
3801 raise ValueError(msg)
3802 for band in bands:
3803 band.load()
3804 return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
3807# --------------------------------------------------------------------
3808# Plugin registry
3811def register_open(
3812 id: str,
3813 factory: (
3814 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile]
3815 | type[ImageFile.ImageFile]
3816 ),
3817 accept: Callable[[bytes], bool | str] | None = None,
3818) -> None:
3819 """
3820 Register an image file plugin. This function should not be used
3821 in application code.
3823 :param id: An image format identifier.
3824 :param factory: An image file factory method.
3825 :param accept: An optional function that can be used to quickly
3826 reject images having another format.
3827 """
3828 id = id.upper()
3829 if id not in ID:
3830 ID.append(id)
3831 OPEN[id] = factory, accept
3834def register_mime(id: str, mimetype: str) -> None:
3835 """
3836 Registers an image MIME type by populating ``Image.MIME``. This function
3837 should not be used in application code.
3839 ``Image.MIME`` provides a mapping from image format identifiers to mime
3840 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can
3841 provide a different result for specific images.
3843 :param id: An image format identifier.
3844 :param mimetype: The image MIME type for this format.
3845 """
3846 MIME[id.upper()] = mimetype
3849def register_save(
3850 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3851) -> None:
3852 """
3853 Registers an image save function. This function should not be
3854 used in application code.
3856 :param id: An image format identifier.
3857 :param driver: A function to save images in this format.
3858 """
3859 SAVE[id.upper()] = driver
3862def register_save_all(
3863 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3864) -> None:
3865 """
3866 Registers an image function to save all the frames
3867 of a multiframe format. This function should not be
3868 used in application code.
3870 :param id: An image format identifier.
3871 :param driver: A function to save images in this format.
3872 """
3873 SAVE_ALL[id.upper()] = driver
3876def register_extension(id: str, extension: str) -> None:
3877 """
3878 Registers an image extension. This function should not be
3879 used in application code.
3881 :param id: An image format identifier.
3882 :param extension: An extension used for this format.
3883 """
3884 EXTENSION[extension.lower()] = id.upper()
3887def register_extensions(id: str, extensions: list[str]) -> None:
3888 """
3889 Registers image extensions. This function should not be
3890 used in application code.
3892 :param id: An image format identifier.
3893 :param extensions: A list of extensions used for this format.
3894 """
3895 for extension in extensions:
3896 register_extension(id, extension)
3899def registered_extensions() -> dict[str, str]:
3900 """
3901 Returns a dictionary containing all file extensions belonging
3902 to registered plugins
3903 """
3904 init()
3905 return EXTENSION
3908def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None:
3909 """
3910 Registers an image decoder. This function should not be
3911 used in application code.
3913 :param name: The name of the decoder
3914 :param decoder: An ImageFile.PyDecoder object
3916 .. versionadded:: 4.1.0
3917 """
3918 DECODERS[name] = decoder
3921def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None:
3922 """
3923 Registers an image encoder. This function should not be
3924 used in application code.
3926 :param name: The name of the encoder
3927 :param encoder: An ImageFile.PyEncoder object
3929 .. versionadded:: 4.1.0
3930 """
3931 ENCODERS[name] = encoder
3934# --------------------------------------------------------------------
3935# Effects
3938def effect_mandelbrot(
3939 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int
3940) -> Image:
3941 """
3942 Generate a Mandelbrot set covering the given extent.
3944 :param size: The requested size in pixels, as a 2-tuple:
3945 (width, height).
3946 :param extent: The extent to cover, as a 4-tuple:
3947 (x0, y0, x1, y1).
3948 :param quality: Quality.
3949 """
3950 return Image()._new(core.effect_mandelbrot(size, extent, quality))
3953def effect_noise(size: tuple[int, int], sigma: float) -> Image:
3954 """
3955 Generate Gaussian noise centered around 128.
3957 :param size: The requested size in pixels, as a 2-tuple:
3958 (width, height).
3959 :param sigma: Standard deviation of noise.
3960 """
3961 return Image()._new(core.effect_noise(size, sigma))
3964def linear_gradient(mode: str) -> Image:
3965 """
3966 Generate 256x256 linear gradient from black to white, top to bottom.
3968 :param mode: Input mode.
3969 """
3970 return Image()._new(core.linear_gradient(mode))
3973def radial_gradient(mode: str) -> Image:
3974 """
3975 Generate 256x256 radial gradient from black to white, centre to edge.
3977 :param mode: Input mode.
3978 """
3979 return Image()._new(core.radial_gradient(mode))
3982# --------------------------------------------------------------------
3983# Resources
3986def _apply_env_variables(env: dict[str, str] | None = None) -> None:
3987 env_dict = env if env is not None else os.environ
3989 for var_name, setter in [
3990 ("PILLOW_ALIGNMENT", core.set_alignment),
3991 ("PILLOW_BLOCK_SIZE", core.set_block_size),
3992 ("PILLOW_BLOCKS_MAX", core.set_blocks_max),
3993 ]:
3994 if var_name not in env_dict:
3995 continue
3997 var = env_dict[var_name].lower()
3999 units = 1
4000 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]:
4001 if var.endswith(postfix):
4002 units = mul
4003 var = var[: -len(postfix)]
4005 try:
4006 var_int = int(var) * units
4007 except ValueError:
4008 warnings.warn(f"{var_name} is not int")
4009 continue
4011 try:
4012 setter(var_int)
4013 except ValueError as e:
4014 warnings.warn(f"{var_name}: {e}")
4017_apply_env_variables()
4018atexit.register(core.clear_cache)
4021if TYPE_CHECKING:
4022 _ExifBase = MutableMapping[int, Any]
4023else:
4024 _ExifBase = MutableMapping
4027class Exif(_ExifBase):
4028 """
4029 This class provides read and write access to EXIF image data::
4031 from PIL import Image
4032 im = Image.open("exif.png")
4033 exif = im.getexif() # Returns an instance of this class
4035 Information can be read and written, iterated over or deleted::
4037 print(exif[274]) # 1
4038 exif[274] = 2
4039 for k, v in exif.items():
4040 print("Tag", k, "Value", v) # Tag 274 Value 2
4041 del exif[274]
4043 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd`
4044 returns a dictionary::
4046 from PIL import ExifTags
4047 im = Image.open("exif_gps.jpg")
4048 exif = im.getexif()
4049 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo)
4050 print(gps_ifd)
4052 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``,
4053 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``.
4055 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data::
4057 print(exif[ExifTags.Base.Software]) # PIL
4058 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99
4059 """
4061 endian: str | None = None
4062 bigtiff = False
4063 _loaded = False
4065 def __init__(self) -> None:
4066 self._data: dict[int, Any] = {}
4067 self._hidden_data: dict[int, Any] = {}
4068 self._ifds: dict[int, dict[int, Any]] = {}
4069 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None
4070 self._loaded_exif: bytes | None = None
4072 def _fixup(self, value: Any) -> Any:
4073 try:
4074 if len(value) == 1 and isinstance(value, tuple):
4075 return value[0]
4076 except Exception:
4077 pass
4078 return value
4080 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]:
4081 # Helper function
4082 # returns a dict with any single item tuples/lists as individual values
4083 return {k: self._fixup(v) for k, v in src_dict.items()}
4085 def _get_ifd_dict(
4086 self, offset: int, group: int | None = None
4087 ) -> dict[int, Any] | None:
4088 try:
4089 # an offset pointer to the location of the nested embedded IFD.
4090 # It should be a long, but may be corrupted.
4091 self.fp.seek(offset)
4092 except (KeyError, TypeError):
4093 return None
4094 else:
4095 from . import TiffImagePlugin
4097 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group)
4098 info.load(self.fp)
4099 return self._fixup_dict(dict(info))
4101 def _get_head(self) -> bytes:
4102 version = b"\x2b" if self.bigtiff else b"\x2a"
4103 if self.endian == "<":
4104 head = b"II" + version + b"\x00" + o32le(8)
4105 else:
4106 head = b"MM\x00" + version + o32be(8)
4107 if self.bigtiff:
4108 head += o32le(8) if self.endian == "<" else o32be(8)
4109 head += b"\x00\x00\x00\x00"
4110 return head
4112 def load(self, data: bytes) -> None:
4113 # Extract EXIF information. This is highly experimental,
4114 # and is likely to be replaced with something better in a future
4115 # version.
4117 # The EXIF record consists of a TIFF file embedded in a JPEG
4118 # application marker (!).
4119 if data == self._loaded_exif:
4120 return
4121 self._loaded_exif = data
4122 self._data.clear()
4123 self._hidden_data.clear()
4124 self._ifds.clear()
4125 while data and data.startswith(b"Exif\x00\x00"):
4126 data = data[6:]
4127 if not data:
4128 self._info = None
4129 return
4131 self.fp: IO[bytes] = io.BytesIO(data)
4132 self.head = self.fp.read(8)
4133 # process dictionary
4134 from . import TiffImagePlugin
4136 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4137 self.endian = self._info._endian
4138 self.fp.seek(self._info.next)
4139 self._info.load(self.fp)
4141 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None:
4142 self._loaded_exif = None
4143 self._data.clear()
4144 self._hidden_data.clear()
4145 self._ifds.clear()
4147 # process dictionary
4148 from . import TiffImagePlugin
4150 self.fp = fp
4151 if offset is not None:
4152 self.head = self._get_head()
4153 else:
4154 self.head = self.fp.read(8)
4155 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4156 if self.endian is None:
4157 self.endian = self._info._endian
4158 if offset is None:
4159 offset = self._info.next
4160 self.fp.tell()
4161 self.fp.seek(offset)
4162 self._info.load(self.fp)
4164 def _get_merged_dict(self) -> dict[int, Any]:
4165 merged_dict = dict(self)
4167 # get EXIF extension
4168 if ExifTags.IFD.Exif in self:
4169 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif)
4170 if ifd:
4171 merged_dict.update(ifd)
4173 # GPS
4174 if ExifTags.IFD.GPSInfo in self:
4175 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict(
4176 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo
4177 )
4179 return merged_dict
4181 def tobytes(self, offset: int = 8) -> bytes:
4182 from . import TiffImagePlugin
4184 head = self._get_head()
4185 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head)
4186 for tag, ifd_dict in self._ifds.items():
4187 if tag not in self:
4188 ifd[tag] = ifd_dict
4189 for tag, value in self.items():
4190 if tag in [
4191 ExifTags.IFD.Exif,
4192 ExifTags.IFD.GPSInfo,
4193 ] and not isinstance(value, dict):
4194 value = self.get_ifd(tag)
4195 if (
4196 tag == ExifTags.IFD.Exif
4197 and ExifTags.IFD.Interop in value
4198 and not isinstance(value[ExifTags.IFD.Interop], dict)
4199 ):
4200 value = value.copy()
4201 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop)
4202 ifd[tag] = value
4203 return b"Exif\x00\x00" + head + ifd.tobytes(offset)
4205 def get_ifd(self, tag: int) -> dict[int, Any]:
4206 if tag not in self._ifds:
4207 if tag == ExifTags.IFD.IFD1:
4208 if self._info is not None and self._info.next != 0:
4209 ifd = self._get_ifd_dict(self._info.next)
4210 if ifd is not None:
4211 self._ifds[tag] = ifd
4212 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
4213 offset = self._hidden_data.get(tag, self.get(tag))
4214 if offset is not None:
4215 ifd = self._get_ifd_dict(offset, tag)
4216 if ifd is not None:
4217 self._ifds[tag] = ifd
4218 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]:
4219 if ExifTags.IFD.Exif not in self._ifds:
4220 self.get_ifd(ExifTags.IFD.Exif)
4221 tag_data = self._ifds[ExifTags.IFD.Exif][tag]
4222 if tag == ExifTags.IFD.MakerNote:
4223 from .TiffImagePlugin import ImageFileDirectory_v2
4225 try:
4226 if tag_data.startswith(b"FUJIFILM"):
4227 ifd_offset = i32le(tag_data, 8)
4228 ifd_data = tag_data[ifd_offset:]
4230 makernote = {}
4231 for i in range(struct.unpack("<H", ifd_data[:2])[0]):
4232 ifd_tag, typ, count, data = struct.unpack(
4233 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
4234 )
4235 try:
4236 (
4237 unit_size,
4238 handler,
4239 ) = ImageFileDirectory_v2._load_dispatch[typ]
4240 except KeyError:
4241 continue
4242 size = count * unit_size
4243 if size > 4:
4244 (offset,) = struct.unpack("<L", data)
4245 data = ifd_data[offset - 12 : offset + size - 12]
4246 else:
4247 data = data[:size]
4249 if len(data) != size:
4250 warnings.warn(
4251 "Possibly corrupt EXIF MakerNote data. "
4252 f"Expecting to read {size} bytes but only got "
4253 f"{len(data)}. Skipping tag {ifd_tag}"
4254 )
4255 continue
4257 if not data:
4258 continue
4260 makernote[ifd_tag] = handler(
4261 ImageFileDirectory_v2(), data, False
4262 )
4263 self._ifds[tag] = dict(self._fixup_dict(makernote))
4264 elif self.get(0x010F) == "Nintendo":
4265 makernote = {}
4266 for i in range(struct.unpack(">H", tag_data[:2])[0]):
4267 ifd_tag, typ, count, data = struct.unpack(
4268 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2]
4269 )
4270 if ifd_tag == 0x1101:
4271 # CameraInfo
4272 (offset,) = struct.unpack(">L", data)
4273 self.fp.seek(offset)
4275 camerainfo: dict[str, int | bytes] = {
4276 "ModelID": self.fp.read(4)
4277 }
4279 self.fp.read(4)
4280 # Seconds since 2000
4281 camerainfo["TimeStamp"] = i32le(self.fp.read(12))
4283 self.fp.read(4)
4284 camerainfo["InternalSerialNumber"] = self.fp.read(4)
4286 self.fp.read(12)
4287 parallax = self.fp.read(4)
4288 handler = ImageFileDirectory_v2._load_dispatch[
4289 TiffTags.FLOAT
4290 ][1]
4291 camerainfo["Parallax"] = handler(
4292 ImageFileDirectory_v2(), parallax, False
4293 )[0]
4295 self.fp.read(4)
4296 camerainfo["Category"] = self.fp.read(2)
4298 makernote = {0x1101: camerainfo}
4299 self._ifds[tag] = makernote
4300 except struct.error:
4301 pass
4302 else:
4303 # Interop
4304 ifd = self._get_ifd_dict(tag_data, tag)
4305 if ifd is not None:
4306 self._ifds[tag] = ifd
4307 ifd = self._ifds.setdefault(tag, {})
4308 if tag == ExifTags.IFD.Exif and self._hidden_data:
4309 ifd = {
4310 k: v
4311 for (k, v) in ifd.items()
4312 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote)
4313 }
4314 return ifd
4316 def hide_offsets(self) -> None:
4317 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo):
4318 if tag in self:
4319 self._hidden_data[tag] = self[tag]
4320 del self[tag]
4322 def __str__(self) -> str:
4323 if self._info is not None:
4324 # Load all keys into self._data
4325 for tag in self._info:
4326 self[tag]
4328 return str(self._data)
4330 def __len__(self) -> int:
4331 keys = set(self._data)
4332 if self._info is not None:
4333 keys.update(self._info)
4334 return len(keys)
4336 def __getitem__(self, tag: int) -> Any:
4337 if self._info is not None and tag not in self._data and tag in self._info:
4338 self._data[tag] = self._fixup(self._info[tag])
4339 del self._info[tag]
4340 return self._data[tag]
4342 def __contains__(self, tag: object) -> bool:
4343 return tag in self._data or (self._info is not None and tag in self._info)
4345 def __setitem__(self, tag: int, value: Any) -> None:
4346 if self._info is not None and tag in self._info:
4347 del self._info[tag]
4348 self._data[tag] = value
4350 def __delitem__(self, tag: int) -> None:
4351 if self._info is not None and tag in self._info:
4352 del self._info[tag]
4353 else:
4354 del self._data[tag]
4355 if tag in self._ifds:
4356 del self._ifds[tag]
4358 def __iter__(self) -> Iterator[int]:
4359 keys = set(self._data)
4360 if self._info is not None:
4361 keys.update(self._info)
4362 return iter(keys)