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
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) -> Image:
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 = ""
735 if format:
736 suffix = f".{format}"
738 if not file:
739 f, filename = tempfile.mkstemp(suffix)
740 os.close(f)
741 else:
742 filename = file
743 if not filename.endswith(suffix):
744 filename = filename + suffix
746 self.load()
748 if not format or format == "PPM":
749 self.im.save_ppm(filename)
750 else:
751 self.save(filename, format, **options)
753 return filename
755 def __eq__(self, other: object) -> bool:
756 if self.__class__ is not other.__class__:
757 return False
758 assert isinstance(other, Image)
759 return (
760 self.mode == other.mode
761 and self.size == other.size
762 and self.info == other.info
763 and self.getpalette() == other.getpalette()
764 and self.tobytes() == other.tobytes()
765 )
767 def __repr__(self) -> str:
768 return (
769 f"<{self.__class__.__module__}.{self.__class__.__name__} "
770 f"image mode={self.mode} size={self.size[0]}x{self.size[1]} "
771 f"at 0x{id(self):X}>"
772 )
774 def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None:
775 """IPython plain text display support"""
777 # Same as __repr__ but without unpredictable id(self),
778 # to keep Jupyter notebook `text/plain` output stable.
779 p.text(
780 f"<{self.__class__.__module__}.{self.__class__.__name__} "
781 f"image mode={self.mode} size={self.size[0]}x{self.size[1]}>"
782 )
784 def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None:
785 """Helper function for iPython display hook.
787 :param image_format: Image format.
788 :returns: image as bytes, saved into the given format.
789 """
790 b = io.BytesIO()
791 try:
792 self.save(b, image_format, **kwargs)
793 except Exception:
794 return None
795 return b.getvalue()
797 def _repr_png_(self) -> bytes | None:
798 """iPython display hook support for PNG format.
800 :returns: PNG version of the image as bytes
801 """
802 return self._repr_image("PNG", compress_level=1)
804 def _repr_jpeg_(self) -> bytes | None:
805 """iPython display hook support for JPEG format.
807 :returns: JPEG version of the image as bytes
808 """
809 return self._repr_image("JPEG")
811 @property
812 def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]:
813 # numpy array interface support
814 new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3}
815 if self.mode == "1":
816 # Binary images need to be extended from bits to bytes
817 # See: https://github.com/python-pillow/Pillow/issues/350
818 new["data"] = self.tobytes("raw", "L")
819 else:
820 new["data"] = self.tobytes()
821 new["shape"], new["typestr"] = _conv_type_shape(self)
822 return new
824 def __arrow_c_schema__(self) -> object:
825 self.load()
826 return self.im.__arrow_c_schema__()
828 def __arrow_c_array__(
829 self, requested_schema: object | None = None
830 ) -> tuple[object, object]:
831 self.load()
832 return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__())
834 def __getstate__(self) -> list[Any]:
835 im_data = self.tobytes() # load image first
836 return [self.info, self.mode, self.size, self.getpalette(), im_data]
838 def __setstate__(self, state: list[Any]) -> None:
839 Image.__init__(self)
840 info, mode, size, palette, data = state[:5]
841 self.info = info
842 self._mode = mode
843 self._size = size
844 self.im = core.new(mode, size)
845 if mode in ("L", "LA", "P", "PA") and palette:
846 self.putpalette(palette)
847 self.frombytes(data)
849 def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes:
850 """
851 Return image as a bytes object.
853 .. warning::
855 This method returns raw image data derived from Pillow's internal
856 storage. For compressed image data (e.g. PNG, JPEG) use
857 :meth:`~.save`, with a BytesIO parameter for in-memory data.
859 :param encoder_name: What encoder to use.
861 The default is to use the standard "raw" encoder.
862 To see how this packs pixel data into the returned
863 bytes, see :file:`libImaging/Pack.c`.
865 A list of C encoders can be seen under codecs
866 section of the function array in
867 :file:`_imaging.c`. Python encoders are registered
868 within the relevant plugins.
869 :param args: Extra arguments to the encoder.
870 :returns: A :py:class:`bytes` object.
871 """
873 encoder_args: Any = args
874 if len(encoder_args) == 1 and isinstance(encoder_args[0], tuple):
875 # may pass tuple instead of argument list
876 encoder_args = encoder_args[0]
878 if encoder_name == "raw" and encoder_args == ():
879 encoder_args = self.mode
881 self.load()
883 if self.width == 0 or self.height == 0:
884 return b""
886 # unpack data
887 e = _getencoder(self.mode, encoder_name, encoder_args)
888 e.setimage(self.im, (0, 0) + self.size)
890 from . import ImageFile
892 bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c
894 output = []
895 while True:
896 bytes_consumed, errcode, data = e.encode(bufsize)
897 output.append(data)
898 if errcode:
899 break
900 if errcode < 0:
901 msg = f"encoder error {errcode} in tobytes"
902 raise RuntimeError(msg)
904 return b"".join(output)
906 def tobitmap(self, name: str = "image") -> bytes:
907 """
908 Returns the image converted to an X11 bitmap.
910 .. note:: This method only works for mode "1" images.
912 :param name: The name prefix to use for the bitmap variables.
913 :returns: A string containing an X11 bitmap.
914 :raises ValueError: If the mode is not "1"
915 """
917 self.load()
918 if self.mode != "1":
919 msg = "not a bitmap"
920 raise ValueError(msg)
921 data = self.tobytes("xbm")
922 return b"".join(
923 [
924 f"#define {name}_width {self.size[0]}\n".encode("ascii"),
925 f"#define {name}_height {self.size[1]}\n".encode("ascii"),
926 f"static char {name}_bits[] = {{\n".encode("ascii"),
927 data,
928 b"};",
929 ]
930 )
932 def frombytes(
933 self,
934 data: bytes | bytearray | SupportsArrayInterface,
935 decoder_name: str = "raw",
936 *args: Any,
937 ) -> None:
938 """
939 Loads this image with pixel data from a bytes object.
941 This method is similar to the :py:func:`~PIL.Image.frombytes` function,
942 but loads data into this image instead of creating a new image object.
943 """
945 if self.width == 0 or self.height == 0:
946 return
948 decoder_args: Any = args
949 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
950 # may pass tuple instead of argument list
951 decoder_args = decoder_args[0]
953 # default format
954 if decoder_name == "raw" and decoder_args == ():
955 decoder_args = self.mode
957 # unpack data
958 d = _getdecoder(self.mode, decoder_name, decoder_args)
959 d.setimage(self.im, (0, 0) + self.size)
960 s = d.decode(data)
962 if s[0] >= 0:
963 msg = "not enough image data"
964 raise ValueError(msg)
965 if s[1] != 0:
966 msg = "cannot decode image data"
967 raise ValueError(msg)
969 def load(self) -> core.PixelAccess | None:
970 """
971 Allocates storage for the image and loads the pixel data. In
972 normal cases, you don't need to call this method, since the
973 Image class automatically loads an opened image when it is
974 accessed for the first time.
976 If the file associated with the image was opened by Pillow, then this
977 method will close it. The exception to this is if the image has
978 multiple frames, in which case the file will be left open for seek
979 operations. See :ref:`file-handling` for more information.
981 :returns: An image access object.
982 :rtype: :py:class:`.PixelAccess`
983 """
984 if self._im is not None and self.palette and self.palette.dirty:
985 # realize palette
986 mode, arr = self.palette.getdata()
987 self.im.putpalette(self.palette.mode, mode, arr)
988 self.palette.dirty = 0
989 self.palette.rawmode = None
990 if "transparency" in self.info and mode in ("LA", "PA"):
991 if isinstance(self.info["transparency"], int):
992 self.im.putpalettealpha(self.info["transparency"], 0)
993 else:
994 self.im.putpalettealphas(self.info["transparency"])
995 self.palette.mode = "RGBA"
996 elif self.palette.mode != mode:
997 # If the palette rawmode is different to the mode,
998 # then update the Python palette data
999 self.palette.palette = self.im.getpalette(
1000 self.palette.mode, self.palette.mode
1001 )
1003 if self._im is not None:
1004 return self.im.pixel_access(self.readonly)
1005 return None
1007 def verify(self) -> None:
1008 """
1009 Verifies the contents of a file. For data read from a file, this
1010 method attempts to determine if the file is broken, without
1011 actually decoding the image data. If this method finds any
1012 problems, it raises suitable exceptions. If you need to load
1013 the image after using this method, you must reopen the image
1014 file.
1015 """
1016 pass
1018 def convert(
1019 self,
1020 mode: str | None = None,
1021 matrix: tuple[float, ...] | None = None,
1022 dither: Dither | None = None,
1023 palette: Palette = Palette.WEB,
1024 colors: int = 256,
1025 ) -> Image:
1026 """
1027 Returns a converted copy of this image. For the "P" mode, this
1028 method translates pixels through the palette. If mode is
1029 omitted, a mode is chosen so that all information in the image
1030 and the palette can be represented without a palette.
1032 This supports all possible conversions between "L", "RGB" and "CMYK". The
1033 ``matrix`` argument only supports "L" and "RGB".
1035 When translating a color image to grayscale (mode "L"),
1036 the library uses the ITU-R 601-2 luma transform::
1038 L = R * 299/1000 + G * 587/1000 + B * 114/1000
1040 The default method of converting a grayscale ("L") or "RGB"
1041 image into a bilevel (mode "1") image uses Floyd-Steinberg
1042 dither to approximate the original image luminosity levels. If
1043 dither is ``None``, all values larger than 127 are set to 255 (white),
1044 all other values to 0 (black). To use other thresholds, use the
1045 :py:meth:`~PIL.Image.Image.point` method.
1047 When converting from "RGBA" to "P" without a ``matrix`` argument,
1048 this passes the operation to :py:meth:`~PIL.Image.Image.quantize`,
1049 and ``dither`` and ``palette`` are ignored.
1051 When converting from "PA", if an "RGBA" palette is present, the alpha
1052 channel from the image will be used instead of the values from the palette.
1054 :param mode: The requested mode. See: :ref:`concept-modes`.
1055 :param matrix: An optional conversion matrix. If given, this
1056 should be 4- or 12-tuple containing floating point values.
1057 :param dither: Dithering method, used when converting from
1058 mode "RGB" to "P" or from "RGB" or "L" to "1".
1059 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1060 (default). Note that this is not used when ``matrix`` is supplied.
1061 :param palette: Palette to use when converting from mode "RGB"
1062 to "P". Available palettes are :data:`Palette.WEB` or
1063 :data:`Palette.ADAPTIVE`.
1064 :param colors: Number of colors to use for the :data:`Palette.ADAPTIVE`
1065 palette. Defaults to 256.
1066 :rtype: :py:class:`~PIL.Image.Image`
1067 :returns: An :py:class:`~PIL.Image.Image` object.
1068 """
1070 self.load()
1072 has_transparency = "transparency" in self.info
1073 if not mode and self.mode == "P":
1074 # determine default mode
1075 if self.palette:
1076 mode = self.palette.mode
1077 else:
1078 mode = "RGB"
1079 if mode == "RGB" and has_transparency:
1080 mode = "RGBA"
1081 if not mode or (mode == self.mode and not matrix):
1082 return self.copy()
1084 if matrix:
1085 # matrix conversion
1086 if mode not in ("L", "RGB"):
1087 msg = "illegal conversion"
1088 raise ValueError(msg)
1089 im = self.im.convert_matrix(mode, matrix)
1090 new_im = self._new(im)
1091 if has_transparency and self.im.bands == 3:
1092 transparency = new_im.info["transparency"]
1094 def convert_transparency(
1095 m: tuple[float, ...], v: tuple[int, int, int]
1096 ) -> int:
1097 value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5
1098 return max(0, min(255, int(value)))
1100 if mode == "L":
1101 transparency = convert_transparency(matrix, transparency)
1102 elif len(mode) == 3:
1103 transparency = tuple(
1104 convert_transparency(matrix[i * 4 : i * 4 + 4], transparency)
1105 for i in range(len(transparency))
1106 )
1107 new_im.info["transparency"] = transparency
1108 return new_im
1110 if self.mode == "RGBA":
1111 if mode == "P":
1112 return self.quantize(colors)
1113 elif mode == "PA":
1114 r, g, b, a = self.split()
1115 rgb = merge("RGB", (r, g, b))
1116 p = rgb.quantize(colors)
1117 return merge("PA", (p, a))
1119 trns = None
1120 delete_trns = False
1121 # transparency handling
1122 if has_transparency:
1123 if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or (
1124 self.mode == "RGB" and mode in ("La", "LA", "RGBa", "RGBA")
1125 ):
1126 # Use transparent conversion to promote from transparent
1127 # color to an alpha channel.
1128 new_im = self._new(
1129 self.im.convert_transparent(mode, self.info["transparency"])
1130 )
1131 del new_im.info["transparency"]
1132 return new_im
1133 elif self.mode in ("L", "RGB", "P") and mode in ("L", "RGB", "P"):
1134 t = self.info["transparency"]
1135 if isinstance(t, bytes):
1136 # Dragons. This can't be represented by a single color
1137 warnings.warn(
1138 "Palette images with Transparency expressed in bytes should be "
1139 "converted to RGBA images"
1140 )
1141 delete_trns = True
1142 else:
1143 # get the new transparency color.
1144 # use existing conversions
1145 trns_im = new(self.mode, (1, 1))
1146 if self.mode == "P":
1147 assert self.palette is not None
1148 trns_im.putpalette(self.palette, self.palette.mode)
1149 if isinstance(t, tuple):
1150 err = "Couldn't allocate a palette color for transparency"
1151 assert trns_im.palette is not None
1152 try:
1153 t = trns_im.palette.getcolor(t, self)
1154 except ValueError as e:
1155 if str(e) == "cannot allocate more than 256 colors":
1156 # If all 256 colors are in use,
1157 # then there is no need for transparency
1158 t = None
1159 else:
1160 raise ValueError(err) from e
1161 if t is None:
1162 trns = None
1163 else:
1164 trns_im.putpixel((0, 0), t)
1166 if mode in ("L", "RGB"):
1167 trns_im = trns_im.convert(mode)
1168 else:
1169 # can't just retrieve the palette number, got to do it
1170 # after quantization.
1171 trns_im = trns_im.convert("RGB")
1172 trns = trns_im.getpixel((0, 0))
1174 elif self.mode == "P" and mode in ("LA", "PA", "RGBA"):
1175 t = self.info["transparency"]
1176 delete_trns = True
1178 if isinstance(t, bytes):
1179 self.im.putpalettealphas(t)
1180 elif isinstance(t, int):
1181 self.im.putpalettealpha(t, 0)
1182 else:
1183 msg = "Transparency for P mode should be bytes or int"
1184 raise ValueError(msg)
1186 if mode == "P" and palette == Palette.ADAPTIVE:
1187 im = self.im.quantize(colors)
1188 new_im = self._new(im)
1189 from . import ImagePalette
1191 new_im.palette = ImagePalette.ImagePalette(
1192 "RGB", new_im.im.getpalette("RGB")
1193 )
1194 if delete_trns:
1195 # This could possibly happen if we requantize to fewer colors.
1196 # The transparency would be totally off in that case.
1197 del new_im.info["transparency"]
1198 if trns is not None:
1199 try:
1200 new_im.info["transparency"] = new_im.palette.getcolor(
1201 cast(tuple[int, ...], trns), # trns was converted to RGB
1202 new_im,
1203 )
1204 except Exception:
1205 # if we can't make a transparent color, don't leave the old
1206 # transparency hanging around to mess us up.
1207 del new_im.info["transparency"]
1208 warnings.warn("Couldn't allocate palette entry for transparency")
1209 return new_im
1211 if "LAB" in (self.mode, mode):
1212 im = self
1213 if mode == "LAB":
1214 if im.mode not in ("RGB", "RGBA", "RGBX"):
1215 im = im.convert("RGBA")
1216 other_mode = im.mode
1217 else:
1218 other_mode = mode
1219 if other_mode in ("RGB", "RGBA", "RGBX"):
1220 from . import ImageCms
1222 srgb = ImageCms.createProfile("sRGB")
1223 lab = ImageCms.createProfile("LAB")
1224 profiles = [lab, srgb] if im.mode == "LAB" else [srgb, lab]
1225 transform = ImageCms.buildTransform(
1226 profiles[0], profiles[1], im.mode, mode
1227 )
1228 return transform.apply(im)
1230 # colorspace conversion
1231 if dither is None:
1232 dither = Dither.FLOYDSTEINBERG
1234 try:
1235 im = self.im.convert(mode, dither)
1236 except ValueError:
1237 try:
1238 # normalize source image and try again
1239 modebase = getmodebase(self.mode)
1240 if modebase == self.mode:
1241 raise
1242 im = self.im.convert(modebase)
1243 im = im.convert(mode, dither)
1244 except KeyError as e:
1245 msg = "illegal conversion"
1246 raise ValueError(msg) from e
1248 new_im = self._new(im)
1249 if mode in ("P", "PA") and palette != Palette.ADAPTIVE:
1250 from . import ImagePalette
1252 new_im.palette = ImagePalette.ImagePalette("RGB", im.getpalette("RGB"))
1253 if delete_trns:
1254 # crash fail if we leave a bytes transparency in an rgb/l mode.
1255 del new_im.info["transparency"]
1256 if trns is not None:
1257 if new_im.mode == "P" and new_im.palette:
1258 try:
1259 new_im.info["transparency"] = new_im.palette.getcolor(
1260 cast(tuple[int, ...], trns), new_im # trns was converted to RGB
1261 )
1262 except ValueError as e:
1263 del new_im.info["transparency"]
1264 if str(e) != "cannot allocate more than 256 colors":
1265 # If all 256 colors are in use,
1266 # then there is no need for transparency
1267 warnings.warn(
1268 "Couldn't allocate palette entry for transparency"
1269 )
1270 else:
1271 new_im.info["transparency"] = trns
1272 return new_im
1274 def quantize(
1275 self,
1276 colors: int = 256,
1277 method: int | None = None,
1278 kmeans: int = 0,
1279 palette: Image | None = None,
1280 dither: Dither = Dither.FLOYDSTEINBERG,
1281 ) -> Image:
1282 """
1283 Convert the image to 'P' mode with the specified number
1284 of colors.
1286 :param colors: The desired number of colors, <= 256
1287 :param method: :data:`Quantize.MEDIANCUT` (median cut),
1288 :data:`Quantize.MAXCOVERAGE` (maximum coverage),
1289 :data:`Quantize.FASTOCTREE` (fast octree),
1290 :data:`Quantize.LIBIMAGEQUANT` (libimagequant; check support
1291 using :py:func:`PIL.features.check_feature` with
1292 ``feature="libimagequant"``).
1294 By default, :data:`Quantize.MEDIANCUT` will be used.
1296 The exception to this is RGBA images. :data:`Quantize.MEDIANCUT`
1297 and :data:`Quantize.MAXCOVERAGE` do not support RGBA images, so
1298 :data:`Quantize.FASTOCTREE` is used by default instead.
1299 :param kmeans: Integer greater than or equal to zero.
1300 :param palette: Quantize to the palette of given
1301 :py:class:`PIL.Image.Image`.
1302 :param dither: Dithering method, used when converting from
1303 mode "RGB" to "P" or from "RGB" or "L" to "1".
1304 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1305 (default).
1306 :returns: A new image
1307 """
1309 self.load()
1311 if method is None:
1312 # defaults:
1313 method = Quantize.MEDIANCUT
1314 if self.mode == "RGBA":
1315 method = Quantize.FASTOCTREE
1317 if self.mode == "RGBA" and method not in (
1318 Quantize.FASTOCTREE,
1319 Quantize.LIBIMAGEQUANT,
1320 ):
1321 # Caller specified an invalid mode.
1322 msg = (
1323 "Fast Octree (method == 2) and libimagequant (method == 3) "
1324 "are the only valid methods for quantizing RGBA images"
1325 )
1326 raise ValueError(msg)
1328 if palette:
1329 # use palette from reference image
1330 palette.load()
1331 if palette.mode != "P":
1332 msg = "bad mode for palette image"
1333 raise ValueError(msg)
1334 if self.mode not in {"RGB", "L"}:
1335 msg = "only RGB or L mode images can be quantized to a palette"
1336 raise ValueError(msg)
1337 im = self.im.convert("P", dither, palette.im)
1338 new_im = self._new(im)
1339 assert palette.palette is not None
1340 new_im.palette = palette.palette.copy()
1341 return new_im
1343 if kmeans < 0:
1344 msg = "kmeans must not be negative"
1345 raise ValueError(msg)
1347 im = self._new(self.im.quantize(colors, method, kmeans))
1349 from . import ImagePalette
1351 mode = im.im.getpalettemode()
1352 palette_data = im.im.getpalette(mode, mode)[: colors * len(mode)]
1353 im.palette = ImagePalette.ImagePalette(mode, palette_data)
1355 return im
1357 def copy(self) -> Image:
1358 """
1359 Copies this image. Use this method if you wish to paste things
1360 into an image, but still retain the original.
1362 :rtype: :py:class:`~PIL.Image.Image`
1363 :returns: An :py:class:`~PIL.Image.Image` object.
1364 """
1365 self.load()
1366 return self._new(self.im.copy())
1368 __copy__ = copy
1370 def crop(self, box: tuple[float, float, float, float] | None = None) -> Image:
1371 """
1372 Returns a rectangular region from this image. The box is a
1373 4-tuple defining the left, upper, right, and lower pixel
1374 coordinate. See :ref:`coordinate-system`.
1376 Note: Prior to Pillow 3.4.0, this was a lazy operation.
1378 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1379 :rtype: :py:class:`~PIL.Image.Image`
1380 :returns: An :py:class:`~PIL.Image.Image` object.
1381 """
1383 if box is None:
1384 return self.copy()
1386 if box[2] < box[0]:
1387 msg = "Coordinate 'right' is less than 'left'"
1388 raise ValueError(msg)
1389 elif box[3] < box[1]:
1390 msg = "Coordinate 'lower' is less than 'upper'"
1391 raise ValueError(msg)
1393 self.load()
1394 return self._new(self._crop(self.im, box))
1396 def _crop(
1397 self, im: core.ImagingCore, box: tuple[float, float, float, float]
1398 ) -> core.ImagingCore:
1399 """
1400 Returns a rectangular region from the core image object im.
1402 This is equivalent to calling im.crop((x0, y0, x1, y1)), but
1403 includes additional sanity checks.
1405 :param im: a core image object
1406 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1407 :returns: A core image object.
1408 """
1410 x0, y0, x1, y1 = map(int, map(round, box))
1412 absolute_values = (abs(x1 - x0), abs(y1 - y0))
1414 _decompression_bomb_check(absolute_values)
1416 return im.crop((x0, y0, x1, y1))
1418 def draft(
1419 self, mode: str | None, size: tuple[int, int] | None
1420 ) -> tuple[str, tuple[int, int, float, float]] | None:
1421 """
1422 Configures the image file loader so it returns a version of the
1423 image that as closely as possible matches the given mode and
1424 size. For example, you can use this method to convert a color
1425 JPEG to grayscale while loading it.
1427 If any changes are made, returns a tuple with the chosen ``mode`` and
1428 ``box`` with coordinates of the original image within the altered one.
1430 Note that this method modifies the :py:class:`~PIL.Image.Image` object
1431 in place. If the image has already been loaded, this method has no
1432 effect.
1434 Note: This method is not implemented for most images. It is
1435 currently implemented only for JPEG and MPO images.
1437 :param mode: The requested mode.
1438 :param size: The requested size in pixels, as a 2-tuple:
1439 (width, height).
1440 """
1441 pass
1443 def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image:
1444 """
1445 Filters this image using the given filter. For a list of
1446 available filters, see the :py:mod:`~PIL.ImageFilter` module.
1448 :param filter: Filter kernel.
1449 :returns: An :py:class:`~PIL.Image.Image` object."""
1451 from . import ImageFilter
1453 self.load()
1455 if callable(filter):
1456 filter = filter()
1457 if not hasattr(filter, "filter"):
1458 msg = "filter argument should be ImageFilter.Filter instance or class"
1459 raise TypeError(msg)
1461 multiband = isinstance(filter, ImageFilter.MultibandFilter)
1462 if self.im.bands == 1 or multiband:
1463 return self._new(filter.filter(self.im))
1465 ims = [
1466 self._new(filter.filter(self.im.getband(c))) for c in range(self.im.bands)
1467 ]
1468 return merge(self.mode, ims)
1470 def getbands(self) -> tuple[str, ...]:
1471 """
1472 Returns a tuple containing the name of each band in this image.
1473 For example, ``getbands`` on an RGB image returns ("R", "G", "B").
1475 :returns: A tuple containing band names.
1476 :rtype: tuple
1477 """
1478 return ImageMode.getmode(self.mode).bands
1480 def getbbox(self, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None:
1481 """
1482 Calculates the bounding box of the non-zero regions in the
1483 image.
1485 :param alpha_only: Optional flag, defaulting to ``True``.
1486 If ``True`` and the image has an alpha channel, trim transparent pixels.
1487 Otherwise, trim pixels when all channels are zero.
1488 Keyword-only argument.
1489 :returns: The bounding box is returned as a 4-tuple defining the
1490 left, upper, right, and lower pixel coordinate. See
1491 :ref:`coordinate-system`. If the image is completely empty, this
1492 method returns None.
1494 """
1496 self.load()
1497 return self.im.getbbox(alpha_only)
1499 def getcolors(
1500 self, maxcolors: int = 256
1501 ) -> list[tuple[int, tuple[int, ...]]] | list[tuple[int, float]] | None:
1502 """
1503 Returns a list of colors used in this image.
1505 The colors will be in the image's mode. For example, an RGB image will
1506 return a tuple of (red, green, blue) color values, and a P image will
1507 return the index of the color in the palette.
1509 :param maxcolors: Maximum number of colors. If this number is
1510 exceeded, this method returns None. The default limit is
1511 256 colors.
1512 :returns: An unsorted list of (count, pixel) values.
1513 """
1515 self.load()
1516 if self.mode in ("1", "L", "P"):
1517 h = self.im.histogram()
1518 out: list[tuple[int, float]] = [(h[i], i) for i in range(256) if h[i]]
1519 if len(out) > maxcolors:
1520 return None
1521 return out
1522 return self.im.getcolors(maxcolors)
1524 def getdata(self, band: int | None = None) -> core.ImagingCore:
1525 """
1526 Returns the contents of this image as a sequence object
1527 containing pixel values. The sequence object is flattened, so
1528 that values for line one follow directly after the values of
1529 line zero, and so on.
1531 Note that the sequence object returned by this method is an
1532 internal PIL data type, which only supports certain sequence
1533 operations. To convert it to an ordinary sequence (e.g. for
1534 printing), use ``list(im.getdata())``.
1536 :param band: What band to return. The default is to return
1537 all bands. To return a single band, pass in the index
1538 value (e.g. 0 to get the "R" band from an "RGB" image).
1539 :returns: A sequence-like object.
1540 """
1541 deprecate("Image.Image.getdata", 14, "get_flattened_data")
1543 self.load()
1544 if band is not None:
1545 return self.im.getband(band)
1546 return self.im # could be abused
1548 def get_flattened_data(
1549 self, band: int | None = None
1550 ) -> tuple[tuple[int, ...], ...] | tuple[float, ...]:
1551 """
1552 Returns the contents of this image as a tuple containing pixel values.
1553 The sequence object is flattened, so that values for line one follow
1554 directly after the values of line zero, and so on.
1556 :param band: What band to return. The default is to return
1557 all bands. To return a single band, pass in the index
1558 value (e.g. 0 to get the "R" band from an "RGB" image).
1559 :returns: A tuple containing pixel values.
1560 """
1561 self.load()
1562 if band is not None:
1563 return tuple(self.im.getband(band))
1564 return tuple(self.im)
1566 def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]:
1567 """
1568 Gets the minimum and maximum pixel values for each band in
1569 the image.
1571 :returns: For a single-band image, a 2-tuple containing the
1572 minimum and maximum pixel value. For a multi-band image,
1573 a tuple containing one 2-tuple for each band.
1574 """
1576 self.load()
1577 if self.im.bands > 1:
1578 return tuple(self.im.getband(i).getextrema() for i in range(self.im.bands))
1579 return self.im.getextrema()
1581 def getxmp(self) -> dict[str, Any]:
1582 """
1583 Returns a dictionary containing the XMP tags.
1584 Requires defusedxml to be installed.
1586 :returns: XMP tags in a dictionary.
1587 """
1589 def get_name(tag: str) -> str:
1590 return re.sub("^{[^}]+}", "", tag)
1592 def get_value(element: Element) -> str | dict[str, Any] | None:
1593 value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()}
1594 children = list(element)
1595 if children:
1596 for child in children:
1597 name = get_name(child.tag)
1598 child_value = get_value(child)
1599 if name in value:
1600 if not isinstance(value[name], list):
1601 value[name] = [value[name]]
1602 value[name].append(child_value)
1603 else:
1604 value[name] = child_value
1605 elif value:
1606 if element.text:
1607 value["text"] = element.text
1608 else:
1609 return element.text
1610 return value
1612 if ElementTree is None:
1613 warnings.warn("XMP data cannot be read without defusedxml dependency")
1614 return {}
1615 if "xmp" not in self.info:
1616 return {}
1617 root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 "))
1618 return {get_name(root.tag): get_value(root)}
1620 def getexif(self) -> Exif:
1621 """
1622 Gets EXIF data from the image.
1624 :returns: an :py:class:`~PIL.Image.Exif` object.
1625 """
1626 if self._exif is None:
1627 self._exif = Exif()
1628 elif self._exif._loaded:
1629 return self._exif
1630 self._exif._loaded = True
1632 exif_info = self.info.get("exif")
1633 if exif_info is None:
1634 if "Raw profile type exif" in self.info:
1635 exif_info = bytes.fromhex(
1636 "".join(self.info["Raw profile type exif"].split("\n")[3:])
1637 )
1638 elif hasattr(self, "tag_v2"):
1639 from . import TiffImagePlugin
1641 assert isinstance(self, TiffImagePlugin.TiffImageFile)
1642 self._exif.bigtiff = self.tag_v2._bigtiff
1643 self._exif.endian = self.tag_v2._endian
1645 assert self.fp is not None
1646 self._exif.load_from_fp(self.fp, self.tag_v2._offset)
1647 if exif_info is not None:
1648 self._exif.load(exif_info)
1650 # XMP tags
1651 if ExifTags.Base.Orientation not in self._exif:
1652 xmp_tags = self.info.get("XML:com.adobe.xmp")
1653 pattern: str | bytes = r'tiff:Orientation(="|>)([0-9])'
1654 if not xmp_tags and (xmp_tags := self.info.get("xmp")):
1655 pattern = rb'tiff:Orientation(="|>)([0-9])'
1656 if xmp_tags:
1657 match = re.search(pattern, xmp_tags)
1658 if match:
1659 self._exif[ExifTags.Base.Orientation] = int(match[2])
1661 return self._exif
1663 def _reload_exif(self) -> None:
1664 if self._exif is None or not self._exif._loaded:
1665 return
1666 self._exif._loaded = False
1667 self.getexif()
1669 def get_child_images(self) -> list[ImageFile.ImageFile]:
1670 from . import ImageFile
1672 deprecate("Image.Image.get_child_images", 13)
1673 return ImageFile.ImageFile.get_child_images(self) # type: ignore[arg-type]
1675 def getim(self) -> CapsuleType:
1676 """
1677 Returns a capsule that points to the internal image memory.
1679 :returns: A capsule object.
1680 """
1682 self.load()
1683 return self.im.ptr
1685 def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None:
1686 """
1687 Returns the image palette as a list.
1689 :param rawmode: The mode in which to return the palette. ``None`` will
1690 return the palette in its current mode.
1692 .. versionadded:: 9.1.0
1694 :returns: A list of color values [r, g, b, ...], or None if the
1695 image has no palette.
1696 """
1698 self.load()
1699 try:
1700 mode = self.im.getpalettemode()
1701 except ValueError:
1702 return None # no palette
1703 if rawmode is None:
1704 rawmode = mode
1705 return list(self.im.getpalette(mode, rawmode))
1707 @property
1708 def has_transparency_data(self) -> bool:
1709 """
1710 Determine if an image has transparency data, whether in the form of an
1711 alpha channel, a palette with an alpha channel, or a "transparency" key
1712 in the info dictionary.
1714 Note the image might still appear solid, if all of the values shown
1715 within are opaque.
1717 :returns: A boolean.
1718 """
1719 if (
1720 self.mode in ("LA", "La", "PA", "RGBA", "RGBa")
1721 or "transparency" in self.info
1722 ):
1723 return True
1724 if self.mode == "P":
1725 assert self.palette is not None
1726 return self.palette.mode.endswith("A")
1727 return False
1729 def apply_transparency(self) -> None:
1730 """
1731 If a P mode image has a "transparency" key in the info dictionary,
1732 remove the key and instead apply the transparency to the palette.
1733 Otherwise, the image is unchanged.
1734 """
1735 if self.mode != "P" or "transparency" not in self.info:
1736 return
1738 from . import ImagePalette
1740 palette = self.getpalette("RGBA")
1741 assert palette is not None
1742 transparency = self.info["transparency"]
1743 if isinstance(transparency, bytes):
1744 for i, alpha in enumerate(transparency):
1745 palette[i * 4 + 3] = alpha
1746 else:
1747 palette[transparency * 4 + 3] = 0
1748 self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette))
1749 self.palette.dirty = 1
1751 del self.info["transparency"]
1753 def getpixel(
1754 self, xy: tuple[int, int] | list[int]
1755 ) -> float | tuple[int, ...] | None:
1756 """
1757 Returns the pixel value at a given position.
1759 :param xy: The coordinate, given as (x, y). See
1760 :ref:`coordinate-system`.
1761 :returns: The pixel value. If the image is a multi-layer image,
1762 this method returns a tuple.
1763 """
1765 self.load()
1766 return self.im.getpixel(tuple(xy))
1768 def getprojection(self) -> tuple[list[int], list[int]]:
1769 """
1770 Get projection to x and y axes
1772 :returns: Two sequences, indicating where there are non-zero
1773 pixels along the X-axis and the Y-axis, respectively.
1774 """
1776 self.load()
1777 x, y = self.im.getprojection()
1778 return list(x), list(y)
1780 def histogram(
1781 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1782 ) -> list[int]:
1783 """
1784 Returns a histogram for the image. The histogram is returned as a
1785 list of pixel counts, one for each pixel value in the source
1786 image. Counts are grouped into 256 bins for each band, even if
1787 the image has more than 8 bits per band. If the image has more
1788 than one band, the histograms for all bands are concatenated (for
1789 example, the histogram for an "RGB" image contains 768 values).
1791 A bilevel image (mode "1") is treated as a grayscale ("L") image
1792 by this method.
1794 If a mask is provided, the method returns a histogram for those
1795 parts of the image where the mask image is non-zero. The mask
1796 image must have the same size as the image, and be either a
1797 bi-level image (mode "1") or a grayscale image ("L").
1799 :param mask: An optional mask.
1800 :param extrema: An optional tuple of manually-specified extrema.
1801 :returns: A list containing pixel counts.
1802 """
1803 self.load()
1804 if mask:
1805 mask.load()
1806 return self.im.histogram((0, 0), mask.im)
1807 if self.mode in ("I", "F"):
1808 return self.im.histogram(
1809 extrema if extrema is not None else self.getextrema()
1810 )
1811 return self.im.histogram()
1813 def entropy(
1814 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1815 ) -> float:
1816 """
1817 Calculates and returns the entropy for the image.
1819 A bilevel image (mode "1") is treated as a grayscale ("L")
1820 image by this method.
1822 If a mask is provided, the method employs the histogram for
1823 those parts of the image where the mask image is non-zero.
1824 The mask image must have the same size as the image, and be
1825 either a bi-level image (mode "1") or a grayscale image ("L").
1827 :param mask: An optional mask.
1828 :param extrema: An optional tuple of manually-specified extrema.
1829 :returns: A float value representing the image entropy
1830 """
1831 self.load()
1832 if mask:
1833 mask.load()
1834 return self.im.entropy((0, 0), mask.im)
1835 if self.mode in ("I", "F"):
1836 return self.im.entropy(
1837 extrema if extrema is not None else self.getextrema()
1838 )
1839 return self.im.entropy()
1841 def paste(
1842 self,
1843 im: Image | str | float | tuple[float, ...],
1844 box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None,
1845 mask: Image | None = None,
1846 ) -> None:
1847 """
1848 Pastes another image into this image. The box argument is either
1849 a 2-tuple giving the upper left corner, a 4-tuple defining the
1850 left, upper, right, and lower pixel coordinate, or None (same as
1851 (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size
1852 of the pasted image must match the size of the region.
1854 If the modes don't match, the pasted image is converted to the mode of
1855 this image (see the :py:meth:`~PIL.Image.Image.convert` method for
1856 details).
1858 Instead of an image, the source can be a integer or tuple
1859 containing pixel values. The method then fills the region
1860 with the given color. When creating RGB images, you can
1861 also use color strings as supported by the ImageColor module. See
1862 :ref:`colors` for more information.
1864 If a mask is given, this method updates only the regions
1865 indicated by the mask. You can use either "1", "L", "LA", "RGBA"
1866 or "RGBa" images (if present, the alpha band is used as mask).
1867 Where the mask is 255, the given image is copied as is. Where
1868 the mask is 0, the current value is preserved. Intermediate
1869 values will mix the two images together, including their alpha
1870 channels if they have them.
1872 See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
1873 combine images with respect to their alpha channels.
1875 :param im: Source image or pixel value (integer, float or tuple).
1876 :param box: An optional 4-tuple giving the region to paste into.
1877 If a 2-tuple is used instead, it's treated as the upper left
1878 corner. If omitted or None, the source is pasted into the
1879 upper left corner.
1881 If an image is given as the second argument and there is no
1882 third, the box defaults to (0, 0), and the second argument
1883 is interpreted as a mask image.
1884 :param mask: An optional mask image.
1885 """
1887 if isinstance(box, Image):
1888 if mask is not None:
1889 msg = "If using second argument as mask, third argument must be None"
1890 raise ValueError(msg)
1891 # abbreviated paste(im, mask) syntax
1892 mask = box
1893 box = None
1895 if box is None:
1896 box = (0, 0)
1898 if len(box) == 2:
1899 # upper left corner given; get size from image or mask
1900 if isinstance(im, Image):
1901 size = im.size
1902 elif isinstance(mask, Image):
1903 size = mask.size
1904 else:
1905 # FIXME: use self.size here?
1906 msg = "cannot determine region size; use 4-item box"
1907 raise ValueError(msg)
1908 box += (box[0] + size[0], box[1] + size[1])
1910 source: core.ImagingCore | str | float | tuple[float, ...]
1911 if isinstance(im, str):
1912 from . import ImageColor
1914 source = ImageColor.getcolor(im, self.mode)
1915 elif isinstance(im, Image):
1916 im.load()
1917 if self.mode != im.mode:
1918 if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"):
1919 # should use an adapter for this!
1920 im = im.convert(self.mode)
1921 source = im.im
1922 else:
1923 source = im
1925 self._ensure_mutable()
1927 if mask:
1928 mask.load()
1929 self.im.paste(source, box, mask.im)
1930 else:
1931 self.im.paste(source, box)
1933 def alpha_composite(
1934 self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0)
1935 ) -> None:
1936 """'In-place' analog of Image.alpha_composite. Composites an image
1937 onto this image.
1939 :param im: image to composite over this one
1940 :param dest: Optional 2 tuple (left, top) specifying the upper
1941 left corner in this (destination) image.
1942 :param source: Optional 2 (left, top) tuple for the upper left
1943 corner in the overlay source image, or 4 tuple (left, top, right,
1944 bottom) for the bounds of the source rectangle
1946 Performance Note: Not currently implemented in-place in the core layer.
1947 """
1949 if not isinstance(source, (list, tuple)):
1950 msg = "Source must be a list or tuple"
1951 raise ValueError(msg)
1952 if not isinstance(dest, (list, tuple)):
1953 msg = "Destination must be a list or tuple"
1954 raise ValueError(msg)
1956 if len(source) == 4:
1957 overlay_crop_box = tuple(source)
1958 elif len(source) == 2:
1959 overlay_crop_box = tuple(source) + im.size
1960 else:
1961 msg = "Source must be a sequence of length 2 or 4"
1962 raise ValueError(msg)
1964 if not len(dest) == 2:
1965 msg = "Destination must be a sequence of length 2"
1966 raise ValueError(msg)
1967 if min(source) < 0:
1968 msg = "Source must be non-negative"
1969 raise ValueError(msg)
1971 # over image, crop if it's not the whole image.
1972 if overlay_crop_box == (0, 0) + im.size:
1973 overlay = im
1974 else:
1975 overlay = im.crop(overlay_crop_box)
1977 # target for the paste
1978 box = tuple(dest) + (dest[0] + overlay.width, dest[1] + overlay.height)
1980 # destination image. don't copy if we're using the whole image.
1981 if box == (0, 0) + self.size:
1982 background = self
1983 else:
1984 background = self.crop(box)
1986 result = alpha_composite(background, overlay)
1987 self.paste(result, box)
1989 def point(
1990 self,
1991 lut: (
1992 Sequence[float]
1993 | NumpyArray
1994 | Callable[[int], float]
1995 | Callable[[ImagePointTransform], ImagePointTransform | float]
1996 | ImagePointHandler
1997 ),
1998 mode: str | None = None,
1999 ) -> Image:
2000 """
2001 Maps this image through a lookup table or function.
2003 :param lut: A lookup table, containing 256 (or 65536 if
2004 self.mode=="I" and mode == "L") values per band in the
2005 image. A function can be used instead, it should take a
2006 single argument. The function is called once for each
2007 possible pixel value, and the resulting table is applied to
2008 all bands of the image.
2010 It may also be an :py:class:`~PIL.Image.ImagePointHandler`
2011 object::
2013 class Example(Image.ImagePointHandler):
2014 def point(self, im: Image) -> Image:
2015 # Return result
2016 :param mode: Output mode (default is same as input). This can only be used if
2017 the source image has mode "L" or "P", and the output has mode "1" or the
2018 source image mode is "I" and the output mode is "L".
2019 :returns: An :py:class:`~PIL.Image.Image` object.
2020 """
2022 self.load()
2024 if isinstance(lut, ImagePointHandler):
2025 return lut.point(self)
2027 if callable(lut):
2028 # if it isn't a list, it should be a function
2029 if self.mode in ("I", "I;16", "F"):
2030 # check if the function can be used with point_transform
2031 # UNDONE wiredfool -- I think this prevents us from ever doing
2032 # a gamma function point transform on > 8bit images.
2033 scale, offset = _getscaleoffset(lut) # type: ignore[arg-type]
2034 return self._new(self.im.point_transform(scale, offset))
2035 # for other modes, convert the function to a table
2036 flatLut = [lut(i) for i in range(256)] * self.im.bands # type: ignore[arg-type]
2037 else:
2038 flatLut = lut
2040 if self.mode == "F":
2041 # FIXME: _imaging returns a confusing error message for this case
2042 msg = "point operation not supported for this mode"
2043 raise ValueError(msg)
2045 if mode != "F":
2046 flatLut = [round(i) for i in flatLut]
2047 return self._new(self.im.point(flatLut, mode))
2049 def putalpha(self, alpha: Image | int) -> None:
2050 """
2051 Adds or replaces the alpha layer in this image. If the image
2052 does not have an alpha layer, it's converted to "LA" or "RGBA".
2053 The new layer must be either "L" or "1".
2055 :param alpha: The new alpha layer. This can either be an "L" or "1"
2056 image having the same size as this image, or an integer.
2057 """
2059 self._ensure_mutable()
2061 if self.mode not in ("LA", "PA", "RGBA"):
2062 # attempt to promote self to a matching alpha mode
2063 try:
2064 mode = getmodebase(self.mode) + "A"
2065 try:
2066 self.im.setmode(mode)
2067 except (AttributeError, ValueError) as e:
2068 # do things the hard way
2069 im = self.im.convert(mode)
2070 if im.mode not in ("LA", "PA", "RGBA"):
2071 msg = "alpha channel could not be added"
2072 raise ValueError(msg) from e # sanity check
2073 self.im = im
2074 self._mode = self.im.mode
2075 except KeyError as e:
2076 msg = "illegal image mode"
2077 raise ValueError(msg) from e
2079 if self.mode in ("LA", "PA"):
2080 band = 1
2081 else:
2082 band = 3
2084 if isinstance(alpha, Image):
2085 # alpha layer
2086 if alpha.mode not in ("1", "L"):
2087 msg = "illegal image mode"
2088 raise ValueError(msg)
2089 alpha.load()
2090 if alpha.mode == "1":
2091 alpha = alpha.convert("L")
2092 else:
2093 # constant alpha
2094 try:
2095 self.im.fillband(band, alpha)
2096 except (AttributeError, ValueError):
2097 # do things the hard way
2098 alpha = new("L", self.size, alpha)
2099 else:
2100 return
2102 self.im.putband(alpha.im, band)
2104 def putdata(
2105 self,
2106 data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray,
2107 scale: float = 1.0,
2108 offset: float = 0.0,
2109 ) -> None:
2110 """
2111 Copies pixel data from a flattened sequence object into the image. The
2112 values should start at the upper left corner (0, 0), continue to the
2113 end of the line, followed directly by the first value of the second
2114 line, and so on. Data will be read until either the image or the
2115 sequence ends. The scale and offset values are used to adjust the
2116 sequence values: **pixel = value*scale + offset**.
2118 :param data: A flattened sequence object. See :ref:`colors` for more
2119 information about values.
2120 :param scale: An optional scale value. The default is 1.0.
2121 :param offset: An optional offset value. The default is 0.0.
2122 """
2124 self._ensure_mutable()
2126 self.im.putdata(data, scale, offset)
2128 def putpalette(
2129 self,
2130 data: ImagePalette.ImagePalette | bytes | Sequence[int],
2131 rawmode: str = "RGB",
2132 ) -> None:
2133 """
2134 Attaches a palette to this image. The image must be a "P", "PA", "L"
2135 or "LA" image.
2137 The palette sequence must contain at most 256 colors, made up of one
2138 integer value for each channel in the raw mode.
2139 For example, if the raw mode is "RGB", then it can contain at most 768
2140 values, made up of red, green and blue values for the corresponding pixel
2141 index in the 256 colors.
2142 If the raw mode is "RGBA", then it can contain at most 1024 values,
2143 containing red, green, blue and alpha values.
2145 Alternatively, an 8-bit string may be used instead of an integer sequence.
2147 :param data: A palette sequence (either a list or a string).
2148 :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", "CMYK", or a
2149 mode that can be transformed to one of those modes (e.g. "R", "RGBA;L").
2150 """
2151 from . import ImagePalette
2153 if self.mode not in ("L", "LA", "P", "PA"):
2154 msg = "illegal image mode"
2155 raise ValueError(msg)
2156 if isinstance(data, ImagePalette.ImagePalette):
2157 if data.rawmode is not None:
2158 palette = ImagePalette.raw(data.rawmode, data.palette)
2159 else:
2160 palette = ImagePalette.ImagePalette(palette=data.palette)
2161 palette.dirty = 1
2162 else:
2163 if not isinstance(data, bytes):
2164 data = bytes(data)
2165 palette = ImagePalette.raw(rawmode, data)
2166 self._mode = "PA" if "A" in self.mode else "P"
2167 self.palette = palette
2168 if rawmode.startswith("CMYK"):
2169 self.palette.mode = "CMYK"
2170 elif "A" in rawmode:
2171 self.palette.mode = "RGBA"
2172 else:
2173 self.palette.mode = "RGB"
2174 self.load() # install new palette
2176 def putpixel(
2177 self, xy: tuple[int, int], value: float | tuple[int, ...] | list[int]
2178 ) -> None:
2179 """
2180 Modifies the pixel at the given position. The color is given as
2181 a single numerical value for single-band images, and a tuple for
2182 multi-band images. In addition to this, RGB and RGBA tuples are
2183 accepted for P and PA images. See :ref:`colors` for more information.
2185 Note that this method is relatively slow. For more extensive changes,
2186 use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
2187 module instead.
2189 See:
2191 * :py:meth:`~PIL.Image.Image.paste`
2192 * :py:meth:`~PIL.Image.Image.putdata`
2193 * :py:mod:`~PIL.ImageDraw`
2195 :param xy: The pixel coordinate, given as (x, y). See
2196 :ref:`coordinate-system`.
2197 :param value: The pixel value.
2198 """
2200 self._ensure_mutable()
2202 if (
2203 self.mode in ("P", "PA")
2204 and isinstance(value, (list, tuple))
2205 and len(value) in [3, 4]
2206 ):
2207 # RGB or RGBA value for a P or PA image
2208 if self.mode == "PA":
2209 alpha = value[3] if len(value) == 4 else 255
2210 value = value[:3]
2211 assert self.palette is not None
2212 palette_index = self.palette.getcolor(tuple(value), self)
2213 value = (palette_index, alpha) if self.mode == "PA" else palette_index
2214 return self.im.putpixel(xy, value)
2216 def remap_palette(
2217 self, dest_map: list[int], source_palette: bytes | bytearray | None = None
2218 ) -> Image:
2219 """
2220 Rewrites the image to reorder the palette.
2222 :param dest_map: A list of indexes into the original palette.
2223 e.g. ``[1,0]`` would swap a two item palette, and ``list(range(256))``
2224 is the identity transform.
2225 :param source_palette: Bytes or None.
2226 :returns: An :py:class:`~PIL.Image.Image` object.
2228 """
2229 from . import ImagePalette
2231 if self.mode not in ("L", "P"):
2232 msg = "illegal image mode"
2233 raise ValueError(msg)
2235 bands = 3
2236 palette_mode = "RGB"
2237 if source_palette is None:
2238 if self.mode == "P":
2239 self.load()
2240 palette_mode = self.im.getpalettemode()
2241 if palette_mode == "RGBA":
2242 bands = 4
2243 source_palette = self.im.getpalette(palette_mode, palette_mode)
2244 else: # L-mode
2245 source_palette = bytearray(i // 3 for i in range(768))
2246 elif len(source_palette) > 768:
2247 bands = 4
2248 palette_mode = "RGBA"
2250 palette_bytes = b""
2251 new_positions = [0] * 256
2253 # pick only the used colors from the palette
2254 for i, oldPosition in enumerate(dest_map):
2255 palette_bytes += source_palette[
2256 oldPosition * bands : oldPosition * bands + bands
2257 ]
2258 new_positions[oldPosition] = i
2260 # replace the palette color id of all pixel with the new id
2262 # Palette images are [0..255], mapped through a 1 or 3
2263 # byte/color map. We need to remap the whole image
2264 # from palette 1 to palette 2. New_positions is
2265 # an array of indexes into palette 1. Palette 2 is
2266 # palette 1 with any holes removed.
2268 # We're going to leverage the convert mechanism to use the
2269 # C code to remap the image from palette 1 to palette 2,
2270 # by forcing the source image into 'L' mode and adding a
2271 # mapping 'L' mode palette, then converting back to 'L'
2272 # sans palette thus converting the image bytes, then
2273 # assigning the optimized RGB palette.
2275 # perf reference, 9500x4000 gif, w/~135 colors
2276 # 14 sec prepatch, 1 sec postpatch with optimization forced.
2278 mapping_palette = bytearray(new_positions)
2280 m_im = self.copy()
2281 m_im._mode = "P"
2283 m_im.palette = ImagePalette.ImagePalette(
2284 palette_mode, palette=mapping_palette * bands
2285 )
2286 # possibly set palette dirty, then
2287 # m_im.putpalette(mapping_palette, 'L') # converts to 'P'
2288 # or just force it.
2289 # UNDONE -- this is part of the general issue with palettes
2290 m_im.im.putpalette(palette_mode, palette_mode + ";L", m_im.palette.tobytes())
2292 m_im = m_im.convert("L")
2294 m_im.putpalette(palette_bytes, palette_mode)
2295 m_im.palette = ImagePalette.ImagePalette(palette_mode, palette=palette_bytes)
2297 if "transparency" in self.info:
2298 try:
2299 m_im.info["transparency"] = dest_map.index(self.info["transparency"])
2300 except ValueError:
2301 if "transparency" in m_im.info:
2302 del m_im.info["transparency"]
2304 return m_im
2306 def _get_safe_box(
2307 self,
2308 size: tuple[int, int],
2309 resample: Resampling,
2310 box: tuple[float, float, float, float],
2311 ) -> tuple[int, int, int, int]:
2312 """Expands the box so it includes adjacent pixels
2313 that may be used by resampling with the given resampling filter.
2314 """
2315 filter_support = _filters_support[resample] - 0.5
2316 scale_x = (box[2] - box[0]) / size[0]
2317 scale_y = (box[3] - box[1]) / size[1]
2318 support_x = filter_support * scale_x
2319 support_y = filter_support * scale_y
2321 return (
2322 max(0, int(box[0] - support_x)),
2323 max(0, int(box[1] - support_y)),
2324 min(self.size[0], math.ceil(box[2] + support_x)),
2325 min(self.size[1], math.ceil(box[3] + support_y)),
2326 )
2328 def resize(
2329 self,
2330 size: tuple[int, int] | list[int] | NumpyArray,
2331 resample: int | None = None,
2332 box: tuple[float, float, float, float] | None = None,
2333 reducing_gap: float | None = None,
2334 ) -> Image:
2335 """
2336 Returns a resized copy of this image.
2338 :param size: The requested size in pixels, as a tuple or array:
2339 (width, height).
2340 :param resample: An optional resampling filter. This can be
2341 one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2342 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2343 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`.
2344 If the image has mode "1" or "P", it is always set to
2345 :py:data:`Resampling.NEAREST`. Otherwise, the default filter is
2346 :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`.
2347 :param box: An optional 4-tuple of floats providing
2348 the source image region to be scaled.
2349 The values must be within (0, 0, width, height) rectangle.
2350 If omitted or None, the entire source is used.
2351 :param reducing_gap: Apply optimization by resizing the image
2352 in two steps. First, reducing the image by integer times
2353 using :py:meth:`~PIL.Image.Image.reduce`.
2354 Second, resizing using regular resampling. The last step
2355 changes size no less than by ``reducing_gap`` times.
2356 ``reducing_gap`` may be None (no first step is performed)
2357 or should be greater than 1.0. The bigger ``reducing_gap``,
2358 the closer the result to the fair resampling.
2359 The smaller ``reducing_gap``, the faster resizing.
2360 With ``reducing_gap`` greater or equal to 3.0, the result is
2361 indistinguishable from fair resampling in most cases.
2362 The default value is None (no optimization).
2363 :returns: An :py:class:`~PIL.Image.Image` object.
2364 """
2366 if resample is None:
2367 resample = Resampling.BICUBIC
2368 elif resample not in (
2369 Resampling.NEAREST,
2370 Resampling.BILINEAR,
2371 Resampling.BICUBIC,
2372 Resampling.LANCZOS,
2373 Resampling.BOX,
2374 Resampling.HAMMING,
2375 ):
2376 msg = f"Unknown resampling filter ({resample})."
2378 filters = [
2379 f"{filter[1]} ({filter[0]})"
2380 for filter in (
2381 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
2382 (Resampling.LANCZOS, "Image.Resampling.LANCZOS"),
2383 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
2384 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
2385 (Resampling.BOX, "Image.Resampling.BOX"),
2386 (Resampling.HAMMING, "Image.Resampling.HAMMING"),
2387 )
2388 ]
2389 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
2390 raise ValueError(msg)
2392 if reducing_gap is not None and reducing_gap < 1.0:
2393 msg = "reducing_gap must be 1.0 or greater"
2394 raise ValueError(msg)
2396 if box is None:
2397 box = (0, 0) + self.size
2399 size = tuple(size)
2400 if self.size == size and box == (0, 0) + self.size:
2401 return self.copy()
2403 if self.mode in ("1", "P"):
2404 resample = Resampling.NEAREST
2406 if self.mode in ["LA", "RGBA"] and resample != Resampling.NEAREST:
2407 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2408 im = im.resize(size, resample, box)
2409 return im.convert(self.mode)
2411 self.load()
2413 if reducing_gap is not None and resample != Resampling.NEAREST:
2414 factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1
2415 factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1
2416 if factor_x > 1 or factor_y > 1:
2417 reduce_box = self._get_safe_box(size, cast(Resampling, resample), box)
2418 factor = (factor_x, factor_y)
2419 self = (
2420 self.reduce(factor, box=reduce_box)
2421 if callable(self.reduce)
2422 else Image.reduce(self, factor, box=reduce_box)
2423 )
2424 box = (
2425 (box[0] - reduce_box[0]) / factor_x,
2426 (box[1] - reduce_box[1]) / factor_y,
2427 (box[2] - reduce_box[0]) / factor_x,
2428 (box[3] - reduce_box[1]) / factor_y,
2429 )
2431 return self._new(self.im.resize(size, resample, box))
2433 def reduce(
2434 self,
2435 factor: int | tuple[int, int],
2436 box: tuple[int, int, int, int] | None = None,
2437 ) -> Image:
2438 """
2439 Returns a copy of the image reduced ``factor`` times.
2440 If the size of the image is not dividable by ``factor``,
2441 the resulting size will be rounded up.
2443 :param factor: A greater than 0 integer or tuple of two integers
2444 for width and height separately.
2445 :param box: An optional 4-tuple of ints providing
2446 the source image region to be reduced.
2447 The values must be within ``(0, 0, width, height)`` rectangle.
2448 If omitted or ``None``, the entire source is used.
2449 """
2450 if not isinstance(factor, (list, tuple)):
2451 factor = (factor, factor)
2453 if box is None:
2454 box = (0, 0) + self.size
2456 if factor == (1, 1) and box == (0, 0) + self.size:
2457 return self.copy()
2459 if self.mode in ["LA", "RGBA"]:
2460 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2461 im = im.reduce(factor, box)
2462 return im.convert(self.mode)
2464 self.load()
2466 return self._new(self.im.reduce(factor, box))
2468 def rotate(
2469 self,
2470 angle: float,
2471 resample: Resampling = Resampling.NEAREST,
2472 expand: int | bool = False,
2473 center: tuple[float, float] | None = None,
2474 translate: tuple[int, int] | None = None,
2475 fillcolor: float | tuple[float, ...] | str | None = None,
2476 ) -> Image:
2477 """
2478 Returns a rotated copy of this image. This method returns a
2479 copy of this image, rotated the given number of degrees counter
2480 clockwise around its centre.
2482 :param angle: In degrees counter clockwise.
2483 :param resample: An optional resampling filter. This can be
2484 one of :py:data:`Resampling.NEAREST` (use nearest neighbour),
2485 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2486 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2487 interpolation in a 4x4 environment). If omitted, or if the image has
2488 mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`.
2489 See :ref:`concept-filters`.
2490 :param expand: Optional expansion flag. If true, expands the output
2491 image to make it large enough to hold the entire rotated image.
2492 If false or omitted, make the output image the same size as the
2493 input image. Note that the expand flag assumes rotation around
2494 the center and no translation.
2495 :param center: Optional center of rotation (a 2-tuple). Origin is
2496 the upper left corner. Default is the center of the image.
2497 :param translate: An optional post-rotate translation (a 2-tuple).
2498 :param fillcolor: An optional color for area outside the rotated image.
2499 :returns: An :py:class:`~PIL.Image.Image` object.
2500 """
2502 angle = angle % 360.0
2504 # Fast paths regardless of filter, as long as we're not
2505 # translating or changing the center.
2506 if not (center or translate):
2507 if angle == 0:
2508 return self.copy()
2509 if angle == 180:
2510 return self.transpose(Transpose.ROTATE_180)
2511 if angle in (90, 270) and (expand or self.width == self.height):
2512 return self.transpose(
2513 Transpose.ROTATE_90 if angle == 90 else Transpose.ROTATE_270
2514 )
2516 # Calculate the affine matrix. Note that this is the reverse
2517 # transformation (from destination image to source) because we
2518 # want to interpolate the (discrete) destination pixel from
2519 # the local area around the (floating) source pixel.
2521 # The matrix we actually want (note that it operates from the right):
2522 # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx)
2523 # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
2524 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1)
2526 # The reverse matrix is thus:
2527 # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx)
2528 # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
2529 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1)
2531 # In any case, the final translation may be updated at the end to
2532 # compensate for the expand flag.
2534 w, h = self.size
2536 if translate is None:
2537 post_trans = (0, 0)
2538 else:
2539 post_trans = translate
2540 if center is None:
2541 center = (w / 2, h / 2)
2543 angle = -math.radians(angle)
2544 matrix = [
2545 round(math.cos(angle), 15),
2546 round(math.sin(angle), 15),
2547 0.0,
2548 round(-math.sin(angle), 15),
2549 round(math.cos(angle), 15),
2550 0.0,
2551 ]
2553 def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]:
2554 a, b, c, d, e, f = matrix
2555 return a * x + b * y + c, d * x + e * y + f
2557 matrix[2], matrix[5] = transform(
2558 -center[0] - post_trans[0], -center[1] - post_trans[1], matrix
2559 )
2560 matrix[2] += center[0]
2561 matrix[5] += center[1]
2563 if expand:
2564 # calculate output size
2565 xx = []
2566 yy = []
2567 for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
2568 transformed_x, transformed_y = transform(x, y, matrix)
2569 xx.append(transformed_x)
2570 yy.append(transformed_y)
2571 nw = math.ceil(max(xx)) - math.floor(min(xx))
2572 nh = math.ceil(max(yy)) - math.floor(min(yy))
2574 # We multiply a translation matrix from the right. Because of its
2575 # special form, this is the same as taking the image of the
2576 # translation vector as new translation vector.
2577 matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
2578 w, h = nw, nh
2580 return self.transform(
2581 (w, h), Transform.AFFINE, matrix, resample, fillcolor=fillcolor
2582 )
2584 def save(
2585 self, fp: StrOrBytesPath | IO[bytes], format: str | None = None, **params: Any
2586 ) -> None:
2587 """
2588 Saves this image under the given filename. If no format is
2589 specified, the format to use is determined from the filename
2590 extension, if possible.
2592 Keyword options can be used to provide additional instructions
2593 to the writer. If a writer doesn't recognise an option, it is
2594 silently ignored. The available options are described in the
2595 :doc:`image format documentation
2596 <../handbook/image-file-formats>` for each writer.
2598 You can use a file object instead of a filename. In this case,
2599 you must always specify the format. The file object must
2600 implement the ``seek``, ``tell``, and ``write``
2601 methods, and be opened in binary mode.
2603 :param fp: A filename (string), os.PathLike object or file object.
2604 :param format: Optional format override. If omitted, the
2605 format to use is determined from the filename extension.
2606 If a file object was used instead of a filename, this
2607 parameter should always be used.
2608 :param params: Extra parameters to the image writer. These can also be
2609 set on the image itself through ``encoderinfo``. This is useful when
2610 saving multiple images::
2612 # Saving XMP data to a single image
2613 from PIL import Image
2614 red = Image.new("RGB", (1, 1), "#f00")
2615 red.save("out.mpo", xmp=b"test")
2617 # Saving XMP data to the second frame of an image
2618 from PIL import Image
2619 black = Image.new("RGB", (1, 1))
2620 red = Image.new("RGB", (1, 1), "#f00")
2621 red.encoderinfo = {"xmp": b"test"}
2622 black.save("out.mpo", save_all=True, append_images=[red])
2623 :returns: None
2624 :exception ValueError: If the output format could not be determined
2625 from the file name. Use the format option to solve this.
2626 :exception OSError: If the file could not be written. The file
2627 may have been created, and may contain partial data.
2628 """
2630 filename: str | bytes = ""
2631 open_fp = False
2632 if is_path(fp):
2633 filename = os.fspath(fp)
2634 open_fp = True
2635 elif fp == sys.stdout:
2636 try:
2637 fp = sys.stdout.buffer
2638 except AttributeError:
2639 pass
2640 if not filename and hasattr(fp, "name") and is_path(fp.name):
2641 # only set the name for metadata purposes
2642 filename = os.fspath(fp.name)
2644 if format:
2645 preinit()
2646 else:
2647 filename_ext = os.path.splitext(filename)[1].lower()
2648 ext = (
2649 filename_ext.decode()
2650 if isinstance(filename_ext, bytes)
2651 else filename_ext
2652 )
2654 # Try importing only the plugin for this extension first
2655 if not _import_plugin_for_extension(ext):
2656 preinit()
2658 if ext not in EXTENSION:
2659 init()
2660 try:
2661 format = EXTENSION[ext]
2662 except KeyError as e:
2663 msg = f"unknown file extension: {ext}"
2664 raise ValueError(msg) from e
2666 from . import ImageFile
2668 # may mutate self!
2669 if isinstance(self, ImageFile.ImageFile) and os.path.abspath(
2670 filename
2671 ) == os.path.abspath(self.filename):
2672 self._ensure_mutable()
2673 else:
2674 self.load()
2676 save_all = params.pop("save_all", None)
2677 self._default_encoderinfo = params
2678 encoderinfo = getattr(self, "encoderinfo", {})
2679 self._attach_default_encoderinfo(self)
2680 self.encoderconfig: tuple[Any, ...] = ()
2682 if format.upper() not in SAVE:
2683 init()
2684 if save_all or (
2685 save_all is None
2686 and params.get("append_images")
2687 and format.upper() in SAVE_ALL
2688 ):
2689 save_handler = SAVE_ALL[format.upper()]
2690 else:
2691 save_handler = SAVE[format.upper()]
2693 created = False
2694 if open_fp:
2695 created = not os.path.exists(filename)
2696 if params.get("append", False):
2697 # Open also for reading ("+"), because TIFF save_all
2698 # writer needs to go back and edit the written data.
2699 fp = builtins.open(filename, "r+b")
2700 else:
2701 fp = builtins.open(filename, "w+b")
2702 else:
2703 fp = cast(IO[bytes], fp)
2705 try:
2706 save_handler(self, fp, filename)
2707 except Exception:
2708 if open_fp:
2709 fp.close()
2710 if created:
2711 try:
2712 os.remove(filename)
2713 except PermissionError:
2714 pass
2715 raise
2716 finally:
2717 self.encoderinfo = encoderinfo
2718 if open_fp:
2719 fp.close()
2721 def _attach_default_encoderinfo(self, im: Image) -> dict[str, Any]:
2722 encoderinfo = getattr(self, "encoderinfo", {})
2723 self.encoderinfo = {**im._default_encoderinfo, **encoderinfo}
2724 return encoderinfo
2726 def seek(self, frame: int) -> None:
2727 """
2728 Seeks to the given frame in this sequence file. If you seek
2729 beyond the end of the sequence, the method raises an
2730 ``EOFError`` exception. When a sequence file is opened, the
2731 library automatically seeks to frame 0.
2733 See :py:meth:`~PIL.Image.Image.tell`.
2735 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2736 number of available frames.
2738 :param frame: Frame number, starting at 0.
2739 :exception EOFError: If the call attempts to seek beyond the end
2740 of the sequence.
2741 """
2743 # overridden by file handlers
2744 if frame != 0:
2745 msg = "no more images in file"
2746 raise EOFError(msg)
2748 def show(self, title: str | None = None) -> None:
2749 """
2750 Displays this image. This method is mainly intended for debugging purposes.
2752 This method calls :py:func:`PIL.ImageShow.show` internally. You can use
2753 :py:func:`PIL.ImageShow.register` to override its default behaviour.
2755 The image is first saved to a temporary file. By default, it will be in
2756 PNG format.
2758 On Unix, the image is then opened using the **xdg-open**, **display**,
2759 **gm**, **eog** or **xv** utility, depending on which one can be found.
2761 On macOS, the image is opened with the native Preview application.
2763 On Windows, the image is opened with the standard PNG display utility.
2765 :param title: Optional title to use for the image window, where possible.
2766 """
2768 from . import ImageShow
2770 ImageShow.show(self, title)
2772 def split(self) -> tuple[Image, ...]:
2773 """
2774 Split this image into individual bands. This method returns a
2775 tuple of individual image bands from an image. For example,
2776 splitting an "RGB" image creates three new images each
2777 containing a copy of one of the original bands (red, green,
2778 blue).
2780 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel`
2781 method can be more convenient and faster.
2783 :returns: A tuple containing bands.
2784 """
2786 self.load()
2787 if self.im.bands == 1:
2788 return (self.copy(),)
2789 return tuple(map(self._new, self.im.split()))
2791 def getchannel(self, channel: int | str) -> Image:
2792 """
2793 Returns an image containing a single channel of the source image.
2795 :param channel: What channel to return. Could be index
2796 (0 for "R" channel of "RGB") or channel name
2797 ("A" for alpha channel of "RGBA").
2798 :returns: An image in "L" mode.
2800 .. versionadded:: 4.3.0
2801 """
2802 self.load()
2804 if isinstance(channel, str):
2805 try:
2806 channel = self.getbands().index(channel)
2807 except ValueError as e:
2808 msg = f'The image has no channel "{channel}"'
2809 raise ValueError(msg) from e
2811 return self._new(self.im.getband(channel))
2813 def tell(self) -> int:
2814 """
2815 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
2817 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2818 number of available frames.
2820 :returns: Frame number, starting with 0.
2821 """
2822 return 0
2824 def thumbnail(
2825 self,
2826 size: tuple[float, float],
2827 resample: Resampling = Resampling.BICUBIC,
2828 reducing_gap: float | None = 2.0,
2829 ) -> None:
2830 """
2831 Make this image into a thumbnail. This method modifies the
2832 image to contain a thumbnail version of itself, no larger than
2833 the given size. This method calculates an appropriate thumbnail
2834 size to preserve the aspect of the image, calls the
2835 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader
2836 (where applicable), and finally resizes the image.
2838 Note that this function modifies the :py:class:`~PIL.Image.Image`
2839 object in place. If you need to use the full resolution image as well,
2840 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
2841 image.
2843 :param size: The requested size in pixels, as a 2-tuple:
2844 (width, height).
2845 :param resample: Optional resampling filter. This can be one
2846 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2847 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2848 :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`.
2849 If omitted, it defaults to :py:data:`Resampling.BICUBIC`.
2850 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0).
2851 See: :ref:`concept-filters`.
2852 :param reducing_gap: Apply optimization by resizing the image
2853 in two steps. First, reducing the image by integer times
2854 using :py:meth:`~PIL.Image.Image.reduce` or
2855 :py:meth:`~PIL.Image.Image.draft` for JPEG images.
2856 Second, resizing using regular resampling. The last step
2857 changes size no less than by ``reducing_gap`` times.
2858 ``reducing_gap`` may be None (no first step is performed)
2859 or should be greater than 1.0. The bigger ``reducing_gap``,
2860 the closer the result to the fair resampling.
2861 The smaller ``reducing_gap``, the faster resizing.
2862 With ``reducing_gap`` greater or equal to 3.0, the result is
2863 indistinguishable from fair resampling in most cases.
2864 The default value is 2.0 (very close to fair resampling
2865 while still being faster in many cases).
2866 :returns: None
2867 """
2869 provided_size = tuple(map(math.floor, size))
2871 def preserve_aspect_ratio() -> tuple[int, int] | None:
2872 def round_aspect(number: float, key: Callable[[int], float]) -> int:
2873 return max(min(math.floor(number), math.ceil(number), key=key), 1)
2875 x, y = provided_size
2876 if x >= self.width and y >= self.height:
2877 return None
2879 aspect = self.width / self.height
2880 if x / y >= aspect:
2881 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y))
2882 else:
2883 y = round_aspect(
2884 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n)
2885 )
2886 return x, y
2888 preserved_size = preserve_aspect_ratio()
2889 if preserved_size is None:
2890 return
2891 final_size = preserved_size
2893 box = None
2894 if reducing_gap is not None:
2895 res = self.draft(
2896 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
2897 )
2898 if res is not None:
2899 box = res[1]
2901 if self.size != final_size:
2902 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap)
2904 self.im = im.im
2905 self._size = final_size
2906 self._mode = self.im.mode
2908 self.readonly = 0
2910 # FIXME: the different transform methods need further explanation
2911 # instead of bloating the method docs, add a separate chapter.
2912 def transform(
2913 self,
2914 size: tuple[int, int],
2915 method: Transform | ImageTransformHandler | SupportsGetData,
2916 data: Sequence[Any] | None = None,
2917 resample: int = Resampling.NEAREST,
2918 fill: int = 1,
2919 fillcolor: float | tuple[float, ...] | str | None = None,
2920 ) -> Image:
2921 """
2922 Transforms this image. This method creates a new image with the
2923 given size, and the same mode as the original, and copies data
2924 to the new image using the given transform.
2926 :param size: The output size in pixels, as a 2-tuple:
2927 (width, height).
2928 :param method: The transformation method. This is one of
2929 :py:data:`Transform.EXTENT` (cut out a rectangular subregion),
2930 :py:data:`Transform.AFFINE` (affine transform),
2931 :py:data:`Transform.PERSPECTIVE` (perspective transform),
2932 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or
2933 :py:data:`Transform.MESH` (map a number of source quadrilaterals
2934 in one operation).
2936 It may also be an :py:class:`~PIL.Image.ImageTransformHandler`
2937 object::
2939 class Example(Image.ImageTransformHandler):
2940 def transform(self, size, data, resample, fill=1):
2941 # Return result
2943 Implementations of :py:class:`~PIL.Image.ImageTransformHandler`
2944 for some of the :py:class:`Transform` methods are provided
2945 in :py:mod:`~PIL.ImageTransform`.
2947 It may also be an object with a ``method.getdata`` method
2948 that returns a tuple supplying new ``method`` and ``data`` values::
2950 class Example:
2951 def getdata(self):
2952 method = Image.Transform.EXTENT
2953 data = (0, 0, 100, 100)
2954 return method, data
2955 :param data: Extra data to the transformation method.
2956 :param resample: Optional resampling filter. It can be one of
2957 :py:data:`Resampling.NEAREST` (use nearest neighbour),
2958 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2959 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2960 interpolation in a 4x4 environment). If omitted, or if the image
2961 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`.
2962 See: :ref:`concept-filters`.
2963 :param fill: If ``method`` is an
2964 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of
2965 the arguments passed to it. Otherwise, it is unused.
2966 :param fillcolor: Optional fill color for the area outside the
2967 transform in the output image.
2968 :returns: An :py:class:`~PIL.Image.Image` object.
2969 """
2971 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST:
2972 return (
2973 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2974 .transform(size, method, data, resample, fill, fillcolor)
2975 .convert(self.mode)
2976 )
2978 if isinstance(method, ImageTransformHandler):
2979 return method.transform(size, self, resample=resample, fill=fill)
2981 if hasattr(method, "getdata"):
2982 # compatibility w. old-style transform objects
2983 method, data = method.getdata()
2985 if data is None:
2986 msg = "missing method data"
2987 raise ValueError(msg)
2989 im = new(self.mode, size, fillcolor)
2990 if self.mode == "P" and self.palette:
2991 im.palette = self.palette.copy()
2992 im.info = self.info.copy()
2993 if method == Transform.MESH:
2994 # list of quads
2995 for box, quad in data:
2996 im.__transformer(
2997 box, self, Transform.QUAD, quad, resample, fillcolor is None
2998 )
2999 else:
3000 im.__transformer(
3001 (0, 0) + size, self, method, data, resample, fillcolor is None
3002 )
3004 return im
3006 def __transformer(
3007 self,
3008 box: tuple[int, int, int, int],
3009 image: Image,
3010 method: Transform,
3011 data: Sequence[float],
3012 resample: int = Resampling.NEAREST,
3013 fill: bool = True,
3014 ) -> None:
3015 w = box[2] - box[0]
3016 h = box[3] - box[1]
3018 if method == Transform.AFFINE:
3019 data = data[:6]
3021 elif method == Transform.EXTENT:
3022 # convert extent to an affine transform
3023 x0, y0, x1, y1 = data
3024 xs = (x1 - x0) / w
3025 ys = (y1 - y0) / h
3026 method = Transform.AFFINE
3027 data = (xs, 0, x0, 0, ys, y0)
3029 elif method == Transform.PERSPECTIVE:
3030 data = data[:8]
3032 elif method == Transform.QUAD:
3033 # quadrilateral warp. data specifies the four corners
3034 # given as NW, SW, SE, and NE.
3035 nw = data[:2]
3036 sw = data[2:4]
3037 se = data[4:6]
3038 ne = data[6:8]
3039 x0, y0 = nw
3040 As = 1.0 / w
3041 At = 1.0 / h
3042 data = (
3043 x0,
3044 (ne[0] - x0) * As,
3045 (sw[0] - x0) * At,
3046 (se[0] - sw[0] - ne[0] + x0) * As * At,
3047 y0,
3048 (ne[1] - y0) * As,
3049 (sw[1] - y0) * At,
3050 (se[1] - sw[1] - ne[1] + y0) * As * At,
3051 )
3053 else:
3054 msg = "unknown transformation method"
3055 raise ValueError(msg)
3057 if resample not in (
3058 Resampling.NEAREST,
3059 Resampling.BILINEAR,
3060 Resampling.BICUBIC,
3061 ):
3062 if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS):
3063 unusable: dict[int, str] = {
3064 Resampling.BOX: "Image.Resampling.BOX",
3065 Resampling.HAMMING: "Image.Resampling.HAMMING",
3066 Resampling.LANCZOS: "Image.Resampling.LANCZOS",
3067 }
3068 msg = unusable[resample] + f" ({resample}) cannot be used."
3069 else:
3070 msg = f"Unknown resampling filter ({resample})."
3072 filters = [
3073 f"{filter[1]} ({filter[0]})"
3074 for filter in (
3075 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
3076 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
3077 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
3078 )
3079 ]
3080 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
3081 raise ValueError(msg)
3083 image.load()
3085 self.load()
3087 if image.mode in ("1", "P"):
3088 resample = Resampling.NEAREST
3090 self.im.transform(box, image.im, method, data, resample, fill)
3092 def transpose(self, method: Transpose) -> Image:
3093 """
3094 Transpose image (flip or rotate in 90 degree steps)
3096 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`,
3097 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`,
3098 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`,
3099 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`.
3100 :returns: Returns a flipped or rotated copy of this image.
3101 """
3103 self.load()
3104 return self._new(self.im.transpose(method))
3106 def effect_spread(self, distance: int) -> Image:
3107 """
3108 Randomly spread pixels in an image.
3110 :param distance: Distance to spread pixels.
3111 """
3112 self.load()
3113 return self._new(self.im.effect_spread(distance))
3115 def toqimage(self) -> ImageQt.ImageQt:
3116 """Returns a QImage copy of this image"""
3117 from . import ImageQt
3119 if not ImageQt.qt_is_installed:
3120 msg = "Qt bindings are not installed"
3121 raise ImportError(msg)
3122 return ImageQt.toqimage(self)
3124 def toqpixmap(self) -> ImageQt.QPixmap:
3125 """Returns a QPixmap copy of this image"""
3126 from . import ImageQt
3128 if not ImageQt.qt_is_installed:
3129 msg = "Qt bindings are not installed"
3130 raise ImportError(msg)
3131 return ImageQt.toqpixmap(self)
3134# --------------------------------------------------------------------
3135# Abstract handlers.
3138class ImagePointHandler(abc.ABC):
3139 """
3140 Used as a mixin by point transforms
3141 (for use with :py:meth:`~PIL.Image.Image.point`)
3142 """
3144 @abc.abstractmethod
3145 def point(self, im: Image) -> Image:
3146 pass
3149class ImageTransformHandler(abc.ABC):
3150 """
3151 Used as a mixin by geometry transforms
3152 (for use with :py:meth:`~PIL.Image.Image.transform`)
3153 """
3155 @abc.abstractmethod
3156 def transform(
3157 self,
3158 size: tuple[int, int],
3159 image: Image,
3160 **options: Any,
3161 ) -> Image:
3162 pass
3165# --------------------------------------------------------------------
3166# Factories
3169def _check_size(size: Any) -> None:
3170 """
3171 Common check to enforce type and sanity check on size tuples
3173 :param size: Should be a 2 tuple of (width, height)
3174 :returns: None, or raises a ValueError
3175 """
3177 if not isinstance(size, (list, tuple)):
3178 msg = "Size must be a list or tuple"
3179 raise ValueError(msg)
3180 if len(size) != 2:
3181 msg = "Size must be a sequence of length 2"
3182 raise ValueError(msg)
3183 if size[0] < 0 or size[1] < 0:
3184 msg = "Width and height must be >= 0"
3185 raise ValueError(msg)
3188def new(
3189 mode: str,
3190 size: tuple[int, int] | list[int],
3191 color: float | tuple[float, ...] | str | None = 0,
3192) -> Image:
3193 """
3194 Creates a new image with the given mode and size.
3196 :param mode: The mode to use for the new image. See:
3197 :ref:`concept-modes`.
3198 :param size: A 2-tuple, containing (width, height) in pixels.
3199 :param color: What color to use for the image. Default is black. If given,
3200 this should be a single integer or floating point value for single-band
3201 modes, and a tuple for multi-band modes (one value per band). When
3202 creating RGB or HSV images, you can also use color strings as supported
3203 by the ImageColor module. See :ref:`colors` for more information. If the
3204 color is None, the image is not initialised.
3205 :returns: An :py:class:`~PIL.Image.Image` object.
3206 """
3208 _check_size(size)
3210 if color is None:
3211 # don't initialize
3212 return Image()._new(core.new(mode, size))
3214 if isinstance(color, str):
3215 # css3-style specifier
3217 from . import ImageColor
3219 color = ImageColor.getcolor(color, mode)
3221 im = Image()
3222 if (
3223 mode == "P"
3224 and isinstance(color, (list, tuple))
3225 and all(isinstance(i, int) for i in color)
3226 ):
3227 color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color))
3228 if len(color_ints) == 3 or len(color_ints) == 4:
3229 # RGB or RGBA value for a P image
3230 from . import ImagePalette
3232 im.palette = ImagePalette.ImagePalette()
3233 color = im.palette.getcolor(color_ints)
3234 return im._new(core.fill(mode, size, color))
3237def frombytes(
3238 mode: str,
3239 size: tuple[int, int],
3240 data: bytes | bytearray | SupportsArrayInterface,
3241 decoder_name: str = "raw",
3242 *args: Any,
3243) -> Image:
3244 """
3245 Creates a copy of an image memory from pixel data in a buffer.
3247 In its simplest form, this function takes three arguments
3248 (mode, size, and unpacked pixel data).
3250 You can also use any pixel decoder supported by PIL. For more
3251 information on available decoders, see the section
3252 :ref:`Writing Your Own File Codec <file-codecs>`.
3254 Note that this function decodes pixel data only, not entire images.
3255 If you have an entire image in a string, wrap it in a
3256 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load
3257 it.
3259 :param mode: The image mode. See: :ref:`concept-modes`.
3260 :param size: The image size.
3261 :param data: A byte buffer containing raw data for the given mode.
3262 :param decoder_name: What decoder to use.
3263 :param args: Additional parameters for the given decoder.
3264 :returns: An :py:class:`~PIL.Image.Image` object.
3265 """
3267 _check_size(size)
3269 im = new(mode, size)
3270 if im.width != 0 and im.height != 0:
3271 decoder_args: Any = args
3272 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
3273 # may pass tuple instead of argument list
3274 decoder_args = decoder_args[0]
3276 if decoder_name == "raw" and decoder_args == ():
3277 decoder_args = mode
3279 im.frombytes(data, decoder_name, decoder_args)
3280 return im
3283def frombuffer(
3284 mode: str,
3285 size: tuple[int, int],
3286 data: bytes | SupportsArrayInterface,
3287 decoder_name: str = "raw",
3288 *args: Any,
3289) -> Image:
3290 """
3291 Creates an image memory referencing pixel data in a byte buffer.
3293 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data
3294 in the byte buffer, where possible. This means that changes to the
3295 original buffer object are reflected in this image). Not all modes can
3296 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK".
3298 Note that this function decodes pixel data only, not entire images.
3299 If you have an entire image file in a string, wrap it in a
3300 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it.
3302 The default parameters used for the "raw" decoder differs from that used for
3303 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a
3304 future release. The current release issues a warning if you do this; to disable
3305 the warning, you should provide the full set of parameters. See below for details.
3307 :param mode: The image mode. See: :ref:`concept-modes`.
3308 :param size: The image size.
3309 :param data: A bytes or other buffer object containing raw
3310 data for the given mode.
3311 :param decoder_name: What decoder to use.
3312 :param args: Additional parameters for the given decoder. For the
3313 default encoder ("raw"), it's recommended that you provide the
3314 full set of parameters::
3316 frombuffer(mode, size, data, "raw", mode, 0, 1)
3318 :returns: An :py:class:`~PIL.Image.Image` object.
3320 .. versionadded:: 1.1.4
3321 """
3323 _check_size(size)
3325 # may pass tuple instead of argument list
3326 if len(args) == 1 and isinstance(args[0], tuple):
3327 args = args[0]
3329 if decoder_name == "raw":
3330 if args == ():
3331 args = mode, 0, 1
3332 if args[0] in _MAPMODES:
3333 im = new(mode, (0, 0))
3334 im = im._new(core.map_buffer(data, size, decoder_name, 0, args))
3335 if mode == "P":
3336 from . import ImagePalette
3338 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB"))
3339 im.readonly = 1
3340 return im
3342 return frombytes(mode, size, data, decoder_name, args)
3345class SupportsArrayInterface(Protocol):
3346 """
3347 An object that has an ``__array_interface__`` dictionary.
3348 """
3350 @property
3351 def __array_interface__(self) -> dict[str, Any]:
3352 raise NotImplementedError()
3355class SupportsArrowArrayInterface(Protocol):
3356 """
3357 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c
3358 data interface.
3359 """
3361 def __arrow_c_array__(
3362 self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037
3363 ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037
3364 raise NotImplementedError()
3367def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
3368 """
3369 Creates an image memory from an object exporting the array interface
3370 (using the buffer protocol)::
3372 from PIL import Image
3373 import numpy as np
3374 a = np.zeros((5, 5))
3375 im = Image.fromarray(a)
3377 If ``obj`` is not contiguous, then the ``tobytes`` method is called
3378 and :py:func:`~PIL.Image.frombuffer` is used.
3380 In the case of NumPy, be aware that Pillow modes do not always correspond
3381 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels,
3382 32-bit signed integer pixels, and 32-bit floating point pixels.
3384 Pillow images can also be converted to arrays::
3386 from PIL import Image
3387 import numpy as np
3388 im = Image.open("hopper.jpg")
3389 a = np.asarray(im)
3391 When converting Pillow images to arrays however, only pixel values are
3392 transferred. This means that P and PA mode images will lose their palette.
3394 :param obj: Object with array interface
3395 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not
3396 contain information about palettes or color spaces, this can be used to place
3397 grayscale L mode data within a P mode image, or read RGB data as YCbCr for
3398 example.
3400 See: :ref:`concept-modes` for general information about modes.
3401 :returns: An image object.
3403 .. versionadded:: 1.1.6
3404 """
3405 arr = obj.__array_interface__
3406 shape = arr["shape"]
3407 ndim = len(shape)
3408 strides = arr.get("strides", None)
3409 try:
3410 typekey = (1, 1) + shape[2:], arr["typestr"]
3411 except KeyError as e:
3412 if mode is not None:
3413 typekey = None
3414 color_modes: list[str] = []
3415 else:
3416 msg = "Cannot handle this data type"
3417 raise TypeError(msg) from e
3418 if typekey is not None:
3419 try:
3420 typemode, rawmode, color_modes = _fromarray_typemap[typekey]
3421 except KeyError as e:
3422 typekey_shape, typestr = typekey
3423 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}"
3424 raise TypeError(msg) from e
3425 if mode is not None:
3426 if mode != typemode and mode not in color_modes:
3427 deprecate("'mode' parameter for changing data types", 13)
3428 rawmode = mode
3429 else:
3430 mode = typemode
3431 if mode in ["1", "L", "I", "P", "F"]:
3432 ndmax = 2
3433 elif mode == "RGB":
3434 ndmax = 3
3435 else:
3436 ndmax = 4
3437 if ndim > ndmax:
3438 msg = f"Too many dimensions: {ndim} > {ndmax}."
3439 raise ValueError(msg)
3441 size = 1 if ndim == 1 else shape[1], shape[0]
3442 if strides is not None:
3443 if hasattr(obj, "tobytes"):
3444 obj = obj.tobytes()
3445 elif hasattr(obj, "tostring"):
3446 obj = obj.tostring()
3447 else:
3448 msg = "'strides' requires either tobytes() or tostring()"
3449 raise ValueError(msg)
3451 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
3454def fromarrow(
3455 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int]
3456) -> Image:
3457 """Creates an image with zero-copy shared memory from an object exporting
3458 the arrow_c_array interface protocol::
3460 from PIL import Image
3461 import pyarrow as pa
3462 arr = pa.array([0]*(5*5*4), type=pa.uint8())
3463 im = Image.fromarrow(arr, 'RGBA', (5, 5))
3465 If the data representation of the ``obj`` is not compatible with
3466 Pillow internal storage, a ValueError is raised.
3468 Pillow images can also be converted to Arrow objects::
3470 from PIL import Image
3471 import pyarrow as pa
3472 im = Image.open('hopper.jpg')
3473 arr = pa.array(im)
3475 As with array support, when converting Pillow images to arrays,
3476 only pixel values are transferred. This means that P and PA mode
3477 images will lose their palette.
3479 :param obj: Object with an arrow_c_array interface
3480 :param mode: Image mode.
3481 :param size: Image size. This must match the storage of the arrow object.
3482 :returns: An Image object
3484 Note that according to the Arrow spec, both the producer and the
3485 consumer should consider the exported array to be immutable, as
3486 unsynchronized updates will potentially cause inconsistent data.
3488 See: :ref:`arrow-support` for more detailed information
3490 .. versionadded:: 11.2.1
3492 """
3493 if not hasattr(obj, "__arrow_c_array__"):
3494 msg = "arrow_c_array interface not found"
3495 raise ValueError(msg)
3497 schema_capsule, array_capsule = obj.__arrow_c_array__()
3498 _im = core.new_arrow(mode, size, schema_capsule, array_capsule)
3499 if _im:
3500 return Image()._new(_im)
3502 msg = "new_arrow returned None without an exception"
3503 raise ValueError(msg)
3506def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile:
3507 """Creates an image instance from a QImage image"""
3508 from . import ImageQt
3510 if not ImageQt.qt_is_installed:
3511 msg = "Qt bindings are not installed"
3512 raise ImportError(msg)
3513 return ImageQt.fromqimage(im)
3516def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile:
3517 """Creates an image instance from a QPixmap image"""
3518 from . import ImageQt
3520 if not ImageQt.qt_is_installed:
3521 msg = "Qt bindings are not installed"
3522 raise ImportError(msg)
3523 return ImageQt.fromqpixmap(im)
3526_fromarray_typemap = {
3527 # (shape, typestr) => mode, rawmode, color modes
3528 # first two members of shape are set to one
3529 ((1, 1), "|b1"): ("1", "1;8", []),
3530 ((1, 1), "|u1"): ("L", "L", ["P"]),
3531 ((1, 1), "|i1"): ("I", "I;8", []),
3532 ((1, 1), "<u2"): ("I", "I;16", []),
3533 ((1, 1), ">u2"): ("I", "I;16B", []),
3534 ((1, 1), "<i2"): ("I", "I;16S", []),
3535 ((1, 1), ">i2"): ("I", "I;16BS", []),
3536 ((1, 1), "<u4"): ("I", "I;32", []),
3537 ((1, 1), ">u4"): ("I", "I;32B", []),
3538 ((1, 1), "<i4"): ("I", "I;32S", []),
3539 ((1, 1), ">i4"): ("I", "I;32BS", []),
3540 ((1, 1), "<f4"): ("F", "F;32F", []),
3541 ((1, 1), ">f4"): ("F", "F;32BF", []),
3542 ((1, 1), "<f8"): ("F", "F;64F", []),
3543 ((1, 1), ">f8"): ("F", "F;64BF", []),
3544 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]),
3545 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]),
3546 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]),
3547 # shortcuts:
3548 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []),
3549 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []),
3550}
3553def _decompression_bomb_check(size: tuple[int, int]) -> None:
3554 if MAX_IMAGE_PIXELS is None:
3555 return
3557 pixels = max(1, size[0]) * max(1, size[1])
3559 if pixels > 2 * MAX_IMAGE_PIXELS:
3560 msg = (
3561 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} "
3562 "pixels, could be decompression bomb DOS attack."
3563 )
3564 raise DecompressionBombError(msg)
3566 if pixels > MAX_IMAGE_PIXELS:
3567 warnings.warn(
3568 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, "
3569 "could be decompression bomb DOS attack.",
3570 DecompressionBombWarning,
3571 )
3574def open(
3575 fp: StrOrBytesPath | IO[bytes],
3576 mode: Literal["r"] = "r",
3577 formats: list[str] | tuple[str, ...] | None = None,
3578) -> ImageFile.ImageFile:
3579 """
3580 Opens and identifies the given image file.
3582 This is a lazy operation; this function identifies the file, but
3583 the file remains open and the actual image data is not read from
3584 the file until you try to process the data (or call the
3585 :py:meth:`~PIL.Image.Image.load` method). See
3586 :py:func:`~PIL.Image.new`. See :ref:`file-handling`.
3588 :param fp: A filename (string), os.PathLike object or a file object.
3589 The file object must implement ``file.read``,
3590 ``file.seek``, and ``file.tell`` methods,
3591 and be opened in binary mode. The file object will also seek to zero
3592 before reading.
3593 :param mode: The mode. If given, this argument must be "r".
3594 :param formats: A list or tuple of formats to attempt to load the file in.
3595 This can be used to restrict the set of formats checked.
3596 Pass ``None`` to try all supported formats. You can print the set of
3597 available formats by running ``python3 -m PIL`` or using
3598 the :py:func:`PIL.features.pilinfo` function.
3599 :returns: An :py:class:`~PIL.Image.Image` object.
3600 :exception FileNotFoundError: If the file cannot be found.
3601 :exception PIL.UnidentifiedImageError: If the image cannot be opened and
3602 identified.
3603 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO``
3604 instance is used for ``fp``.
3605 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple.
3606 """
3608 if mode != "r":
3609 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
3610 raise ValueError(msg)
3611 elif isinstance(fp, io.StringIO):
3612 msg = ( # type: ignore[unreachable]
3613 "StringIO cannot be used to open an image. "
3614 "Binary data must be used instead."
3615 )
3616 raise ValueError(msg)
3618 if formats is None:
3619 formats = ID
3620 elif not isinstance(formats, (list, tuple)):
3621 msg = "formats must be a list or tuple" # type: ignore[unreachable]
3622 raise TypeError(msg)
3624 exclusive_fp = False
3625 filename: str | bytes = ""
3626 if is_path(fp):
3627 filename = os.fspath(fp)
3628 fp = builtins.open(filename, "rb")
3629 exclusive_fp = True
3630 else:
3631 fp = cast(IO[bytes], fp)
3633 try:
3634 fp.seek(0)
3635 except (AttributeError, io.UnsupportedOperation):
3636 fp = io.BytesIO(fp.read())
3637 exclusive_fp = True
3639 prefix = fp.read(16)
3641 # Try to import just the plugin needed for this file extension
3642 # before falling back to preinit() which imports common plugins
3643 ext = os.path.splitext(filename)[1] if filename else ""
3644 if not _import_plugin_for_extension(ext):
3645 preinit()
3647 warning_messages: list[str] = []
3649 def _open_core(
3650 fp: IO[bytes],
3651 filename: str | bytes,
3652 prefix: bytes,
3653 formats: list[str] | tuple[str, ...],
3654 ) -> ImageFile.ImageFile | None:
3655 for i in formats:
3656 i = i.upper()
3657 if i not in OPEN:
3658 init()
3659 try:
3660 factory, accept = OPEN[i]
3661 result = not accept or accept(prefix)
3662 if isinstance(result, str):
3663 warning_messages.append(result)
3664 elif result:
3665 fp.seek(0)
3666 im = factory(fp, filename)
3667 _decompression_bomb_check(im.size)
3668 return im
3669 except (SyntaxError, IndexError, TypeError, struct.error) as e:
3670 if WARN_POSSIBLE_FORMATS:
3671 warning_messages.append(i + " opening failed. " + str(e))
3672 except BaseException:
3673 if exclusive_fp:
3674 fp.close()
3675 raise
3676 return None
3678 im = _open_core(fp, filename, prefix, formats)
3680 if im is None and formats is ID:
3681 # Try preinit (few common plugins) then init (all plugins)
3682 for loader in (preinit, init):
3683 checked_formats = ID.copy()
3684 loader()
3685 if formats != checked_formats:
3686 im = _open_core(
3687 fp,
3688 filename,
3689 prefix,
3690 tuple(f for f in formats if f not in checked_formats),
3691 )
3692 if im is not None:
3693 break
3695 if im:
3696 im._exclusive_fp = exclusive_fp
3697 return im
3699 if exclusive_fp:
3700 fp.close()
3701 for message in warning_messages:
3702 warnings.warn(message)
3703 msg = "cannot identify image file %r" % (filename if filename else fp)
3704 raise UnidentifiedImageError(msg)
3707#
3708# Image processing.
3711def alpha_composite(im1: Image, im2: Image) -> Image:
3712 """
3713 Alpha composite im2 over im1.
3715 :param im1: The first image. Must have mode RGBA or LA.
3716 :param im2: The second image. Must have the same mode and size as the first image.
3717 :returns: An :py:class:`~PIL.Image.Image` object.
3718 """
3720 im1.load()
3721 im2.load()
3722 return im1._new(core.alpha_composite(im1.im, im2.im))
3725def blend(im1: Image, im2: Image, alpha: float) -> Image:
3726 """
3727 Creates a new image by interpolating between two input images, using
3728 a constant alpha::
3730 out = image1 * (1.0 - alpha) + image2 * alpha
3732 :param im1: The first image.
3733 :param im2: The second image. Must have the same mode and size as
3734 the first image.
3735 :param alpha: The interpolation alpha factor. If alpha is 0.0, a
3736 copy of the first image is returned. If alpha is 1.0, a copy of
3737 the second image is returned. There are no restrictions on the
3738 alpha value. If necessary, the result is clipped to fit into
3739 the allowed output range.
3740 :returns: An :py:class:`~PIL.Image.Image` object.
3741 """
3743 im1.load()
3744 im2.load()
3745 return im1._new(core.blend(im1.im, im2.im, alpha))
3748def composite(image1: Image, image2: Image, mask: Image) -> Image:
3749 """
3750 Create composite image by blending images using a transparency mask.
3752 :param image1: The first image.
3753 :param image2: The second image. Must have the same mode and
3754 size as the first image.
3755 :param mask: A mask image. This image can have mode
3756 "1", "L", or "RGBA", and must have the same size as the
3757 other two images.
3758 """
3760 image = image2.copy()
3761 image.paste(image1, None, mask)
3762 return image
3765def eval(image: Image, *args: Callable[[int], float]) -> Image:
3766 """
3767 Applies the function (which should take one argument) to each pixel
3768 in the given image. If the image has more than one band, the same
3769 function is applied to each band. Note that the function is
3770 evaluated once for each possible pixel value, so you cannot use
3771 random components or other generators.
3773 :param image: The input image.
3774 :param function: A function object, taking one integer argument.
3775 :returns: An :py:class:`~PIL.Image.Image` object.
3776 """
3778 return image.point(args[0])
3781def merge(mode: str, bands: Sequence[Image]) -> Image:
3782 """
3783 Merge a set of single band images into a new multiband image.
3785 :param mode: The mode to use for the output image. See:
3786 :ref:`concept-modes`.
3787 :param bands: A sequence containing one single-band image for
3788 each band in the output image. All bands must have the
3789 same size.
3790 :returns: An :py:class:`~PIL.Image.Image` object.
3791 """
3793 if getmodebands(mode) != len(bands) or "*" in mode:
3794 msg = "wrong number of bands"
3795 raise ValueError(msg)
3796 for band in bands[1:]:
3797 if band.mode != getmodetype(mode):
3798 msg = "mode mismatch"
3799 raise ValueError(msg)
3800 if band.size != bands[0].size:
3801 msg = "size mismatch"
3802 raise ValueError(msg)
3803 for band in bands:
3804 band.load()
3805 return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
3808# --------------------------------------------------------------------
3809# Plugin registry
3812def register_open(
3813 id: str,
3814 factory: (
3815 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile]
3816 | type[ImageFile.ImageFile]
3817 ),
3818 accept: Callable[[bytes], bool | str] | None = None,
3819) -> None:
3820 """
3821 Register an image file plugin. This function should not be used
3822 in application code.
3824 :param id: An image format identifier.
3825 :param factory: An image file factory method.
3826 :param accept: An optional function that can be used to quickly
3827 reject images having another format.
3828 """
3829 id = id.upper()
3830 if id not in ID:
3831 ID.append(id)
3832 OPEN[id] = factory, accept
3835def register_mime(id: str, mimetype: str) -> None:
3836 """
3837 Registers an image MIME type by populating ``Image.MIME``. This function
3838 should not be used in application code.
3840 ``Image.MIME`` provides a mapping from image format identifiers to mime
3841 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can
3842 provide a different result for specific images.
3844 :param id: An image format identifier.
3845 :param mimetype: The image MIME type for this format.
3846 """
3847 MIME[id.upper()] = mimetype
3850def register_save(
3851 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3852) -> None:
3853 """
3854 Registers an image save function. This function should not be
3855 used in application code.
3857 :param id: An image format identifier.
3858 :param driver: A function to save images in this format.
3859 """
3860 SAVE[id.upper()] = driver
3863def register_save_all(
3864 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3865) -> None:
3866 """
3867 Registers an image function to save all the frames
3868 of a multiframe format. This function should not be
3869 used in application code.
3871 :param id: An image format identifier.
3872 :param driver: A function to save images in this format.
3873 """
3874 SAVE_ALL[id.upper()] = driver
3877def register_extension(id: str, extension: str) -> None:
3878 """
3879 Registers an image extension. This function should not be
3880 used in application code.
3882 :param id: An image format identifier.
3883 :param extension: An extension used for this format.
3884 """
3885 EXTENSION[extension.lower()] = id.upper()
3888def register_extensions(id: str, extensions: list[str]) -> None:
3889 """
3890 Registers image extensions. This function should not be
3891 used in application code.
3893 :param id: An image format identifier.
3894 :param extensions: A list of extensions used for this format.
3895 """
3896 for extension in extensions:
3897 register_extension(id, extension)
3900def registered_extensions() -> dict[str, str]:
3901 """
3902 Returns a dictionary containing all file extensions belonging
3903 to registered plugins
3904 """
3905 init()
3906 return EXTENSION
3909def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None:
3910 """
3911 Registers an image decoder. This function should not be
3912 used in application code.
3914 :param name: The name of the decoder
3915 :param decoder: An ImageFile.PyDecoder object
3917 .. versionadded:: 4.1.0
3918 """
3919 DECODERS[name] = decoder
3922def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None:
3923 """
3924 Registers an image encoder. This function should not be
3925 used in application code.
3927 :param name: The name of the encoder
3928 :param encoder: An ImageFile.PyEncoder object
3930 .. versionadded:: 4.1.0
3931 """
3932 ENCODERS[name] = encoder
3935# --------------------------------------------------------------------
3936# Simple display support.
3939def _show(image: Image, **options: Any) -> None:
3940 from . import ImageShow
3942 deprecate("Image._show", 13, "ImageShow.show")
3943 ImageShow.show(image, **options)
3946# --------------------------------------------------------------------
3947# Effects
3950def effect_mandelbrot(
3951 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int
3952) -> Image:
3953 """
3954 Generate a Mandelbrot set covering the given extent.
3956 :param size: The requested size in pixels, as a 2-tuple:
3957 (width, height).
3958 :param extent: The extent to cover, as a 4-tuple:
3959 (x0, y0, x1, y1).
3960 :param quality: Quality.
3961 """
3962 return Image()._new(core.effect_mandelbrot(size, extent, quality))
3965def effect_noise(size: tuple[int, int], sigma: float) -> Image:
3966 """
3967 Generate Gaussian noise centered around 128.
3969 :param size: The requested size in pixels, as a 2-tuple:
3970 (width, height).
3971 :param sigma: Standard deviation of noise.
3972 """
3973 return Image()._new(core.effect_noise(size, sigma))
3976def linear_gradient(mode: str) -> Image:
3977 """
3978 Generate 256x256 linear gradient from black to white, top to bottom.
3980 :param mode: Input mode.
3981 """
3982 return Image()._new(core.linear_gradient(mode))
3985def radial_gradient(mode: str) -> Image:
3986 """
3987 Generate 256x256 radial gradient from black to white, centre to edge.
3989 :param mode: Input mode.
3990 """
3991 return Image()._new(core.radial_gradient(mode))
3994# --------------------------------------------------------------------
3995# Resources
3998def _apply_env_variables(env: dict[str, str] | None = None) -> None:
3999 env_dict = env if env is not None else os.environ
4001 for var_name, setter in [
4002 ("PILLOW_ALIGNMENT", core.set_alignment),
4003 ("PILLOW_BLOCK_SIZE", core.set_block_size),
4004 ("PILLOW_BLOCKS_MAX", core.set_blocks_max),
4005 ]:
4006 if var_name not in env_dict:
4007 continue
4009 var = env_dict[var_name].lower()
4011 units = 1
4012 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]:
4013 if var.endswith(postfix):
4014 units = mul
4015 var = var[: -len(postfix)]
4017 try:
4018 var_int = int(var) * units
4019 except ValueError:
4020 warnings.warn(f"{var_name} is not int")
4021 continue
4023 try:
4024 setter(var_int)
4025 except ValueError as e:
4026 warnings.warn(f"{var_name}: {e}")
4029_apply_env_variables()
4030atexit.register(core.clear_cache)
4033if TYPE_CHECKING:
4034 _ExifBase = MutableMapping[int, Any]
4035else:
4036 _ExifBase = MutableMapping
4039class Exif(_ExifBase):
4040 """
4041 This class provides read and write access to EXIF image data::
4043 from PIL import Image
4044 im = Image.open("exif.png")
4045 exif = im.getexif() # Returns an instance of this class
4047 Information can be read and written, iterated over or deleted::
4049 print(exif[274]) # 1
4050 exif[274] = 2
4051 for k, v in exif.items():
4052 print("Tag", k, "Value", v) # Tag 274 Value 2
4053 del exif[274]
4055 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd`
4056 returns a dictionary::
4058 from PIL import ExifTags
4059 im = Image.open("exif_gps.jpg")
4060 exif = im.getexif()
4061 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo)
4062 print(gps_ifd)
4064 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``,
4065 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``.
4067 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data::
4069 print(exif[ExifTags.Base.Software]) # PIL
4070 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99
4071 """
4073 endian: str | None = None
4074 bigtiff = False
4075 _loaded = False
4077 def __init__(self) -> None:
4078 self._data: dict[int, Any] = {}
4079 self._hidden_data: dict[int, Any] = {}
4080 self._ifds: dict[int, dict[int, Any]] = {}
4081 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None
4082 self._loaded_exif: bytes | None = None
4084 def _fixup(self, value: Any) -> Any:
4085 try:
4086 if len(value) == 1 and isinstance(value, tuple):
4087 return value[0]
4088 except Exception:
4089 pass
4090 return value
4092 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]:
4093 # Helper function
4094 # returns a dict with any single item tuples/lists as individual values
4095 return {k: self._fixup(v) for k, v in src_dict.items()}
4097 def _get_ifd_dict(
4098 self, offset: int, group: int | None = None
4099 ) -> dict[int, Any] | None:
4100 try:
4101 # an offset pointer to the location of the nested embedded IFD.
4102 # It should be a long, but may be corrupted.
4103 self.fp.seek(offset)
4104 except (KeyError, TypeError):
4105 return None
4106 else:
4107 from . import TiffImagePlugin
4109 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group)
4110 info.load(self.fp)
4111 return self._fixup_dict(dict(info))
4113 def _get_head(self) -> bytes:
4114 version = b"\x2b" if self.bigtiff else b"\x2a"
4115 if self.endian == "<":
4116 head = b"II" + version + b"\x00" + o32le(8)
4117 else:
4118 head = b"MM\x00" + version + o32be(8)
4119 if self.bigtiff:
4120 head += o32le(8) if self.endian == "<" else o32be(8)
4121 head += b"\x00\x00\x00\x00"
4122 return head
4124 def load(self, data: bytes) -> None:
4125 # Extract EXIF information. This is highly experimental,
4126 # and is likely to be replaced with something better in a future
4127 # version.
4129 # The EXIF record consists of a TIFF file embedded in a JPEG
4130 # application marker (!).
4131 if data == self._loaded_exif:
4132 return
4133 self._loaded_exif = data
4134 self._data.clear()
4135 self._hidden_data.clear()
4136 self._ifds.clear()
4137 while data and data.startswith(b"Exif\x00\x00"):
4138 data = data[6:]
4139 if not data:
4140 self._info = None
4141 return
4143 self.fp: IO[bytes] = io.BytesIO(data)
4144 self.head = self.fp.read(8)
4145 # process dictionary
4146 from . import TiffImagePlugin
4148 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4149 self.endian = self._info._endian
4150 self.fp.seek(self._info.next)
4151 self._info.load(self.fp)
4153 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None:
4154 self._loaded_exif = None
4155 self._data.clear()
4156 self._hidden_data.clear()
4157 self._ifds.clear()
4159 # process dictionary
4160 from . import TiffImagePlugin
4162 self.fp = fp
4163 if offset is not None:
4164 self.head = self._get_head()
4165 else:
4166 self.head = self.fp.read(8)
4167 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4168 if self.endian is None:
4169 self.endian = self._info._endian
4170 if offset is None:
4171 offset = self._info.next
4172 self.fp.tell()
4173 self.fp.seek(offset)
4174 self._info.load(self.fp)
4176 def _get_merged_dict(self) -> dict[int, Any]:
4177 merged_dict = dict(self)
4179 # get EXIF extension
4180 if ExifTags.IFD.Exif in self:
4181 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif)
4182 if ifd:
4183 merged_dict.update(ifd)
4185 # GPS
4186 if ExifTags.IFD.GPSInfo in self:
4187 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict(
4188 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo
4189 )
4191 return merged_dict
4193 def tobytes(self, offset: int = 8) -> bytes:
4194 from . import TiffImagePlugin
4196 head = self._get_head()
4197 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head)
4198 for tag, ifd_dict in self._ifds.items():
4199 if tag not in self:
4200 ifd[tag] = ifd_dict
4201 for tag, value in self.items():
4202 if tag in [
4203 ExifTags.IFD.Exif,
4204 ExifTags.IFD.GPSInfo,
4205 ] and not isinstance(value, dict):
4206 value = self.get_ifd(tag)
4207 if (
4208 tag == ExifTags.IFD.Exif
4209 and ExifTags.IFD.Interop in value
4210 and not isinstance(value[ExifTags.IFD.Interop], dict)
4211 ):
4212 value = value.copy()
4213 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop)
4214 ifd[tag] = value
4215 return b"Exif\x00\x00" + head + ifd.tobytes(offset)
4217 def get_ifd(self, tag: int) -> dict[int, Any]:
4218 if tag not in self._ifds:
4219 if tag == ExifTags.IFD.IFD1:
4220 if self._info is not None and self._info.next != 0:
4221 ifd = self._get_ifd_dict(self._info.next)
4222 if ifd is not None:
4223 self._ifds[tag] = ifd
4224 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
4225 offset = self._hidden_data.get(tag, self.get(tag))
4226 if offset is not None:
4227 ifd = self._get_ifd_dict(offset, tag)
4228 if ifd is not None:
4229 self._ifds[tag] = ifd
4230 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]:
4231 if ExifTags.IFD.Exif not in self._ifds:
4232 self.get_ifd(ExifTags.IFD.Exif)
4233 tag_data = self._ifds[ExifTags.IFD.Exif][tag]
4234 if tag == ExifTags.IFD.MakerNote:
4235 from .TiffImagePlugin import ImageFileDirectory_v2
4237 if tag_data.startswith(b"FUJIFILM"):
4238 ifd_offset = i32le(tag_data, 8)
4239 ifd_data = tag_data[ifd_offset:]
4241 makernote = {}
4242 for i in range(struct.unpack("<H", ifd_data[:2])[0]):
4243 ifd_tag, typ, count, data = struct.unpack(
4244 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
4245 )
4246 try:
4247 (
4248 unit_size,
4249 handler,
4250 ) = ImageFileDirectory_v2._load_dispatch[typ]
4251 except KeyError:
4252 continue
4253 size = count * unit_size
4254 if size > 4:
4255 (offset,) = struct.unpack("<L", data)
4256 data = ifd_data[offset - 12 : offset + size - 12]
4257 else:
4258 data = data[:size]
4260 if len(data) != size:
4261 warnings.warn(
4262 "Possibly corrupt EXIF MakerNote data. "
4263 f"Expecting to read {size} bytes but only got "
4264 f"{len(data)}. Skipping tag {ifd_tag}"
4265 )
4266 continue
4268 if not data:
4269 continue
4271 makernote[ifd_tag] = handler(
4272 ImageFileDirectory_v2(), data, False
4273 )
4274 self._ifds[tag] = dict(self._fixup_dict(makernote))
4275 elif self.get(0x010F) == "Nintendo":
4276 makernote = {}
4277 for i in range(struct.unpack(">H", tag_data[:2])[0]):
4278 ifd_tag, typ, count, data = struct.unpack(
4279 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2]
4280 )
4281 if ifd_tag == 0x1101:
4282 # CameraInfo
4283 (offset,) = struct.unpack(">L", data)
4284 self.fp.seek(offset)
4286 camerainfo: dict[str, int | bytes] = {
4287 "ModelID": self.fp.read(4)
4288 }
4290 self.fp.read(4)
4291 # Seconds since 2000
4292 camerainfo["TimeStamp"] = i32le(self.fp.read(12))
4294 self.fp.read(4)
4295 camerainfo["InternalSerialNumber"] = self.fp.read(4)
4297 self.fp.read(12)
4298 parallax = self.fp.read(4)
4299 handler = ImageFileDirectory_v2._load_dispatch[
4300 TiffTags.FLOAT
4301 ][1]
4302 camerainfo["Parallax"] = handler(
4303 ImageFileDirectory_v2(), parallax, False
4304 )[0]
4306 self.fp.read(4)
4307 camerainfo["Category"] = self.fp.read(2)
4309 makernote = {0x1101: camerainfo}
4310 self._ifds[tag] = makernote
4311 else:
4312 # Interop
4313 ifd = self._get_ifd_dict(tag_data, tag)
4314 if ifd is not None:
4315 self._ifds[tag] = ifd
4316 ifd = self._ifds.setdefault(tag, {})
4317 if tag == ExifTags.IFD.Exif and self._hidden_data:
4318 ifd = {
4319 k: v
4320 for (k, v) in ifd.items()
4321 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote)
4322 }
4323 return ifd
4325 def hide_offsets(self) -> None:
4326 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo):
4327 if tag in self:
4328 self._hidden_data[tag] = self[tag]
4329 del self[tag]
4331 def __str__(self) -> str:
4332 if self._info is not None:
4333 # Load all keys into self._data
4334 for tag in self._info:
4335 self[tag]
4337 return str(self._data)
4339 def __len__(self) -> int:
4340 keys = set(self._data)
4341 if self._info is not None:
4342 keys.update(self._info)
4343 return len(keys)
4345 def __getitem__(self, tag: int) -> Any:
4346 if self._info is not None and tag not in self._data and tag in self._info:
4347 self._data[tag] = self._fixup(self._info[tag])
4348 del self._info[tag]
4349 return self._data[tag]
4351 def __contains__(self, tag: object) -> bool:
4352 return tag in self._data or (self._info is not None and tag in self._info)
4354 def __setitem__(self, tag: int, value: Any) -> None:
4355 if self._info is not None and tag in self._info:
4356 del self._info[tag]
4357 self._data[tag] = value
4359 def __delitem__(self, tag: int) -> None:
4360 if self._info is not None and tag in self._info:
4361 del self._info[tag]
4362 else:
4363 del self._data[tag]
4364 if tag in self._ifds:
4365 del self._ifds[tag]
4367 def __iter__(self) -> Iterator[int]:
4368 keys = set(self._data)
4369 if self._info is not None:
4370 keys.update(self._info)
4371 return iter(keys)