Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PIL/Image.py: 19%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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
29__lazy_modules__ = {
30 "PIL._binary",
31 "PIL._deprecate",
32 "PIL._util",
33 "io",
34 "math",
35 "re",
36 "struct",
37}
39import abc
40import atexit
41import builtins
42import io
43import math
44import os
45import re
46import struct
47import sys
48import warnings
49from collections.abc import MutableMapping
50from enum import IntEnum
51from typing import IO, Protocol, cast
53# VERSION was removed in Pillow 6.0.0.
54# PILLOW_VERSION was removed in Pillow 9.0.0.
55# Use __version__ instead.
56from . import (
57 ExifTags,
58 ImageMode,
59 TiffTags,
60 UnidentifiedImageError,
61 __version__,
62 _plugins,
63)
64from ._binary import i32le, o32be, o32le
65from ._deprecate import deprecate
66from ._util import DeferredError, is_path
68TYPE_CHECKING = False
69if TYPE_CHECKING:
70 from collections.abc import Callable, Iterator, Sequence
71 from typing import Any, Literal, Self
74class DecompressionBombWarning(RuntimeWarning):
75 pass
78class DecompressionBombError(Exception):
79 pass
82WARN_POSSIBLE_FORMATS: bool = False
84# Limit to around a quarter gigabyte for a 24-bit (3 bpp) image
85MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3)
88try:
89 # If the _imaging C module is not present, Pillow will not load.
90 # Note that other modules should not refer to _imaging directly;
91 # import Image and use the Image.core variable instead.
92 # Also note that Image.core is not a publicly documented interface,
93 # and should be considered private and subject to change.
94 from . import _imaging as core
96 if __version__ != getattr(core, "PILLOW_VERSION", None):
97 msg = (
98 "The _imaging extension was built for another version of Pillow or PIL:\n"
99 f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n"
100 f"Pillow version: {__version__}"
101 )
102 raise ImportError(msg)
104except ImportError as v:
105 # Explanations for ways that we know we might have an import error
106 if str(v).startswith("Module use of python"):
107 # The _imaging C module is present, but not compiled for
108 # the right version (windows only). Print a warning, if
109 # possible.
110 warnings.warn(
111 "The _imaging extension was built for another version of Python.",
112 RuntimeWarning,
113 )
114 elif str(v).startswith("The _imaging extension"):
115 warnings.warn(str(v), RuntimeWarning)
116 # Fail here anyway. Don't let people run with a mostly broken Pillow.
117 # see docs/porting.rst
118 raise
121#
122# Constants
125# transpose
126class Transpose(IntEnum):
127 FLIP_LEFT_RIGHT = 0
128 FLIP_TOP_BOTTOM = 1
129 ROTATE_90 = 2
130 ROTATE_180 = 3
131 ROTATE_270 = 4
132 TRANSPOSE = 5
133 TRANSVERSE = 6
136# transforms (also defined in Imaging.h)
137class Transform(IntEnum):
138 AFFINE = 0
139 EXTENT = 1
140 PERSPECTIVE = 2
141 QUAD = 3
142 MESH = 4
145# resampling filters (also defined in Imaging.h)
146class Resampling(IntEnum):
147 NEAREST = 0
148 BOX = 4
149 BILINEAR = 2
150 HAMMING = 5
151 BICUBIC = 3
152 LANCZOS = 1
153 MKS2013 = 6
154 MKS2021 = 7
157_filters_support = {
158 Resampling.BOX: 0.5,
159 Resampling.BILINEAR: 1.0,
160 Resampling.HAMMING: 1.0,
161 Resampling.BICUBIC: 2.0,
162 Resampling.LANCZOS: 3.0,
163 Resampling.MKS2013: 2.5,
164 Resampling.MKS2021: 4.5,
165}
168# dithers
169class Dither(IntEnum):
170 NONE = 0
171 ORDERED = 1 # Not yet implemented
172 RASTERIZE = 2 # Not yet implemented
173 FLOYDSTEINBERG = 3 # default
176# palettes/quantizers
177class Palette(IntEnum):
178 WEB = 0
179 ADAPTIVE = 1
182class Quantize(IntEnum):
183 MEDIANCUT = 0
184 MAXCOVERAGE = 1
185 FASTOCTREE = 2
186 LIBIMAGEQUANT = 3
189module = sys.modules[__name__]
190for enum in (Transpose, Transform, Resampling, Dither, Palette, Quantize):
191 for item in enum:
192 setattr(module, item.name, item.value)
195if hasattr(core, "DEFAULT_STRATEGY"):
196 DEFAULT_STRATEGY = core.DEFAULT_STRATEGY
197 FILTERED = core.FILTERED
198 HUFFMAN_ONLY = core.HUFFMAN_ONLY
199 RLE = core.RLE
200 FIXED = core.FIXED
203# --------------------------------------------------------------------
204# Registries
206TYPE_CHECKING = False
207if TYPE_CHECKING:
208 import mmap
209 from xml.etree.ElementTree import Element
211 from IPython.lib.pretty import PrettyPrinter
213 from . import ImageFile, ImageFilter, ImagePalette, ImageQt, TiffImagePlugin
214 from ._typing import CapsuleType, NumpyArray, StrOrBytesPath
215ID: list[str] = []
216OPEN: dict[
217 str,
218 tuple[
219 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile],
220 Callable[[bytes], bool | str] | None,
221 ],
222] = {}
223MIME: dict[str, str] = {}
224SAVE: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
225SAVE_ALL: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
226EXTENSION: dict[str, str] = {}
227DECODERS: dict[str, type[ImageFile.PyDecoder]] = {}
228ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {}
230# --------------------------------------------------------------------
231# Modes
233_ENDIAN = "<" if sys.byteorder == "little" else ">"
236def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]:
237 m = ImageMode.getmode(im.mode)
238 shape: tuple[int, ...] = (im.height, im.width)
239 extra = len(m.bands)
240 if extra != 1:
241 shape += (extra,)
242 return shape, m.typestr
245MODES = [
246 "1",
247 "CMYK",
248 "F",
249 "HSV",
250 "I",
251 "I;16",
252 "I;16B",
253 "I;16L",
254 "I;16N",
255 "L",
256 "LA",
257 "La",
258 "LAB",
259 "P",
260 "PA",
261 "RGB",
262 "RGBA",
263 "RGBa",
264 "RGBX",
265 "YCbCr",
266]
268# raw modes that may be memory mapped. NOTE: if you change this, you
269# may have to modify the stride calculation in map.c too!
270_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")
273def getmodebase(mode: str) -> str:
274 """
275 Gets the "base" mode for given mode. This function returns "L" for
276 images that contain grayscale data, and "RGB" for images that
277 contain color data.
279 :param mode: Input mode.
280 :returns: "L" or "RGB".
281 :exception KeyError: If the input mode was not a standard mode.
282 """
283 return ImageMode.getmode(mode).basemode
286def getmodetype(mode: str) -> str:
287 """
288 Gets the storage type mode. Given a mode, this function returns a
289 single-layer mode suitable for storing individual bands.
291 :param mode: Input mode.
292 :returns: "L", "I", or "F".
293 :exception KeyError: If the input mode was not a standard mode.
294 """
295 return ImageMode.getmode(mode).basetype
298def getmodebandnames(mode: str) -> tuple[str, ...]:
299 """
300 Gets a list of individual band names. Given a mode, this function returns
301 a tuple containing the names of individual bands (use
302 :py:method:`~PIL.Image.getmodetype` to get the mode used to store each
303 individual band.
305 :param mode: Input mode.
306 :returns: A tuple containing band names. The length of the tuple
307 gives the number of bands in an image of the given mode.
308 :exception KeyError: If the input mode was not a standard mode.
309 """
310 return ImageMode.getmode(mode).bands
313def getmodebands(mode: str) -> int:
314 """
315 Gets the number of individual bands for this mode.
317 :param mode: Input mode.
318 :returns: The number of bands in this mode.
319 :exception KeyError: If the input mode was not a standard mode.
320 """
321 return len(ImageMode.getmode(mode).bands)
324# --------------------------------------------------------------------
325# Helpers
327_initialized = 0
329# Mapping from file extension to plugin module name for lazy importing
330_EXTENSION_PLUGIN: dict[str, str] = {
331 # Common formats (preinit)
332 ".bmp": "BmpImagePlugin",
333 ".dib": "BmpImagePlugin",
334 ".gif": "GifImagePlugin",
335 ".jfif": "JpegImagePlugin",
336 ".jpe": "JpegImagePlugin",
337 ".jpg": "JpegImagePlugin",
338 ".jpeg": "JpegImagePlugin",
339 ".pbm": "PpmImagePlugin",
340 ".pgm": "PpmImagePlugin",
341 ".pnm": "PpmImagePlugin",
342 ".ppm": "PpmImagePlugin",
343 ".pfm": "PpmImagePlugin",
344 ".png": "PngImagePlugin",
345 ".apng": "PngImagePlugin",
346 # Less common formats (init)
347 ".avif": "AvifImagePlugin",
348 ".avifs": "AvifImagePlugin",
349 ".blp": "BlpImagePlugin",
350 ".bufr": "BufrStubImagePlugin",
351 ".cur": "CurImagePlugin",
352 ".dcx": "DcxImagePlugin",
353 ".dds": "DdsImagePlugin",
354 ".ps": "EpsImagePlugin",
355 ".eps": "EpsImagePlugin",
356 ".fit": "FitsImagePlugin",
357 ".fits": "FitsImagePlugin",
358 ".fli": "FliImagePlugin",
359 ".flc": "FliImagePlugin",
360 ".fpx": "FpxImagePlugin",
361 ".ftc": "FtexImagePlugin",
362 ".ftu": "FtexImagePlugin",
363 ".gbr": "GbrImagePlugin",
364 ".grib": "GribStubImagePlugin",
365 ".h5": "Hdf5StubImagePlugin",
366 ".hdf": "Hdf5StubImagePlugin",
367 ".icns": "IcnsImagePlugin",
368 ".ico": "IcoImagePlugin",
369 ".im": "ImImagePlugin",
370 ".iim": "IptcImagePlugin",
371 ".jp2": "Jpeg2KImagePlugin",
372 ".j2k": "Jpeg2KImagePlugin",
373 ".jpc": "Jpeg2KImagePlugin",
374 ".jpf": "Jpeg2KImagePlugin",
375 ".jpx": "Jpeg2KImagePlugin",
376 ".j2c": "Jpeg2KImagePlugin",
377 ".mic": "MicImagePlugin",
378 ".mpg": "MpegImagePlugin",
379 ".mpeg": "MpegImagePlugin",
380 ".mpo": "MpoImagePlugin",
381 ".msp": "MspImagePlugin",
382 ".palm": "PalmImagePlugin",
383 ".pcd": "PcdImagePlugin",
384 ".pcx": "PcxImagePlugin",
385 ".pdf": "PdfImagePlugin",
386 ".pxr": "PixarImagePlugin",
387 ".psd": "PsdImagePlugin",
388 ".qoi": "QoiImagePlugin",
389 ".bw": "SgiImagePlugin",
390 ".rgb": "SgiImagePlugin",
391 ".rgba": "SgiImagePlugin",
392 ".sgi": "SgiImagePlugin",
393 ".ras": "SunImagePlugin",
394 ".tga": "TgaImagePlugin",
395 ".icb": "TgaImagePlugin",
396 ".vda": "TgaImagePlugin",
397 ".vst": "TgaImagePlugin",
398 ".tif": "TiffImagePlugin",
399 ".tiff": "TiffImagePlugin",
400 ".webp": "WebPImagePlugin",
401 ".wmf": "WmfImagePlugin",
402 ".emf": "WmfImagePlugin",
403 ".xbm": "XbmImagePlugin",
404 ".xpm": "XpmImagePlugin",
405}
408def _import_plugin_for_extension(ext: str | bytes) -> bool:
409 """Import only the plugin needed for a specific file extension."""
410 if not ext:
411 return False
413 if isinstance(ext, bytes):
414 ext = ext.decode()
415 ext = ext.lower()
416 if ext in EXTENSION:
417 return True
419 plugin = _EXTENSION_PLUGIN.get(ext)
420 if plugin is None:
421 return False
423 try:
424 __import__(f"{__spec__.parent}.{plugin}", globals(), locals(), [])
425 return True
426 except ImportError:
427 return False
430def preinit() -> None:
431 """
432 Explicitly loads BMP, GIF, JPEG, PPM and PNG file format drivers.
434 It is called when opening or saving images.
435 """
437 global _initialized
438 if _initialized >= 1:
439 return
441 try:
442 from . import BmpImagePlugin
444 assert BmpImagePlugin
445 except ImportError:
446 pass
447 try:
448 from . import GifImagePlugin
450 assert GifImagePlugin
451 except ImportError:
452 pass
453 try:
454 from . import JpegImagePlugin
456 assert JpegImagePlugin
457 except ImportError:
458 pass
459 try:
460 from . import PpmImagePlugin
462 assert PpmImagePlugin
463 except ImportError:
464 pass
465 try:
466 from . import PngImagePlugin
468 assert PngImagePlugin
469 except ImportError:
470 pass
472 _initialized = 1
475def init() -> bool:
476 """
477 Explicitly initializes the Python Imaging Library. This function
478 loads all available file format drivers.
480 It is called when opening or saving images if :py:meth:`~preinit()` is
481 insufficient, and by :py:meth:`~PIL.features.pilinfo`.
482 """
484 global _initialized
485 if _initialized >= 2:
486 return False
488 for plugin in _plugins:
489 try:
490 __import__(f"{__spec__.parent}.{plugin}", globals(), locals(), [])
491 except ImportError:
492 pass
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 _copy_info(self) -> dict[str | tuple[int, int], Any]:
679 return {k: v.copy() if isinstance(v, list) else v for k, v in self.info.items()}
681 def _new(self, im: core.ImagingCore) -> Image:
682 new = Image()
683 new.im = im
684 new._mode = im.mode
685 new._size = im.size
686 if im.mode in ("P", "PA"):
687 if self.palette:
688 new.palette = self.palette.copy()
689 else:
690 from . import ImagePalette
692 new.palette = ImagePalette.ImagePalette()
693 new.info = self._copy_info()
694 return new
696 # Context manager support
697 def __enter__(self) -> Self:
698 return self
700 def __exit__(self, *args: object) -> None:
701 pass
703 def close(self) -> None:
704 """
705 This operation will destroy the image core and release its memory.
706 The image data will be unusable afterward.
708 This function is required to close images that have multiple frames or
709 have not had their file read and closed by the
710 :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for
711 more information.
712 """
713 if getattr(self, "map", None):
714 if sys.platform == "win32" and sys.implementation.name == "pypy":
715 self.map.close()
716 self.map: mmap.mmap | None = None
718 # Instead of simply setting to None, we're setting up a
719 # deferred error that will better explain that the core image
720 # object is gone.
721 self._im = DeferredError(ValueError("Operation on closed image"))
723 def _copy(self) -> None:
724 self.load()
725 self.im = self.im.copy()
726 self.readonly = 0
728 def _ensure_mutable(self) -> None:
729 if self.readonly:
730 self._copy()
731 else:
732 self.load()
734 def _dump(
735 self, file: str | None = None, format: str | None = None, **options: Any
736 ) -> str:
737 suffix = f".{format}" if format else ""
739 if file:
740 filename = file
741 if not filename.endswith(suffix):
742 filename += suffix
743 else:
744 import tempfile
746 f, filename = tempfile.mkstemp(suffix)
747 os.close(f)
749 self.save(filename, format or "PPM", **options)
751 return filename
753 def __eq__(self, other: object) -> bool:
754 if self.__class__ is not other.__class__:
755 return False
756 assert isinstance(other, Image)
757 return (
758 self.mode == other.mode
759 and self.size == other.size
760 and self.info == other.info
761 and self.getpalette() == other.getpalette()
762 and self.tobytes() == other.tobytes()
763 )
765 def __repr__(self) -> str:
766 return (
767 f"<{self.__class__.__module__}.{self.__class__.__name__} "
768 f"image mode={self.mode} size={self.size[0]}x{self.size[1]} "
769 f"at 0x{id(self):X}>"
770 )
772 def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None:
773 """IPython plain text display support"""
775 # Same as __repr__ but without unpredictable id(self),
776 # to keep Jupyter notebook `text/plain` output stable.
777 p.text(
778 f"<{self.__class__.__module__}.{self.__class__.__name__} "
779 f"image mode={self.mode} size={self.size[0]}x{self.size[1]}>"
780 )
782 def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None:
783 """Helper function for iPython display hook.
785 :param image_format: Image format.
786 :returns: image as bytes, saved into the given format.
787 """
788 b = io.BytesIO()
789 try:
790 self.save(b, image_format, **kwargs)
791 except Exception:
792 return None
793 return b.getvalue()
795 def _repr_png_(self) -> bytes | None:
796 """iPython display hook support for PNG format.
798 :returns: PNG version of the image as bytes
799 """
800 return self._repr_image("PNG", compress_level=1)
802 def _repr_jpeg_(self) -> bytes | None:
803 """iPython display hook support for JPEG format.
805 :returns: JPEG version of the image as bytes
806 """
807 return self._repr_image("JPEG")
809 @property
810 def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]:
811 # numpy array interface support
812 new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3}
813 if self.mode == "1":
814 # Binary images need to be extended from bits to bytes
815 # See: https://github.com/python-pillow/Pillow/issues/350
816 new["data"] = self.tobytes("raw", "L")
817 else:
818 new["data"] = self.tobytes()
819 new["shape"], new["typestr"] = _conv_type_shape(self)
820 return new
822 def __arrow_c_schema__(self) -> object:
823 self.load()
824 return self.im.__arrow_c_schema__()
826 def __arrow_c_array__(
827 self, requested_schema: object | None = None
828 ) -> tuple[object, object]:
829 self.load()
830 return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__())
832 def __getstate__(self) -> list[Any]:
833 im_data = self.tobytes() # load image first
834 return [self.info, self.mode, self.size, self.getpalette(), im_data]
836 def __setstate__(self, state: list[Any]) -> None:
837 Image.__init__(self)
838 info, mode, size, palette, data = state[:5]
839 self.info = info
840 self._mode = mode
841 self._size = size
842 self.im = core.new(mode, size)
843 if mode in ("L", "LA", "P", "PA") and palette:
844 self.putpalette(palette)
845 self.frombytes(data)
847 def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes:
848 """
849 Return image as a bytes object.
851 .. warning::
853 This method returns raw image data derived from Pillow's internal
854 storage. For compressed image data (e.g. PNG, JPEG) use
855 :meth:`~.save`, with a BytesIO parameter for in-memory data.
857 :param encoder_name: What encoder to use.
859 The default is to use the standard "raw" encoder.
860 To see how this packs pixel data into the returned
861 bytes, see :file:`libImaging/Pack.c`.
863 A list of C encoders can be seen under codecs
864 section of the function array in
865 :file:`_imaging.c`. Python encoders are registered
866 within the relevant plugins.
867 :param args: Extra arguments to the encoder.
868 :returns: A :py:class:`bytes` object.
869 """
871 encoder_args: Any = args
872 if len(encoder_args) == 1 and isinstance(encoder_args[0], tuple):
873 # may pass tuple instead of argument list
874 encoder_args = encoder_args[0]
876 if encoder_name == "raw" and encoder_args == ():
877 encoder_args = self.mode
879 self.load()
881 if self.width == 0 or self.height == 0:
882 return b""
884 # unpack data
885 e = _getencoder(self.mode, encoder_name, encoder_args)
886 e.setimage(self.im, (0, 0, *self.size))
888 from . import ImageFile
890 bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c
892 output = []
893 while True:
894 bytes_consumed, errcode, data = e.encode(bufsize)
895 output.append(data)
896 if errcode:
897 break
898 if errcode < 0:
899 msg = f"encoder error {errcode} in tobytes"
900 raise RuntimeError(msg)
902 return b"".join(output)
904 def tobitmap(self, name: str = "image") -> bytes:
905 """
906 Returns the image converted to an X11 bitmap.
908 .. note:: This method only works for mode "1" images.
910 :param name: The name prefix to use for the bitmap variables.
911 :returns: A string containing an X11 bitmap.
912 :raises ValueError: If the mode is not "1"
913 """
915 self.load()
916 if self.mode != "1":
917 msg = "not a bitmap"
918 raise ValueError(msg)
919 data = self.tobytes("xbm")
920 return b"".join(
921 [
922 f"#define {name}_width {self.size[0]}\n".encode("ascii"),
923 f"#define {name}_height {self.size[1]}\n".encode("ascii"),
924 f"static char {name}_bits[] = {{\n".encode("ascii"),
925 data,
926 b"};",
927 ]
928 )
930 def frombytes(
931 self,
932 data: DecoderInput,
933 decoder_name: str = "raw",
934 *args: Any,
935 ) -> None:
936 """
937 Loads this image with pixel data from a bytes object.
939 This method is similar to the :py:func:`~PIL.Image.frombytes` function,
940 but loads data into this image instead of creating a new image object.
941 """
943 if self.width == 0 or self.height == 0:
944 return
946 decoder_args: Any = args
947 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
948 # may pass tuple instead of argument list
949 decoder_args = decoder_args[0]
951 if decoder_args and decoder_args[0] in {"P;2L", "P;4L"}:
952 multiple = 4 if decoder_args[0] == "P;2L" else 8
953 if len(data) % multiple:
954 msg = "not enough image data"
955 raise ValueError(msg)
957 # default format
958 if decoder_name == "raw" and decoder_args == ():
959 decoder_args = self.mode
961 # unpack data
962 d = _getdecoder(self.mode, decoder_name, decoder_args)
963 d.setimage(self.im, (0, 0, *self.size))
964 s = d.decode(data)
966 if s[0] >= 0:
967 msg = "not enough image data"
968 raise ValueError(msg)
969 if s[1] != 0:
970 msg = "cannot decode image data"
971 raise ValueError(msg)
973 def load(self) -> core.PixelAccess | None:
974 """
975 Allocates storage for the image and loads the pixel data. In
976 normal cases, you don't need to call this method, since the
977 Image class automatically loads an opened image when it is
978 accessed for the first time.
980 If the file associated with the image was opened by Pillow, then this
981 method will close it. The exception to this is if the image has
982 multiple frames, in which case the file will be left open for seek
983 operations. See :ref:`file-handling` for more information.
985 :returns: An image access object.
986 """
987 if self._im is not None and self.palette and self.palette.dirty:
988 # realize palette
989 mode, arr = self.palette.getdata()
990 self.im.putpalette(self.palette.mode, mode, arr)
991 self.palette.dirty = 0
992 self.palette.rawmode = None
993 if "transparency" in self.info and mode in ("LA", "PA"):
994 if isinstance(self.info["transparency"], int):
995 self.im.putpalettealpha(self.info["transparency"], 0)
996 else:
997 self.im.putpalettealphas(self.info["transparency"])
998 self.palette.mode = "RGBA"
999 elif self.palette.mode != mode:
1000 # If the palette rawmode is different to the mode,
1001 # then update the Python palette data
1002 self.palette.palette = self.im.getpalette(self.palette.mode)
1004 if self._im is not None:
1005 return self.im.pixel_access(self.readonly)
1006 return None
1008 def verify(self) -> None:
1009 """
1010 Verifies the contents of a file. For data read from a file, this
1011 method attempts to determine if the file is broken, without
1012 actually decoding the image data. If this method finds any
1013 problems, it raises suitable exceptions. If you need to load
1014 the image after using this method, you must reopen the image
1015 file.
1016 """
1017 pass
1019 def convert(
1020 self,
1021 mode: str | None = None,
1022 matrix: list[float] | tuple[float, ...] | None = None,
1023 dither: Dither | None = None,
1024 palette: Palette = Palette.WEB,
1025 colors: int = 256,
1026 ) -> Image:
1027 """
1028 Returns a converted copy of this image. For the "P" mode, this
1029 method translates pixels through the palette. If mode is
1030 omitted, a mode is chosen so that all information in the image
1031 and the palette can be represented without a palette.
1033 This supports all possible conversions between "L", "RGB" and "CMYK". The
1034 ``matrix`` argument only supports "L" and "RGB".
1036 When translating a color image to grayscale (mode "L"),
1037 the library uses the ITU-R 601-2 luma transform::
1039 L = R * 299/1000 + G * 587/1000 + B * 114/1000
1041 The default method of converting a grayscale ("L") or "RGB"
1042 image into a bilevel (mode "1") image uses Floyd-Steinberg
1043 dither to approximate the original image luminosity levels. If
1044 dither is ``None``, all values larger than 127 are set to 255 (white),
1045 all other values to 0 (black). To use other thresholds, use the
1046 :py:meth:`~PIL.Image.Image.point` method.
1048 When converting from "RGBA" to "P" without a ``matrix`` argument,
1049 this passes the operation to :py:meth:`~PIL.Image.Image.quantize`,
1050 and ``dither`` and ``palette`` are ignored.
1052 When converting from "PA", if an "RGBA" palette is present, the alpha
1053 channel from the image will be used instead of the values from the palette.
1055 :param mode: The requested mode. See: :ref:`concept-modes`.
1056 :param matrix: An optional conversion matrix. If given, this
1057 should be 4- or 12-sequence containing floating point values.
1058 :param dither: Dithering method, used when converting from
1059 mode "RGB" to "P" or from "RGB" or "L" to "1".
1060 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1061 (default). Note that this is not used when ``matrix`` is supplied.
1062 :param palette: Palette to use when converting from mode "RGB"
1063 to "P". Available palettes are :data:`Palette.WEB` or
1064 :data:`Palette.ADAPTIVE`.
1065 :param colors: Number of colors to use for the :data:`Palette.ADAPTIVE`
1066 palette. Defaults to 256.
1067 :returns: An :py:class:`~PIL.Image.Image` object.
1068 """
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: list[float] | tuple[float, ...], v: tuple[int, int, int]
1096 ) -> int:
1097 value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5
1098 return max(0, min(255, int(value)))
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), # trns was converted to RGB
1261 new_im,
1262 )
1263 except ValueError as e:
1264 del new_im.info["transparency"]
1265 if str(e) != "cannot allocate more than 256 colors":
1266 # If all 256 colors are in use,
1267 # then there is no need for transparency
1268 warnings.warn(
1269 "Couldn't allocate palette entry for transparency"
1270 )
1271 else:
1272 new_im.info["transparency"] = trns
1273 return new_im
1275 def quantize(
1276 self,
1277 colors: int = 256,
1278 method: int | None = None,
1279 kmeans: int = 0,
1280 palette: Image | None = None,
1281 dither: Dither = Dither.FLOYDSTEINBERG,
1282 ) -> Image:
1283 """
1284 Convert the image to 'P' mode with the specified number
1285 of colors.
1287 :param colors: The desired number of colors, <= 256
1288 :param method: :data:`Quantize.MEDIANCUT` (median cut),
1289 :data:`Quantize.MAXCOVERAGE` (maximum coverage),
1290 :data:`Quantize.FASTOCTREE` (fast octree),
1291 :data:`Quantize.LIBIMAGEQUANT` (libimagequant; check support
1292 using :py:func:`PIL.features.check_feature` with
1293 ``feature="libimagequant"``).
1295 By default, :data:`Quantize.MEDIANCUT` will be used.
1297 The exception to this is RGBA images. :data:`Quantize.MEDIANCUT`
1298 and :data:`Quantize.MAXCOVERAGE` do not support RGBA images, so
1299 :data:`Quantize.FASTOCTREE` is used by default instead.
1300 :param kmeans: Integer greater than or equal to zero.
1301 :param palette: Quantize to the palette of given
1302 :py:class:`PIL.Image.Image`.
1303 :param dither: Dithering method, used when converting from
1304 mode "RGB" to "P" or from "RGB" or "L" to "1".
1305 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1306 (default).
1307 :returns: A new image
1308 """
1310 self.load()
1312 if method is None:
1313 # defaults:
1314 method = Quantize.MEDIANCUT
1315 if self.mode == "RGBA":
1316 method = Quantize.FASTOCTREE
1318 if self.mode == "RGBA" and method not in (
1319 Quantize.FASTOCTREE,
1320 Quantize.LIBIMAGEQUANT,
1321 ):
1322 # Caller specified an invalid mode.
1323 msg = (
1324 "Fast Octree (method == 2) and libimagequant (method == 3) "
1325 "are the only valid methods for quantizing RGBA images"
1326 )
1327 raise ValueError(msg)
1329 if palette:
1330 # use palette from reference image
1331 palette.load()
1332 if palette.mode != "P":
1333 msg = "bad mode for palette image"
1334 raise ValueError(msg)
1335 if self.mode not in {"RGB", "L"}:
1336 msg = "only RGB or L mode images can be quantized to a palette"
1337 raise ValueError(msg)
1338 im = self.im.convert("P", dither, palette.im)
1339 new_im = self._new(im)
1340 assert palette.palette is not None
1341 new_im.palette = palette.palette.copy()
1342 return new_im
1344 if kmeans < 0:
1345 msg = "kmeans must not be negative"
1346 raise ValueError(msg)
1348 im = self._new(self.im.quantize(colors, method, kmeans))
1350 from . import ImagePalette
1352 mode = im.im.getpalettemode()
1353 palette_data = im.im.getpalette(mode)[: colors * len(mode)]
1354 im.palette = ImagePalette.ImagePalette(mode, palette_data)
1356 return im
1358 def copy(self) -> Image:
1359 """
1360 Copies this image. Use this method if you wish to paste things
1361 into an image, but still retain the original.
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 :returns: An :py:class:`~PIL.Image.Image` object.
1380 """
1382 if box is None or box == (0, 0, *self.size):
1383 return self.copy()
1385 if box[2] < box[0]:
1386 msg = "Coordinate 'right' is less than 'left'"
1387 raise ValueError(msg)
1388 elif box[3] < box[1]:
1389 msg = "Coordinate 'lower' is less than 'upper'"
1390 raise ValueError(msg)
1392 self.load()
1393 return self._new(self._crop(self.im, box))
1395 def _crop(
1396 self, im: core.ImagingCore, box: tuple[float, float, float, float]
1397 ) -> core.ImagingCore:
1398 """
1399 Returns a rectangular region from the core image object im.
1401 This is equivalent to calling im.crop((x0, y0, x1, y1)), but
1402 includes additional sanity checks.
1404 :param im: a core image object
1405 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1406 :returns: A core image object.
1407 """
1409 x0, y0, x1, y1 = map(int, map(round, box))
1411 absolute_values = (abs(x1 - x0), abs(y1 - y0))
1413 _decompression_bomb_check(absolute_values)
1415 return im.crop((x0, y0, x1, y1))
1417 def draft(
1418 self, mode: str | None, size: tuple[int, int] | None
1419 ) -> tuple[str, tuple[int, int, float, float]] | None:
1420 """
1421 Configures the image file loader so it returns a version of the
1422 image that as closely as possible matches the given mode and
1423 size. For example, you can use this method to convert a color
1424 JPEG to grayscale while loading it.
1426 If any changes are made, returns a tuple with the chosen ``mode`` and
1427 ``box`` with coordinates of the original image within the altered one.
1429 Note that this method modifies the :py:class:`~PIL.Image.Image` object
1430 in place. If the image has already been loaded, this method has no
1431 effect.
1433 Note: This method is not implemented for most images. It is
1434 currently implemented only for JPEG and MPO images.
1436 :param mode: The requested mode.
1437 :param size: The requested size in pixels, as a 2-tuple:
1438 (width, height).
1439 """
1440 pass
1442 def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image:
1443 """
1444 Filters this image using the given filter. For a list of
1445 available filters, see the :py:mod:`~PIL.ImageFilter` module.
1447 :param filter: Filter kernel.
1448 :returns: An :py:class:`~PIL.Image.Image` object."""
1450 from . import ImageFilter
1452 self.load()
1454 if callable(filter):
1455 filter = filter()
1456 if not hasattr(filter, "filter"):
1457 msg = "filter argument should be ImageFilter.Filter instance or class"
1458 raise TypeError(msg)
1460 multiband = isinstance(filter, ImageFilter.MultibandFilter)
1461 if self.im.bands == 1 or multiband:
1462 return self._new(filter.filter(self.im))
1464 ims = [
1465 self._new(filter.filter(self.im.getband(c))) for c in range(self.im.bands)
1466 ]
1467 return merge(self.mode, ims)
1469 def getbands(self) -> tuple[str, ...]:
1470 """
1471 Returns a tuple containing the name of each band in this image.
1472 For example, ``getbands`` on an RGB image returns ("R", "G", "B").
1474 :returns: A tuple containing band names.
1475 """
1476 return ImageMode.getmode(self.mode).bands
1478 def getbbox(self, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None:
1479 """
1480 Calculates the bounding box of the non-zero regions in the
1481 image.
1483 :param alpha_only: Optional flag, defaulting to ``True``.
1484 If ``True`` and the image has an alpha channel, trim transparent pixels.
1485 Otherwise, trim pixels when all channels are zero.
1486 Keyword-only argument.
1487 :returns: The bounding box is returned as a 4-tuple defining the
1488 left, upper, right, and lower pixel coordinate. See
1489 :ref:`coordinate-system`. If the image is completely empty, this
1490 method returns None.
1492 """
1494 self.load()
1495 return self.im.getbbox(alpha_only)
1497 def getcolors(
1498 self, maxcolors: int = 256
1499 ) -> list[tuple[int, tuple[int, ...]]] | list[tuple[int, float]] | None:
1500 """
1501 Returns a list of colors used in this image.
1503 The colors will be in the image's mode. For example, an RGB image will
1504 return a tuple of (red, green, blue) color values, and a P image will
1505 return the index of the color in the palette.
1507 :param maxcolors: Maximum number of colors. If this number is
1508 exceeded, this method returns None. The default limit is
1509 256 colors.
1510 :returns: An unsorted list of (count, pixel) values.
1511 """
1513 self.load()
1514 if self.mode in ("1", "L", "P"):
1515 h = self.im.histogram()
1516 out: list[tuple[int, float]] = [(h[i], i) for i in range(256) if h[i]]
1517 if len(out) > maxcolors:
1518 return None
1519 return out
1520 return self.im.getcolors(maxcolors)
1522 def getdata(self, band: int | None = None) -> core.ImagingCore:
1523 """
1524 Returns the contents of this image as a sequence object
1525 containing pixel values. The sequence object is flattened, so
1526 that values for line one follow directly after the values of
1527 line zero, and so on.
1529 Note that the sequence object returned by this method is an
1530 internal PIL data type, which only supports certain sequence
1531 operations. To convert it to an ordinary sequence (e.g. for
1532 printing), use ``list(im.getdata())``.
1534 :param band: What band to return. The default is to return
1535 all bands. To return a single band, pass in the index
1536 value (e.g. 0 to get the "R" band from an "RGB" image).
1537 :returns: A sequence-like object.
1538 """
1539 deprecate("Image.Image.getdata", 14, "get_flattened_data")
1541 self.load()
1542 if band is not None:
1543 return self.im.getband(band)
1544 return self.im # could be abused
1546 def get_flattened_data(
1547 self, band: int | None = None
1548 ) -> tuple[tuple[int, ...], ...] | tuple[float, ...]:
1549 """
1550 Returns the contents of this image as a tuple containing pixel values.
1551 The sequence object is flattened, so that values for line one follow
1552 directly after the values of line zero, and so on.
1554 :param band: What band to return. The default is to return
1555 all bands. To return a single band, pass in the index
1556 value (e.g. 0 to get the "R" band from an "RGB" image).
1557 :returns: A tuple containing pixel values.
1558 """
1559 self.load()
1560 if band is not None:
1561 return tuple(self.im.getband(band))
1562 return tuple(self.im)
1564 def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]:
1565 """
1566 Gets the minimum and maximum pixel values for each band in
1567 the image.
1569 :returns: For a single-band image, a 2-tuple containing the
1570 minimum and maximum pixel value. For a multi-band image,
1571 a tuple containing one 2-tuple for each band.
1572 """
1574 self.load()
1575 if self.im.bands > 1:
1576 return tuple(self.im.getband(i).getextrema() for i in range(self.im.bands))
1577 return self.im.getextrema()
1579 def getxmp(self, *, strip_namespaces: bool = True) -> dict[str, Any]:
1580 """
1581 Returns a dictionary containing the XMP tags.
1582 Requires defusedxml to be installed.
1584 :param strip_namespaces: If ``False``, keep each tag's full
1585 ``{namespace-uri}local-name`` form instead of stripping the namespace
1586 prefix.
1588 .. versionadded:: 13.0.0
1590 :returns: XMP tags in a dictionary.
1591 """
1592 try:
1593 from defusedxml import ElementTree
1594 except ImportError:
1595 warnings.warn("XMP data cannot be read without defusedxml dependency")
1596 return {}
1598 if strip_namespaces:
1600 def get_name(tag: str) -> str:
1601 return re.sub("^{[^}]+}", "", tag)
1603 else:
1605 def get_name(tag: str) -> str:
1606 return tag
1608 def get_value(element: Element) -> str | dict[str, Any] | None:
1609 value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()}
1610 children = list(element)
1611 if children:
1612 for child in children:
1613 name = get_name(child.tag)
1614 child_value = get_value(child)
1615 if name in value:
1616 if not isinstance(value[name], list):
1617 value[name] = [value[name]]
1618 value[name].append(child_value)
1619 else:
1620 value[name] = child_value
1621 elif value:
1622 if element.text:
1623 value["text"] = element.text
1624 else:
1625 return element.text
1626 return value
1628 if "xmp" not in self.info:
1629 return {}
1630 root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 "))
1631 return {get_name(root.tag): get_value(root)}
1633 def getexif(self) -> Exif:
1634 """
1635 Gets EXIF data from the image.
1637 :returns: an :py:class:`~PIL.Image.Exif` object.
1638 """
1639 if self._exif is None:
1640 self._exif = Exif()
1641 elif self._exif._loaded:
1642 return self._exif
1643 self._exif._loaded = True
1645 exif_info = self.info.get("exif")
1646 if exif_info is None:
1647 if "Raw profile type exif" in self.info:
1648 exif_info = bytes.fromhex(
1649 "".join(self.info["Raw profile type exif"].split("\n")[3:])
1650 )
1651 elif hasattr(self, "tag_v2"):
1652 from . import TiffImagePlugin
1654 assert isinstance(self, TiffImagePlugin.TiffImageFile)
1655 self._exif.bigtiff = self.tag_v2._bigtiff
1656 self._exif.endian = self.tag_v2._endian
1658 assert self.fp is not None
1659 self._exif.load_from_fp(self.fp, self.tag_v2._offset)
1660 if exif_info is not None:
1661 self._exif.load(exif_info)
1663 # XMP tags
1664 if ExifTags.Base.Orientation not in self._exif:
1665 xmp_tags = self.info.get("XML:com.adobe.xmp")
1666 pattern: str | bytes = r'tiff:Orientation(="|>)([0-9])'
1667 if not xmp_tags and (xmp_tags := self.info.get("xmp")):
1668 pattern = rb'tiff:Orientation(="|>)([0-9])'
1669 if xmp_tags:
1670 match = re.search(pattern, xmp_tags)
1671 if match:
1672 self._exif[ExifTags.Base.Orientation] = int(match[2])
1674 return self._exif
1676 def _reload_exif(self) -> None:
1677 if self._exif is None or not self._exif._loaded:
1678 return
1679 self._exif._loaded = False
1680 self.getexif()
1682 def getim(self) -> CapsuleType:
1683 """
1684 Returns a capsule that points to the internal image memory.
1686 :returns: A capsule object.
1687 """
1689 self.load()
1690 return self.im.ptr
1692 def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None:
1693 """
1694 Returns the image palette as a list.
1696 :param rawmode: The mode in which to return the palette. ``None`` will
1697 return the palette in its current mode.
1699 .. versionadded:: 9.1.0
1701 :returns: A list of color values [r, g, b, ...], or None if the
1702 image has no palette.
1703 """
1705 self.load()
1706 try:
1707 mode = self.im.getpalettemode()
1708 except ValueError:
1709 return None # no palette
1710 if rawmode is None:
1711 rawmode = mode
1712 return list(self.im.getpalette(mode, rawmode))
1714 @property
1715 def has_transparency_data(self) -> bool:
1716 """
1717 Determine if an image has transparency data, whether in the form of an
1718 alpha channel, a palette with an alpha channel, or a "transparency" key
1719 in the info dictionary.
1721 Note the image might still appear solid, if all of the values shown
1722 within are opaque.
1724 :returns: A boolean.
1725 """
1726 if (
1727 self.mode in ("LA", "La", "PA", "RGBA", "RGBa")
1728 or "transparency" in self.info
1729 ):
1730 return True
1731 if self.mode == "P":
1732 assert self.palette is not None
1733 return self.palette.mode.endswith("A")
1734 return False
1736 def apply_transparency(self) -> None:
1737 """
1738 If a P mode image has a "transparency" key in the info dictionary,
1739 remove the key and instead apply the transparency to the palette.
1740 Otherwise, the image is unchanged.
1741 """
1742 if self.mode != "P" or "transparency" not in self.info:
1743 return
1745 from . import ImagePalette
1747 palette = self.getpalette("RGBA")
1748 assert palette is not None
1749 transparency = self.info["transparency"]
1750 if isinstance(transparency, bytes):
1751 for i, alpha in enumerate(transparency):
1752 palette[i * 4 + 3] = alpha
1753 else:
1754 palette[transparency * 4 + 3] = 0
1755 self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette))
1756 self.palette.dirty = 1
1758 del self.info["transparency"]
1760 def getpixel(
1761 self, xy: tuple[int, int] | list[int]
1762 ) -> float | tuple[int, ...] | None:
1763 """
1764 Returns the pixel value at a given position.
1766 :param xy: The coordinate, given as (x, y). See
1767 :ref:`coordinate-system`.
1768 :returns: The pixel value. If the image is a multi-layer image,
1769 this method returns a tuple.
1770 """
1772 self.load()
1773 return self.im.getpixel(tuple(xy))
1775 def getprojection(self) -> tuple[list[int], list[int]]:
1776 """
1777 Get projection to x and y axes
1779 :returns: Two sequences, indicating where there are non-zero
1780 pixels along the X-axis and the Y-axis, respectively.
1781 """
1783 self.load()
1784 x, y = self.im.getprojection()
1785 return list(x), list(y)
1787 def histogram(
1788 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1789 ) -> list[int]:
1790 """
1791 Returns a histogram for the image. The histogram is returned as a
1792 list of pixel counts, one for each pixel value in the source
1793 image. Counts are grouped into 256 bins for each band, even if
1794 the image has more than 8 bits per band. If the image has more
1795 than one band, the histograms for all bands are concatenated (for
1796 example, the histogram for an "RGB" image contains 768 values).
1798 A bilevel image (mode "1") is treated as a grayscale ("L") image
1799 by this method.
1801 If a mask is provided, the method returns a histogram for those
1802 parts of the image where the mask image is non-zero. The mask
1803 image must have the same size as the image, and be either a
1804 bi-level image (mode "1") or a grayscale image ("L").
1806 :param mask: An optional mask.
1807 :param extrema: An optional tuple of manually-specified extrema.
1808 :returns: A list containing pixel counts.
1809 """
1810 self.load()
1811 if mask:
1812 mask.load()
1813 return self.im.histogram((0, 0), mask.im)
1814 if self.mode in ("I", "F"):
1815 return self.im.histogram(
1816 extrema if extrema is not None else self.getextrema()
1817 )
1818 return self.im.histogram()
1820 def entropy(
1821 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1822 ) -> float:
1823 """
1824 Calculates and returns the entropy for the image.
1826 A bilevel image (mode "1") is treated as a grayscale ("L")
1827 image by this method.
1829 If a mask is provided, the method employs the histogram for
1830 those parts of the image where the mask image is non-zero.
1831 The mask image must have the same size as the image, and be
1832 either a bi-level image (mode "1") or a grayscale image ("L").
1834 :param mask: An optional mask.
1835 :param extrema: An optional tuple of manually-specified extrema.
1836 :returns: A float value representing the image entropy
1837 """
1838 self.load()
1839 if mask:
1840 mask.load()
1841 return self.im.entropy((0, 0), mask.im)
1842 if self.mode in ("I", "F"):
1843 return self.im.entropy(
1844 extrema if extrema is not None else self.getextrema()
1845 )
1846 return self.im.entropy()
1848 def paste(
1849 self,
1850 im: Image | str | float | tuple[float, ...],
1851 box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None,
1852 mask: Image | None = None,
1853 ) -> None:
1854 """
1855 Pastes another image into this image. The box argument is either
1856 a 2-tuple giving the upper left corner, a 4-tuple defining the
1857 left, upper, right, and lower pixel coordinate, or None (same as
1858 (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size
1859 of the pasted image must match the size of the region.
1861 If the modes don't match, the pasted image is converted to the mode of
1862 this image (see the :py:meth:`~PIL.Image.Image.convert` method for
1863 details).
1865 Instead of an image, the source can be a integer or tuple
1866 containing pixel values. The method then fills the region
1867 with the given color. When creating RGB images, you can
1868 also use color strings as supported by the ImageColor module. See
1869 :ref:`colors` for more information.
1871 If a mask is given, this method updates only the regions
1872 indicated by the mask. You can use either "1", "L", "LA", "RGBA"
1873 or "RGBa" images (if present, the alpha band is used as mask).
1874 Where the mask is 255, the given image is copied as is. Where
1875 the mask is 0, the current value is preserved. Intermediate
1876 values will mix the two images together, including their alpha
1877 channels if they have them.
1879 See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
1880 combine images with respect to their alpha channels.
1882 :param im: Source image or pixel value (integer, float or tuple).
1883 :param box: An optional 4-tuple giving the region to paste into.
1884 If a 2-tuple is used instead, it's treated as the upper left
1885 corner. If omitted or None, the source is pasted into the
1886 upper left corner.
1888 If an image is given as the second argument and there is no
1889 third, the box defaults to (0, 0), and the second argument
1890 is interpreted as a mask image.
1891 :param mask: An optional mask image.
1892 """
1894 if isinstance(box, Image):
1895 if mask is not None:
1896 msg = "If using second argument as mask, third argument must be None"
1897 raise ValueError(msg)
1898 # abbreviated paste(im, mask) syntax
1899 mask = box
1900 box = None
1902 if box is None:
1903 box = (0, 0)
1905 if len(box) == 2:
1906 # upper left corner given; get size from image or mask
1907 if isinstance(im, Image):
1908 size = im.size
1909 elif isinstance(mask, Image):
1910 size = mask.size
1911 else:
1912 # FIXME: use self.size here?
1913 msg = "cannot determine region size; use 4-item box"
1914 raise ValueError(msg)
1915 box += (box[0] + size[0], box[1] + size[1])
1917 source: core.ImagingCore | str | float | tuple[float, ...]
1918 if isinstance(im, str):
1919 from . import ImageColor
1921 source = ImageColor.getcolor(im, self.mode)
1922 elif isinstance(im, Image):
1923 im.load()
1924 if self.mode != im.mode:
1925 if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"):
1926 # should use an adapter for this!
1927 im = im.convert(self.mode)
1928 source = im.im
1929 else:
1930 source = im
1932 self._ensure_mutable()
1934 if mask:
1935 mask.load()
1936 self.im.paste(source, box, mask.im)
1937 else:
1938 self.im.paste(source, box)
1940 def alpha_composite(
1941 self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0)
1942 ) -> None:
1943 """'In-place' analog of Image.alpha_composite. Composites an image
1944 onto this image.
1946 :param im: image to composite over this one
1947 :param dest: Optional 2 tuple (left, top) specifying the upper
1948 left corner in this (destination) image.
1949 :param source: Optional 2 (left, top) tuple for the upper left
1950 corner in the overlay source image, or 4 tuple (left, top, right,
1951 bottom) for the bounds of the source rectangle
1953 Performance Note: Not currently implemented in-place in the core layer.
1954 """
1956 if not isinstance(source, (list, tuple)):
1957 msg = "Source must be a list or tuple"
1958 raise ValueError(msg)
1959 if not isinstance(dest, (list, tuple)):
1960 msg = "Destination must be a list or tuple"
1961 raise ValueError(msg)
1963 if len(source) == 4:
1964 overlay_crop_box = tuple(source)
1965 elif len(source) == 2:
1966 overlay_crop_box = tuple(source) + im.size
1967 else:
1968 msg = "Source must be a sequence of length 2 or 4"
1969 raise ValueError(msg)
1971 if not len(dest) == 2:
1972 msg = "Destination must be a sequence of length 2"
1973 raise ValueError(msg)
1974 if min(source) < 0:
1975 msg = "Source must be non-negative"
1976 raise ValueError(msg)
1978 # over image, crop if it's not the whole image.
1979 if overlay_crop_box == (0, 0, *im.size):
1980 overlay = im
1981 else:
1982 overlay = im.crop(overlay_crop_box)
1984 # target for the paste
1985 box = tuple(dest) + (dest[0] + overlay.width, dest[1] + overlay.height)
1987 # destination image. don't copy if we're using the whole image.
1988 if box == (0, 0, *self.size):
1989 background = self
1990 else:
1991 background = self.crop(box)
1993 result = alpha_composite(background, overlay)
1994 self.paste(result, box)
1996 def point(
1997 self,
1998 lut: (
1999 Sequence[float]
2000 | NumpyArray
2001 | Callable[[int], float]
2002 | Callable[[ImagePointTransform], ImagePointTransform | float]
2003 | ImagePointHandler
2004 ),
2005 mode: str | None = None,
2006 ) -> Image:
2007 """
2008 Maps this image through a lookup table or function.
2010 :param lut: A lookup table, containing 256 (or 65536 if
2011 self.mode=="I" and mode == "L") values per band in the
2012 image. A function can be used instead, it should take a
2013 single argument. The function is called once for each
2014 possible pixel value, and the resulting table is applied to
2015 all bands of the image.
2017 It may also be an :py:class:`~PIL.Image.ImagePointHandler`
2018 object::
2020 class Example(Image.ImagePointHandler):
2021 def point(self, im: Image) -> Image:
2022 # Return result
2023 :param mode: Output mode (default is same as input). This can only be used if
2024 the source image has mode "L" or "P", and the output has mode "1" or the
2025 source image mode is "I" and the output mode is "L".
2026 :returns: An :py:class:`~PIL.Image.Image` object.
2027 """
2029 self.load()
2031 if isinstance(lut, ImagePointHandler):
2032 return lut.point(self)
2034 if callable(lut):
2035 # if it isn't a list, it should be a function
2036 if self.mode in ("I", "I;16", "F"):
2037 # check if the function can be used with point_transform
2038 # UNDONE wiredfool -- I think this prevents us from ever doing
2039 # a gamma function point transform on > 8bit images.
2040 scale, offset = _getscaleoffset(lut) # type: ignore[arg-type]
2041 return self._new(self.im.point_transform(scale, offset))
2042 # for other modes, convert the function to a table
2043 flatLut = [lut(i) for i in range(256)] * self.im.bands # type: ignore[arg-type]
2044 else:
2045 flatLut = lut
2047 if self.mode == "F":
2048 # FIXME: _imaging returns a confusing error message for this case
2049 msg = "point operation not supported for this mode"
2050 raise ValueError(msg)
2052 if mode != "F":
2053 flatLut = [round(i) for i in flatLut]
2054 return self._new(self.im.point(flatLut, mode))
2056 def putalpha(self, alpha: Image | int) -> None:
2057 """
2058 Adds or replaces the alpha layer in this image. If the image
2059 does not have an alpha layer, it's converted to "LA" or "RGBA".
2060 The new layer must be either "L" or "1".
2062 :param alpha: The new alpha layer. This can either be an "L" or "1"
2063 image having the same size as this image, or an integer.
2064 """
2066 self._ensure_mutable()
2068 if self.mode in ("RGB", "RGBX"):
2069 # promote self to RGBA
2070 self.im.setalpha()
2071 self._mode = "RGBA"
2072 elif self.mode not in ("LA", "PA", "RGBA"):
2073 try:
2074 # do things the hard way
2075 mode = getmodebase(self.mode) + "A"
2076 im = self.im.convert(mode)
2077 if im.mode not in ("LA", "PA", "RGBA"):
2078 msg = "alpha channel could not be added"
2079 raise ValueError(msg) # sanity check
2080 self.im = im
2081 self._mode = self.im.mode
2082 except KeyError as e:
2083 msg = "illegal image mode"
2084 raise ValueError(msg) from e
2086 if self.mode in ("LA", "PA"):
2087 band = 1
2088 else:
2089 band = 3
2091 if isinstance(alpha, Image):
2092 # alpha layer
2093 if alpha.mode not in ("1", "L"):
2094 msg = "illegal image mode"
2095 raise ValueError(msg)
2096 alpha.load()
2097 if alpha.mode == "1":
2098 alpha = alpha.convert("L")
2099 else:
2100 # constant alpha
2101 try:
2102 self.im.fillband(band, alpha)
2103 except (AttributeError, ValueError):
2104 # do things the hard way
2105 alpha = new("L", self.size, alpha)
2106 else:
2107 return
2109 self.im.putband(alpha.im, band)
2111 def putdata(
2112 self,
2113 data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray,
2114 scale: float = 1.0,
2115 offset: float = 0.0,
2116 ) -> None:
2117 """
2118 Copies pixel data from a flattened sequence object into the image. The
2119 values should start at the upper left corner (0, 0), continue to the
2120 end of the line, followed directly by the first value of the second
2121 line, and so on. Data will be read until either the image or the
2122 sequence ends. The scale and offset values are used to adjust the
2123 sequence values: **pixel = value*scale + offset**.
2125 :param data: A flattened sequence object. See :ref:`colors` for more
2126 information about values.
2127 :param scale: An optional scale value. The default is 1.0.
2128 :param offset: An optional offset value. The default is 0.0.
2129 """
2131 self._ensure_mutable()
2133 self.im.putdata(data, scale, offset)
2135 def putpalette(
2136 self,
2137 data: ImagePalette.ImagePalette | bytes | Sequence[int],
2138 rawmode: str = "RGB",
2139 ) -> None:
2140 """
2141 Attaches a palette to this image. The image must be a "P", "PA", "L"
2142 or "LA" image.
2144 The palette sequence must contain at most 256 colors, made up of one
2145 integer value for each channel in the raw mode.
2146 For example, if the raw mode is "RGB", then it can contain at most 768
2147 values, made up of red, green and blue values for the corresponding pixel
2148 index in the 256 colors.
2149 If the raw mode is "RGBA", then it can contain at most 1024 values,
2150 containing red, green, blue and alpha values.
2152 Alternatively, an 8-bit string may be used instead of an integer sequence.
2154 :param data: A palette sequence (either a list or a string).
2155 :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", "CMYK", or a
2156 mode that can be transformed to one of those modes (e.g. "R", "RGBA;L").
2157 """
2158 from . import ImagePalette
2160 if self.mode not in ("L", "LA", "P", "PA"):
2161 msg = "illegal image mode"
2162 raise ValueError(msg)
2163 if isinstance(data, ImagePalette.ImagePalette):
2164 palette = ImagePalette.raw(data.rawmode or "RGB", data.palette)
2165 else:
2166 palette = ImagePalette.raw(rawmode, data)
2167 self._mode = "PA" if "A" in self.mode else "P"
2168 self.palette = palette
2169 if rawmode.startswith("CMYK"):
2170 self.palette.mode = "CMYK"
2171 elif "A" in rawmode:
2172 self.palette.mode = "RGBA"
2173 self.load() # install new palette
2175 def putpixel(
2176 self,
2177 xy: tuple[int, int] | list[int],
2178 value: float | tuple[int, ...] | list[int],
2179 ) -> None:
2180 """
2181 Modifies the pixel at the given position. The color is given as
2182 a single numerical value for single-band images, and a tuple for
2183 multi-band images. In addition to this, RGB and RGBA tuples are
2184 accepted for P and PA images. See :ref:`colors` for more information.
2186 Note that this method is relatively slow. For more extensive changes,
2187 use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
2188 module instead.
2190 See:
2192 * :py:meth:`~PIL.Image.Image.paste`
2193 * :py:meth:`~PIL.Image.Image.putdata`
2194 * :py:mod:`~PIL.ImageDraw`
2196 :param xy: The pixel coordinate, given as (x, y). See
2197 :ref:`coordinate-system`.
2198 :param value: The pixel value.
2199 """
2201 self._ensure_mutable()
2203 if (
2204 self.mode in ("P", "PA")
2205 and isinstance(value, (list, tuple))
2206 and len(value) in [3, 4]
2207 ):
2208 # RGB or RGBA value for a P or PA image
2209 if self.mode == "PA":
2210 alpha = value[3] if len(value) == 4 else 255
2211 value = value[:3]
2212 assert self.palette is not None
2213 palette_index = self.palette.getcolor(tuple(value), self)
2214 value = (palette_index, alpha) if self.mode == "PA" else palette_index
2215 return self.im.putpixel(xy, value)
2217 def remap_palette(
2218 self, dest_map: list[int], source_palette: bytes | bytearray | None = None
2219 ) -> Image:
2220 """
2221 Rewrites the image to reorder the palette.
2223 :param dest_map: A list of indexes into the original palette.
2224 e.g. ``[1,0]`` would swap a two item palette, and ``list(range(256))``
2225 is the identity transform.
2226 :param source_palette: Bytes or None.
2227 :returns: An :py:class:`~PIL.Image.Image` object.
2229 """
2230 from . import ImagePalette
2232 if self.mode not in ("L", "P"):
2233 msg = "illegal image mode"
2234 raise ValueError(msg)
2236 bands = 3
2237 palette_mode = "RGB"
2238 if source_palette is None:
2239 if self.mode == "P":
2240 self.load()
2241 palette_mode = self.im.getpalettemode()
2242 if palette_mode == "RGBA":
2243 bands = 4
2244 source_palette = self.im.getpalette(palette_mode)
2245 else: # L-mode
2246 source_palette = bytearray(i // 3 for i in range(768))
2247 elif len(source_palette) > 768:
2248 bands = 4
2249 palette_mode = "RGBA"
2251 palette_bytes = b""
2252 new_positions = [0] * 256
2254 # pick only the used colors from the palette
2255 for i, oldPosition in enumerate(dest_map):
2256 palette_bytes += source_palette[
2257 oldPosition * bands : oldPosition * bands + bands
2258 ]
2259 new_positions[oldPosition] = i
2261 # replace the palette color id of all pixel with the new id
2263 # Palette images are [0..255], mapped through a 1 or 3
2264 # byte/color map. We need to remap the whole image
2265 # from palette 1 to palette 2. New_positions is
2266 # an array of indexes into palette 1. Palette 2 is
2267 # palette 1 with any holes removed.
2269 # We're going to leverage the convert mechanism to use the
2270 # C code to remap the image from palette 1 to palette 2,
2271 # by forcing the source image into 'L' mode and adding a
2272 # mapping 'L' mode palette, then converting back to 'L'
2273 # sans palette thus converting the image bytes, then
2274 # assigning the optimized RGB palette.
2276 # perf reference, 9500x4000 gif, w/~135 colors
2277 # 14 sec prepatch, 1 sec postpatch with optimization forced.
2279 mapping_palette = bytearray(new_positions)
2281 m_im = self.copy()
2282 m_im._mode = "P"
2284 m_im.palette = ImagePalette.ImagePalette(
2285 palette_mode, palette=mapping_palette * bands
2286 )
2287 # possibly set palette dirty, then
2288 # m_im.putpalette(mapping_palette, 'L') # converts to 'P'
2289 # or just force it.
2290 # UNDONE -- this is part of the general issue with palettes
2291 m_im.im.putpalette(palette_mode, palette_mode + ";L", m_im.palette.tobytes())
2293 m_im = m_im.convert("L")
2295 m_im.putpalette(palette_bytes, palette_mode)
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`, :py:data:`Resampling.LANCZOS`,
2344 :py:data:`Resampling.MKS2013`, or :py:data:`Resampling.MKS2021`.
2345 If the image has mode "1" or "P", it is always set to
2346 :py:data:`Resampling.NEAREST`. Otherwise, the default filter is
2347 :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`.
2348 :param box: An optional 4-tuple of floats providing
2349 the source image region to be scaled.
2350 The values must be within (0, 0, width, height) rectangle.
2351 If omitted or None, the entire source is used.
2352 :param reducing_gap: Apply optimization by resizing the image
2353 in two steps. First, reducing the image by integer times
2354 using :py:meth:`~PIL.Image.Image.reduce`.
2355 Second, resizing using regular resampling. The last step
2356 changes size no less than by ``reducing_gap`` times.
2357 ``reducing_gap`` may be None (no first step is performed)
2358 or should be greater than 1.0. The bigger ``reducing_gap``,
2359 the closer the result to the fair resampling.
2360 The smaller ``reducing_gap``, the faster resizing.
2361 With ``reducing_gap`` greater or equal to 3.0, the result is
2362 indistinguishable from fair resampling in most cases.
2363 The default value is None (no optimization).
2364 :returns: An :py:class:`~PIL.Image.Image` object.
2365 """
2367 if resample is None:
2368 resample = Resampling.BICUBIC
2369 elif resample not in (
2370 Resampling.NEAREST,
2371 Resampling.BILINEAR,
2372 Resampling.BICUBIC,
2373 Resampling.LANCZOS,
2374 Resampling.BOX,
2375 Resampling.HAMMING,
2376 Resampling.MKS2013,
2377 Resampling.MKS2021,
2378 ):
2379 msg = f"Unknown resampling filter ({resample})."
2381 filters = [
2382 f"{filter[1]} ({filter[0]})"
2383 for filter in (
2384 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
2385 (Resampling.LANCZOS, "Image.Resampling.LANCZOS"),
2386 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
2387 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
2388 (Resampling.BOX, "Image.Resampling.BOX"),
2389 (Resampling.HAMMING, "Image.Resampling.HAMMING"),
2390 (Resampling.MKS2013, "Image.Resampling.MKS2013"),
2391 (Resampling.MKS2021, "Image.Resampling.MKS2021"),
2392 )
2393 ]
2394 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
2395 raise ValueError(msg)
2397 if reducing_gap is not None and reducing_gap < 1.0:
2398 msg = "reducing_gap must be 1.0 or greater"
2399 raise ValueError(msg)
2401 if box is None:
2402 box = (0, 0, *self.size)
2404 size = tuple(size)
2405 if self.size == size and box == (0, 0, *self.size):
2406 return self.copy()
2408 if self.mode in ("1", "P"):
2409 resample = Resampling.NEAREST
2411 if self.mode in ["LA", "RGBA"] and resample != Resampling.NEAREST:
2412 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2413 im = im.resize(size, resample, box)
2414 return im.convert(self.mode)
2416 self.load()
2418 if reducing_gap is not None and resample != Resampling.NEAREST:
2419 factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1
2420 factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1
2421 if factor_x > 1 or factor_y > 1:
2422 reduce_box = self._get_safe_box(size, cast("Resampling", resample), box)
2423 factor = (factor_x, factor_y)
2424 self = (
2425 self.reduce(factor, box=reduce_box)
2426 if callable(self.reduce)
2427 else Image.reduce(self, factor, box=reduce_box)
2428 )
2429 box = (
2430 (box[0] - reduce_box[0]) / factor_x,
2431 (box[1] - reduce_box[1]) / factor_y,
2432 (box[2] - reduce_box[0]) / factor_x,
2433 (box[3] - reduce_box[1]) / factor_y,
2434 )
2436 return self._new(self.im.resize(size, resample, box))
2438 def reduce(
2439 self,
2440 factor: int | tuple[int, int],
2441 box: tuple[int, int, int, int] | None = None,
2442 ) -> Image:
2443 """
2444 Returns a copy of the image reduced ``factor`` times.
2445 If the size of the image is not dividable by ``factor``,
2446 the resulting size will be rounded up.
2448 :param factor: A greater than 0 integer or tuple of two integers
2449 for width and height separately.
2450 :param box: An optional 4-tuple of ints providing
2451 the source image region to be reduced.
2452 The values must be within ``(0, 0, width, height)`` rectangle.
2453 If omitted or ``None``, the entire source is used.
2454 """
2455 if not isinstance(factor, (list, tuple)):
2456 factor = (factor, factor)
2458 if factor == (1, 1):
2459 return self.crop(box)
2461 if box is None:
2462 box = (0, 0, *self.size)
2464 if self.mode in ["LA", "RGBA"]:
2465 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2466 im = im.reduce(factor, box)
2467 return im.convert(self.mode)
2469 self.load()
2471 return self._new(self.im.reduce(factor, box))
2473 def rotate(
2474 self,
2475 angle: float,
2476 resample: Resampling = Resampling.NEAREST,
2477 expand: int | bool = False,
2478 center: tuple[float, float] | None = None,
2479 translate: tuple[int, int] | None = None,
2480 fillcolor: float | tuple[float, ...] | str | None = None,
2481 ) -> Image:
2482 """
2483 Returns a rotated copy of this image. This method returns a
2484 copy of this image, rotated the given number of degrees counter
2485 clockwise around its centre.
2487 :param angle: In degrees counterclockwise.
2488 :param resample: An optional resampling filter. This can be
2489 one of :py:data:`Resampling.NEAREST` (use nearest neighbour),
2490 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2491 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2492 interpolation in a 4x4 environment). If omitted, or if the image has
2493 mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`.
2494 See :ref:`concept-filters`.
2495 :param expand: Optional expansion flag. If true, expands the output
2496 image to make it large enough to hold the entire rotated image.
2497 If false or omitted, make the output image the same size as the
2498 input image. Note that the expand flag assumes rotation around
2499 the center and no translation.
2500 :param center: Optional center of rotation (a 2-tuple). Origin is
2501 the upper left corner. Default is the center of the image.
2502 :param translate: An optional post-rotate translation (a 2-tuple).
2503 :param fillcolor: An optional color for area outside the rotated image.
2504 :returns: An :py:class:`~PIL.Image.Image` object.
2505 """
2507 angle = angle % 360.0
2509 # Fast paths regardless of filter, as long as we're not
2510 # translating or changing the center.
2511 if not (center or translate):
2512 if angle == 0:
2513 return self.copy()
2514 if angle == 180:
2515 return self.transpose(Transpose.ROTATE_180)
2516 if angle in (90, 270) and (expand or self.width == self.height):
2517 return self.transpose(
2518 Transpose.ROTATE_90 if angle == 90 else Transpose.ROTATE_270
2519 )
2521 # Calculate the affine matrix. Note that this is the reverse
2522 # transformation (from destination image to source) because we
2523 # want to interpolate the (discrete) destination pixel from
2524 # the local area around the (floating) source pixel.
2526 # The matrix we actually want (note that it operates from the right):
2527 # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx)
2528 # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
2529 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1)
2531 # The reverse matrix is thus:
2532 # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx)
2533 # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
2534 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1)
2536 # In any case, the final translation may be updated at the end to
2537 # compensate for the expand flag.
2539 w, h = self.size
2541 if translate is None:
2542 post_trans = (0, 0)
2543 else:
2544 post_trans = translate
2545 if center is None:
2546 center = (w / 2, h / 2)
2548 angle = -math.radians(angle)
2549 matrix = [
2550 round(math.cos(angle), 15),
2551 round(math.sin(angle), 15),
2552 0.0,
2553 round(-math.sin(angle), 15),
2554 round(math.cos(angle), 15),
2555 0.0,
2556 ]
2558 def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]:
2559 a, b, c, d, e, f = matrix
2560 return a * x + b * y + c, d * x + e * y + f
2562 matrix[2], matrix[5] = transform(
2563 -center[0] - post_trans[0], -center[1] - post_trans[1], matrix
2564 )
2565 matrix[2] += center[0]
2566 matrix[5] += center[1]
2568 if expand:
2569 # calculate output size
2570 xx = []
2571 yy = []
2572 for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
2573 transformed_x, transformed_y = transform(x, y, matrix)
2574 xx.append(transformed_x)
2575 yy.append(transformed_y)
2576 nw = math.ceil(max(xx)) - math.floor(min(xx))
2577 nh = math.ceil(max(yy)) - math.floor(min(yy))
2579 # We multiply a translation matrix from the right. Because of its
2580 # special form, this is the same as taking the image of the
2581 # translation vector as new translation vector.
2582 matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
2583 w, h = nw, nh
2585 return self.transform(
2586 (w, h), Transform.AFFINE, matrix, resample, fillcolor=fillcolor
2587 )
2589 def save(
2590 self, fp: StrOrBytesPath | IO[bytes], format: str | None = None, **params: Any
2591 ) -> None:
2592 """
2593 Saves this image under the given filename. If no format is
2594 specified, the format to use is determined from the filename
2595 extension, if possible.
2597 Keyword options can be used to provide additional instructions
2598 to the writer. If a writer doesn't recognise an option, it is
2599 silently ignored. The available options are described in the
2600 :doc:`image format documentation
2601 <../handbook/image-file-formats>` for each writer.
2603 You can use a file object instead of a filename. In this case,
2604 you must always specify the format. The file object must
2605 implement the ``seek``, ``tell``, and ``write``
2606 methods, and be opened in binary mode.
2608 :param fp: A filename (string), os.PathLike object or file object.
2609 :param format: Optional format override. If omitted, the
2610 format to use is determined from the filename extension.
2611 If a file object was used instead of a filename, this
2612 parameter should always be used.
2613 :param params: Extra parameters to the image writer. These can also be
2614 set on the image itself through ``encoderinfo``. This is useful when
2615 saving multiple images::
2617 # Saving XMP data to a single image
2618 from PIL import Image
2619 red = Image.new("RGB", (1, 1), "#f00")
2620 red.save("out.mpo", xmp=b"test")
2622 # Saving XMP data to the second frame of an image
2623 from PIL import Image
2624 black = Image.new("RGB", (1, 1))
2625 red = Image.new("RGB", (1, 1), "#f00")
2626 red.encoderinfo = {"xmp": b"test"}
2627 black.save("out.mpo", save_all=True, append_images=[red])
2628 :returns: None
2629 :exception ValueError: If the output format could not be determined
2630 from the file name. Use the format option to solve this.
2631 :exception OSError: If the file could not be written. The file
2632 may have been created, and may contain partial data.
2633 """
2635 filename: str | bytes = ""
2636 open_fp = False
2637 if is_path(fp):
2638 filename = os.fspath(fp)
2639 open_fp = True
2640 elif fp == sys.stdout and isinstance(sys.stdout, io.TextIOWrapper):
2641 fp = sys.stdout.buffer
2642 if not filename and hasattr(fp, "name") and is_path(fp.name):
2643 # only set the name for metadata purposes
2644 filename = os.fspath(fp.name)
2646 if format:
2647 preinit()
2648 else:
2649 filename_ext = os.path.splitext(filename)[1].lower()
2650 ext = (
2651 filename_ext.decode()
2652 if isinstance(filename_ext, bytes)
2653 else filename_ext
2654 )
2656 # Try importing only the plugin for this extension first
2657 if not _import_plugin_for_extension(ext):
2658 preinit()
2660 if ext not in EXTENSION:
2661 init()
2662 try:
2663 format = EXTENSION[ext]
2664 except KeyError as e:
2665 msg = f"unknown file extension: {ext}"
2666 raise ValueError(msg) from e
2668 from . import ImageFile
2670 # may mutate self!
2671 if isinstance(self, ImageFile.ImageFile) and os.path.abspath(
2672 filename
2673 ) == os.path.abspath(self.filename):
2674 self._ensure_mutable()
2675 else:
2676 self.load()
2678 save_all = params.pop("save_all", None)
2679 self._default_encoderinfo = params
2680 encoderinfo = getattr(self, "encoderinfo", {})
2681 self._attach_default_encoderinfo(self)
2682 self.encoderconfig: tuple[Any, ...] = ()
2684 if format.upper() not in SAVE:
2685 init()
2686 if save_all or (
2687 save_all is None
2688 and params.get("append_images")
2689 and format.upper() in SAVE_ALL
2690 ):
2691 save_handler = SAVE_ALL[format.upper()]
2692 else:
2693 save_handler = SAVE[format.upper()]
2695 created = False
2696 if open_fp:
2697 created = not os.path.exists(filename)
2698 if params.get("append", False):
2699 # Open also for reading ("+"), because TIFF save_all
2700 # writer needs to go back and edit the written data.
2701 fp = builtins.open(filename, "r+b")
2702 else:
2703 fp = builtins.open(filename, "w+b")
2704 else:
2705 fp = cast("IO[bytes]", fp)
2707 try:
2708 save_handler(self, fp, filename)
2709 except Exception:
2710 if open_fp:
2711 fp.close()
2712 if created:
2713 try:
2714 os.remove(filename)
2715 except PermissionError:
2716 pass
2717 raise
2718 finally:
2719 self.encoderinfo = encoderinfo
2720 if open_fp:
2721 fp.close()
2723 def _attach_default_encoderinfo(self, im: Image) -> dict[str, Any]:
2724 encoderinfo = getattr(self, "encoderinfo", {})
2725 self.encoderinfo = {**im._default_encoderinfo, **encoderinfo}
2726 return encoderinfo
2728 def seek(self, frame: int) -> None:
2729 """
2730 Seeks to the given frame in this sequence file. If you seek
2731 beyond the end of the sequence, the method raises an
2732 ``EOFError`` exception. When a sequence file is opened, the
2733 library automatically seeks to frame 0.
2735 See :py:meth:`~PIL.Image.Image.tell`.
2737 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2738 number of available frames.
2740 :param frame: Frame number, starting at 0.
2741 :exception EOFError: If the call attempts to seek beyond the end
2742 of the sequence.
2743 """
2745 # overridden by file handlers
2746 if frame != 0:
2747 msg = "no more images in file"
2748 raise EOFError(msg)
2750 def show(self, title: str | None = None) -> None:
2751 """
2752 Displays this image. This method is mainly intended for debugging purposes.
2754 This method calls :py:func:`PIL.ImageShow.show` internally. You can use
2755 :py:func:`PIL.ImageShow.register` to override its default behaviour.
2757 The image is first saved to a temporary file. By default, it will be in
2758 PNG format.
2760 On Unix, the image is then opened using the **xdg-open**, **display**,
2761 **gm**, **eog** or **xv** utility, depending on which one can be found.
2763 On macOS, the image is opened with the native Preview application.
2765 On Windows, the image is opened with the standard PNG display utility.
2767 :param title: Optional title to use for the image window, where possible.
2768 """
2770 from . import ImageShow
2772 ImageShow.show(self, title)
2774 def split(self) -> tuple[Image, ...]:
2775 """
2776 Split this image into individual bands. This method returns a
2777 tuple of individual image bands from an image. For example,
2778 splitting an "RGB" image creates three new images each
2779 containing a copy of one of the original bands (red, green,
2780 blue).
2782 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel`
2783 method can be more convenient and faster.
2785 :returns: A tuple containing bands.
2786 """
2788 self.load()
2789 if self.im.bands == 1:
2790 return (self.copy(),)
2791 return tuple(map(self._new, self.im.split()))
2793 def getchannel(self, channel: int | str) -> Image:
2794 """
2795 Returns an image containing a single channel of the source image.
2797 :param channel: What channel to return. Could be index
2798 (0 for "R" channel of "RGB") or channel name
2799 ("A" for alpha channel of "RGBA").
2800 :returns: An image in "L" mode.
2802 .. versionadded:: 4.3.0
2803 """
2804 self.load()
2806 if isinstance(channel, str):
2807 try:
2808 channel = self.getbands().index(channel)
2809 except ValueError as e:
2810 msg = f'The image has no channel "{channel}"'
2811 raise ValueError(msg) from e
2813 return self._new(self.im.getband(channel))
2815 def tell(self) -> int:
2816 """
2817 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
2819 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2820 number of available frames.
2822 :returns: Frame number, starting with 0.
2823 """
2824 return 0
2826 def thumbnail(
2827 self,
2828 size: tuple[float, float],
2829 resample: Resampling = Resampling.BICUBIC,
2830 reducing_gap: float | None = 2.0,
2831 ) -> None:
2832 """
2833 Make this image into a thumbnail. This method modifies the
2834 image to contain a thumbnail version of itself, no larger than
2835 the given size. This method calculates an appropriate thumbnail
2836 size to preserve the aspect of the image, calls the
2837 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader
2838 (where applicable), and finally resizes the image.
2840 Note that this function modifies the :py:class:`~PIL.Image.Image`
2841 object in place. If you need to use the full resolution image as well,
2842 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
2843 image.
2845 :param size: The requested size in pixels, as a 2-tuple:
2846 (width, height).
2847 :param resample: Optional resampling filter. This can be one
2848 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2849 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2850 :py:data:`Resampling.BICUBIC`, :py:data:`Resampling.LANCZOS`,
2851 :py:data:`Resampling.MKS2013`, or :py:data:`Resampling.MKS2021`.
2852 If omitted, it defaults to :py:data:`Resampling.BICUBIC`.
2853 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0).
2854 See: :ref:`concept-filters`.
2855 :param reducing_gap: Apply optimization by resizing the image
2856 in two steps. First, reducing the image by integer times
2857 using :py:meth:`~PIL.Image.Image.reduce` or
2858 :py:meth:`~PIL.Image.Image.draft` for JPEG images.
2859 Second, resizing using regular resampling. The last step
2860 changes size no less than by ``reducing_gap`` times.
2861 ``reducing_gap`` may be None (no first step is performed)
2862 or should be greater than 1.0. The bigger ``reducing_gap``,
2863 the closer the result to the fair resampling.
2864 The smaller ``reducing_gap``, the faster resizing.
2865 With ``reducing_gap`` greater or equal to 3.0, the result is
2866 indistinguishable from fair resampling in most cases.
2867 The default value is 2.0 (very close to fair resampling
2868 while still being faster in many cases).
2869 :returns: None
2870 """
2872 provided_size = tuple(map(math.floor, size))
2874 def preserve_aspect_ratio() -> tuple[int, int] | None:
2875 def round_aspect(number: float, key: Callable[[int], float]) -> int:
2876 return max(min(math.floor(number), math.ceil(number), key=key), 1)
2878 x, y = provided_size
2879 if x >= self.width and y >= self.height:
2880 return None
2882 aspect = self.width / self.height
2883 if x / y >= aspect:
2884 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y))
2885 else:
2886 y = round_aspect(
2887 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n)
2888 )
2889 return x, y
2891 preserved_size = preserve_aspect_ratio()
2892 if preserved_size is None:
2893 return
2894 final_size = preserved_size
2896 box = None
2897 if reducing_gap is not None:
2898 res = self.draft(
2899 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
2900 )
2901 if res is not None:
2902 box = res[1]
2904 if self.size != final_size:
2905 im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap)
2907 self.im = im.im
2908 self._size = final_size
2909 self._mode = self.im.mode
2911 self.readonly = 0
2913 # FIXME: the different transform methods need further explanation
2914 # instead of bloating the method docs, add a separate chapter.
2915 def transform(
2916 self,
2917 size: tuple[int, int],
2918 method: Transform | ImageTransformHandler | SupportsGetData,
2919 data: Sequence[Any] | None = None,
2920 resample: int = Resampling.NEAREST,
2921 fill: int = 1,
2922 fillcolor: float | tuple[float, ...] | str | None = None,
2923 ) -> Image:
2924 """
2925 Transforms this image. This method creates a new image with the
2926 given size, and the same mode as the original, and copies data
2927 to the new image using the given transform.
2929 :param size: The output size in pixels, as a 2-tuple:
2930 (width, height).
2931 :param method: The transformation method. This is one of
2932 :py:data:`Transform.EXTENT` (cut out a rectangular subregion),
2933 :py:data:`Transform.AFFINE` (affine transform),
2934 :py:data:`Transform.PERSPECTIVE` (perspective transform),
2935 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or
2936 :py:data:`Transform.MESH` (map a number of source quadrilaterals
2937 in one operation).
2939 It may also be an :py:class:`~PIL.Image.ImageTransformHandler`
2940 object::
2942 class Example(Image.ImageTransformHandler):
2943 def transform(self, size, data, resample, fill=1):
2944 # Return result
2946 Implementations of :py:class:`~PIL.Image.ImageTransformHandler`
2947 for some of the :py:class:`Transform` methods are provided
2948 in :py:mod:`~PIL.ImageTransform`.
2950 It may also be an object with a ``method.getdata`` method
2951 that returns a tuple supplying new ``method`` and ``data`` values::
2953 class Example:
2954 def getdata(self):
2955 method = Image.Transform.EXTENT
2956 data = (0, 0, 100, 100)
2957 return method, data
2958 :param data: Extra data to the transformation method.
2959 :param resample: Optional resampling filter. It can be one of
2960 :py:data:`Resampling.NEAREST` (use nearest neighbour),
2961 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2962 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2963 interpolation in a 4x4 environment). If omitted, or if the image
2964 has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`.
2965 See: :ref:`concept-filters`.
2966 :param fill: If ``method`` is an
2967 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of
2968 the arguments passed to it. Otherwise, it is unused.
2969 :param fillcolor: Optional fill color for the area outside the
2970 transform in the output image.
2971 :returns: An :py:class:`~PIL.Image.Image` object.
2972 """
2974 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST:
2975 return (
2976 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2977 .transform(size, method, data, resample, fill, fillcolor)
2978 .convert(self.mode)
2979 )
2981 if isinstance(method, ImageTransformHandler):
2982 return method.transform(size, self, resample=resample, fill=fill)
2984 if hasattr(method, "getdata"):
2985 # compatibility w. old-style transform objects
2986 method, data = method.getdata()
2988 if data is None:
2989 msg = "missing method data"
2990 raise ValueError(msg)
2992 im = new(self.mode, size, fillcolor)
2993 if self.mode in ("P", "PA") and self.palette:
2994 im.palette = self.palette.copy()
2995 im.info = self._copy_info()
2996 if method == Transform.MESH:
2997 # list of quads
2998 for box, quad in data:
2999 im.__transformer(
3000 box, self, Transform.QUAD, quad, resample, fillcolor is None
3001 )
3002 else:
3003 im.__transformer(
3004 (0, 0, *size), self, method, data, resample, fillcolor is None
3005 )
3007 return im
3009 def __transformer(
3010 self,
3011 box: tuple[int, int, int, int],
3012 image: Image,
3013 method: Transform,
3014 data: Sequence[float],
3015 resample: int = Resampling.NEAREST,
3016 fill: bool = True,
3017 ) -> None:
3018 w = box[2] - box[0]
3019 h = box[3] - box[1]
3021 if method == Transform.AFFINE:
3022 data = data[:6]
3024 elif method == Transform.EXTENT:
3025 # convert extent to an affine transform
3026 x0, y0, x1, y1 = data
3027 xs = (x1 - x0) / w
3028 ys = (y1 - y0) / h
3029 method = Transform.AFFINE
3030 data = (xs, 0, x0, 0, ys, y0)
3032 elif method == Transform.PERSPECTIVE:
3033 data = data[:8]
3035 elif method == Transform.QUAD:
3036 # quadrilateral warp. data specifies the four corners
3037 # given as NW, SW, SE, and NE.
3038 nw = data[:2]
3039 sw = data[2:4]
3040 se = data[4:6]
3041 ne = data[6:8]
3042 x0, y0 = nw
3043 As = 1.0 / w
3044 At = 1.0 / h
3045 data = (
3046 x0,
3047 (ne[0] - x0) * As,
3048 (sw[0] - x0) * At,
3049 (se[0] - sw[0] - ne[0] + x0) * As * At,
3050 y0,
3051 (ne[1] - y0) * As,
3052 (sw[1] - y0) * At,
3053 (se[1] - sw[1] - ne[1] + y0) * As * At,
3054 )
3056 else:
3057 msg = "unknown transformation method"
3058 raise ValueError(msg)
3060 if resample not in (
3061 Resampling.NEAREST,
3062 Resampling.BILINEAR,
3063 Resampling.BICUBIC,
3064 ):
3065 if resample in (
3066 Resampling.BOX,
3067 Resampling.HAMMING,
3068 Resampling.LANCZOS,
3069 Resampling.MKS2013,
3070 Resampling.MKS2021,
3071 ):
3072 unusable: dict[int, str] = {
3073 Resampling.BOX: "Image.Resampling.BOX",
3074 Resampling.HAMMING: "Image.Resampling.HAMMING",
3075 Resampling.LANCZOS: "Image.Resampling.LANCZOS",
3076 Resampling.MKS2013: "Image.Resampling.MKS2013",
3077 Resampling.MKS2021: "Image.Resampling.MKS2021",
3078 }
3079 msg = unusable[resample] + f" ({resample}) cannot be used."
3080 else:
3081 msg = f"Unknown resampling filter ({resample})."
3083 filters = [
3084 f"{filter[1]} ({filter[0]})"
3085 for filter in (
3086 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
3087 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
3088 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
3089 )
3090 ]
3091 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
3092 raise ValueError(msg)
3094 image.load()
3096 self.load()
3098 if image.mode in ("1", "P"):
3099 resample = Resampling.NEAREST
3101 self.im.transform(box, image.im, method, data, resample, fill)
3103 def transpose(self, method: Transpose) -> Image:
3104 """
3105 Transpose image (flip or rotate in 90 degree steps)
3107 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`,
3108 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`,
3109 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`,
3110 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`.
3111 :returns: Returns a flipped or rotated copy of this image.
3112 """
3114 self.load()
3115 return self._new(self.im.transpose(method))
3117 def effect_spread(self, distance: int) -> Image:
3118 """
3119 Randomly spread pixels in an image.
3121 :param distance: Distance to spread pixels.
3122 """
3123 self.load()
3124 return self._new(self.im.effect_spread(distance))
3126 def toqimage(self) -> ImageQt.ImageQt:
3127 """Returns a QImage copy of this image"""
3128 from . import ImageQt
3130 if not ImageQt.qt_is_installed:
3131 msg = "Qt bindings are not installed"
3132 raise ImportError(msg)
3133 return ImageQt.toqimage(self)
3135 def toqpixmap(self) -> ImageQt.QPixmap:
3136 """Returns a QPixmap copy of this image"""
3137 from . import ImageQt
3139 if not ImageQt.qt_is_installed:
3140 msg = "Qt bindings are not installed"
3141 raise ImportError(msg)
3142 return ImageQt.toqpixmap(self)
3145# --------------------------------------------------------------------
3146# Abstract handlers.
3149class ImagePointHandler(abc.ABC):
3150 """
3151 Used as a mixin by point transforms
3152 (for use with :py:meth:`~PIL.Image.Image.point`)
3153 """
3155 @abc.abstractmethod
3156 def point(self, im: Image) -> Image:
3157 pass
3160class ImageTransformHandler(abc.ABC):
3161 """
3162 Used as a mixin by geometry transforms
3163 (for use with :py:meth:`~PIL.Image.Image.transform`)
3164 """
3166 @abc.abstractmethod
3167 def transform(
3168 self,
3169 size: tuple[int, int],
3170 image: Image,
3171 **options: Any,
3172 ) -> Image:
3173 pass
3176# --------------------------------------------------------------------
3177# Factories
3180def _check_size(size: Any) -> None:
3181 """
3182 Common check to enforce type and sanity check on size tuples
3184 :param size: Should be a 2 tuple of (width, height)
3185 :returns: None, or raises a ValueError
3186 """
3188 if not isinstance(size, (list, tuple)):
3189 msg = "Size must be a list or tuple"
3190 raise ValueError(msg)
3191 if len(size) != 2:
3192 msg = "Size must be a sequence of length 2"
3193 raise ValueError(msg)
3194 if size[0] < 0 or size[1] < 0:
3195 msg = "Width and height must be >= 0"
3196 raise ValueError(msg)
3199def new(
3200 mode: str,
3201 size: tuple[int, int] | list[int],
3202 color: float | tuple[float, ...] | str | None = 0,
3203) -> Image:
3204 """
3205 Creates a new image with the given mode and size.
3207 :param mode: The mode to use for the new image. See: :ref:`concept-modes`.
3208 :param size: A 2-tuple, containing (width, height) in pixels.
3209 :param color: What color to use for the image. If given, this should be a single
3210 integer or floating point value for single-band modes, and a tuple for
3211 multi-band modes (one value per band). When creating RGB or HSV images, you can
3212 also use color strings as supported by the ImageColor module. See :ref:`colors`
3213 for more information. The default color is zero, which appears as black in
3214 single band or RGB-based images. ``None`` is also treated as zero.
3215 :returns: An :py:class:`~PIL.Image.Image` object.
3216 """
3218 _check_size(size)
3220 if color is None:
3221 # core.new() returns zeroed memory, so there is nothing to fill
3222 return Image()._new(core.new(mode, size))
3224 if isinstance(color, str):
3225 # css3-style specifier
3227 from . import ImageColor
3229 color = ImageColor.getcolor(color, mode)
3231 im = Image()
3232 if (
3233 mode == "P"
3234 and isinstance(color, (list, tuple))
3235 and all(isinstance(i, int) for i in color)
3236 ):
3237 color_ints: tuple[int, ...] = cast("tuple[int, ...]", tuple(color))
3238 if len(color_ints) == 3 or len(color_ints) == 4:
3239 # RGB or RGBA value for a P image
3240 from . import ImagePalette
3242 im.palette = ImagePalette.ImagePalette()
3243 color = im.palette.getcolor(color_ints)
3244 return im._new(core.fill(mode, size, color))
3247def frombytes(
3248 mode: str,
3249 size: tuple[int, int],
3250 data: DecoderInput,
3251 decoder_name: str = "raw",
3252 *args: Any,
3253) -> Image:
3254 """
3255 Creates a copy of an image memory from pixel data in a buffer.
3257 In its simplest form, this function takes three arguments
3258 (mode, size, and unpacked pixel data).
3260 You can also use any pixel decoder supported by PIL. For more
3261 information on available decoders, see the section
3262 :ref:`Writing Your Own File Codec <file-codecs>`.
3264 Note that this function decodes pixel data only, not entire images.
3265 If you have an entire image in a string, wrap it in a
3266 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load
3267 it.
3269 :param mode: The image mode. See: :ref:`concept-modes`.
3270 :param size: The image size.
3271 :param data: A byte buffer containing raw data for the given mode.
3272 :param decoder_name: What decoder to use.
3273 :param args: Additional parameters for the given decoder.
3274 :returns: An :py:class:`~PIL.Image.Image` object.
3275 """
3277 _check_size(size)
3279 im = new(mode, size)
3280 if im.width != 0 and im.height != 0:
3281 decoder_args: Any = args
3282 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
3283 # may pass tuple instead of argument list
3284 decoder_args = decoder_args[0]
3286 if decoder_name == "raw" and decoder_args == ():
3287 decoder_args = mode
3289 im.frombytes(data, decoder_name, decoder_args)
3290 return im
3293def frombuffer(
3294 mode: str,
3295 size: tuple[int, int],
3296 data: bytes | SupportsArrayInterface,
3297 decoder_name: str = "raw",
3298 *args: Any,
3299) -> Image:
3300 """
3301 Creates an image memory referencing pixel data in a byte buffer.
3303 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data
3304 in the byte buffer, where possible. This means that changes to the
3305 original buffer object are reflected in this image). Not all modes can
3306 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK".
3308 Note that this function decodes pixel data only, not entire images.
3309 If you have an entire image file in a string, wrap it in a
3310 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it.
3312 The default parameters used for the "raw" decoder differs from that used for
3313 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a
3314 future release. The current release issues a warning if you do this; to disable
3315 the warning, you should provide the full set of parameters. See below for details.
3317 :param mode: The image mode. See: :ref:`concept-modes`.
3318 :param size: The image size.
3319 :param data: A bytes or other buffer object containing raw
3320 data for the given mode.
3321 :param decoder_name: What decoder to use.
3322 :param args: Additional parameters for the given decoder. For the
3323 default encoder ("raw"), it's recommended that you provide the
3324 full set of parameters::
3326 frombuffer(mode, size, data, "raw", mode, 0, 1)
3328 :returns: An :py:class:`~PIL.Image.Image` object.
3330 .. versionadded:: 1.1.4
3331 """
3333 _check_size(size)
3335 # may pass tuple instead of argument list
3336 if len(args) == 1 and isinstance(args[0], tuple):
3337 args = args[0]
3339 if decoder_name == "raw":
3340 if args == ():
3341 args = mode, 0, 1
3342 if args[0] in _MAPMODES:
3343 im = new(mode, (0, 0))
3344 im = im._new(core.map_buffer(data, size, decoder_name, 0, args))
3345 if mode == "P":
3346 from . import ImagePalette
3348 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB"))
3349 im.readonly = 1
3350 return im
3352 return frombytes(mode, size, data, decoder_name, args)
3355class SupportsArrayInterface(Protocol):
3356 """
3357 An object that has an ``__array_interface__`` dictionary.
3358 """
3360 @property
3361 def __array_interface__(self) -> dict[str, Any]:
3362 raise NotImplementedError()
3364 def __len__(self) -> int:
3365 raise NotImplementedError()
3368DecoderInput = bytes | bytearray | memoryview | SupportsArrayInterface
3371class SupportsArrowArrayInterface(Protocol):
3372 """
3373 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c
3374 data interface.
3375 """
3377 def __arrow_c_array__(
3378 self, requested_schema: PyCapsule = None # type: ignore[name-defined] # noqa: F821
3379 ) -> tuple[PyCapsule, PyCapsule]: # type: ignore[name-defined] # noqa: F821
3380 raise NotImplementedError()
3383def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
3384 """
3385 Creates an image memory from an object exporting the array interface
3386 (using the buffer protocol)::
3388 from PIL import Image
3389 import numpy as np
3390 a = np.zeros((5, 5))
3391 im = Image.fromarray(a)
3393 If ``obj`` is not contiguous, then the ``tobytes`` method is called
3394 and :py:func:`~PIL.Image.frombuffer` is used.
3396 In the case of NumPy, be aware that Pillow modes do not always correspond
3397 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels,
3398 32-bit signed integer pixels, and 32-bit floating point pixels.
3400 Pillow images can also be converted to arrays::
3402 from PIL import Image
3403 import numpy as np
3404 im = Image.open("hopper.jpg")
3405 a = np.asarray(im)
3407 When converting Pillow images to arrays however, only pixel values are
3408 transferred. This means that P and PA mode images will lose their palette.
3410 :param obj: Object with array interface
3411 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not
3412 contain information about palettes or color spaces, this can be used to place
3413 grayscale L mode data within a P mode image, or read RGB data as YCbCr for
3414 example.
3416 See: :ref:`concept-modes` for general information about modes.
3417 :returns: An image object.
3419 .. versionadded:: 1.1.6
3420 """
3421 arr = obj.__array_interface__
3422 shape = arr["shape"]
3423 ndim = len(shape)
3424 strides = arr.get("strides", None)
3425 try:
3426 typekey = (1, 1) + shape[2:], arr["typestr"]
3427 except KeyError as e:
3428 if mode is not None:
3429 typekey = None
3430 color_modes: list[str] = []
3431 else:
3432 msg = "Cannot handle this data type"
3433 raise TypeError(msg) from e
3434 if typekey is not None:
3435 try:
3436 typemode, rawmode, color_modes = _fromarray_typemap[typekey]
3437 except KeyError as e:
3438 typekey_shape, typestr = typekey
3439 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}"
3440 raise TypeError(msg) from e
3441 if mode is not None:
3442 if mode != typemode and mode not in color_modes:
3443 msg = "Invalid mode for data type"
3444 raise ValueError(msg)
3445 rawmode = mode
3446 else:
3447 mode = typemode
3448 if mode in ["1", "L", "I", "P", "F"]:
3449 ndmax = 2
3450 elif mode == "RGB":
3451 ndmax = 3
3452 else:
3453 ndmax = 4
3454 if ndim > ndmax:
3455 msg = f"Too many dimensions: {ndim} > {ndmax}."
3456 raise ValueError(msg)
3458 size = 1 if ndim == 1 else shape[1], shape[0]
3459 if strides is not None:
3460 if hasattr(obj, "tobytes"):
3461 obj = obj.tobytes()
3462 elif hasattr(obj, "tostring"):
3463 obj = obj.tostring()
3464 else:
3465 msg = "'strides' requires either tobytes() or tostring()"
3466 raise ValueError(msg)
3468 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
3471def fromarrow(
3472 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int]
3473) -> Image:
3474 """Creates an image with zero-copy shared memory from an object exporting
3475 the arrow_c_array interface protocol::
3477 from PIL import Image
3478 import pyarrow as pa
3479 arr = pa.array([0]*(5*5*4), type=pa.uint8())
3480 im = Image.fromarrow(arr, 'RGBA', (5, 5))
3482 If the data representation of the ``obj`` is not compatible with
3483 Pillow internal storage, a ValueError is raised.
3485 Pillow images can also be converted to Arrow objects::
3487 from PIL import Image
3488 import pyarrow as pa
3489 im = Image.open('hopper.jpg')
3490 arr = pa.array(im)
3492 As with array support, when converting Pillow images to arrays,
3493 only pixel values are transferred. This means that P and PA mode
3494 images will lose their palette.
3496 :param obj: Object with an arrow_c_array interface
3497 :param mode: Image mode.
3498 :param size: Image size. This must match the storage of the arrow object.
3499 :returns: An Image object
3501 Note that according to the Arrow spec, both the producer and the
3502 consumer should consider the exported array to be immutable, as
3503 unsynchronized updates will potentially cause inconsistent data.
3505 See: :ref:`arrow-support` for more detailed information
3507 .. versionadded:: 11.2.1
3509 """
3510 if not hasattr(obj, "__arrow_c_array__"):
3511 msg = "arrow_c_array interface not found"
3512 raise ValueError(msg)
3514 schema_capsule, array_capsule = obj.__arrow_c_array__()
3515 _im = core.new_arrow(mode, size, schema_capsule, array_capsule)
3516 if _im:
3517 return Image()._new(_im)
3519 msg = "new_arrow returned None without an exception"
3520 raise ValueError(msg)
3523def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile:
3524 """Creates an image instance from a QImage image"""
3525 from . import ImageQt
3527 if not ImageQt.qt_is_installed:
3528 msg = "Qt bindings are not installed"
3529 raise ImportError(msg)
3530 return ImageQt.fromqimage(im)
3533def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile:
3534 """Creates an image instance from a QPixmap image"""
3535 from . import ImageQt
3537 if not ImageQt.qt_is_installed:
3538 msg = "Qt bindings are not installed"
3539 raise ImportError(msg)
3540 return ImageQt.fromqpixmap(im)
3543_fromarray_typemap = {
3544 # (shape, typestr) => mode, rawmode, color modes
3545 # first two members of shape are set to one
3546 ((1, 1), "|b1"): ("1", "1;8", []),
3547 ((1, 1), "|u1"): ("L", "L", ["P"]),
3548 ((1, 1), "|i1"): ("I", "I;8", []),
3549 ((1, 1), "<u2"): ("I", "I;16", []),
3550 ((1, 1), ">u2"): ("I", "I;16B", []),
3551 ((1, 1), "<i2"): ("I", "I;16S", []),
3552 ((1, 1), ">i2"): ("I", "I;16BS", []),
3553 ((1, 1), "<u4"): ("I", "I;32", []),
3554 ((1, 1), ">u4"): ("I", "I;32B", []),
3555 ((1, 1), "<i4"): ("I", "I;32S", []),
3556 ((1, 1), ">i4"): ("I", "I;32BS", []),
3557 ((1, 1), "<f4"): ("F", "F;32F", []),
3558 ((1, 1), ">f4"): ("F", "F;32BF", []),
3559 ((1, 1), "<f8"): ("F", "F;64F", []),
3560 ((1, 1), ">f8"): ("F", "F;64BF", []),
3561 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]),
3562 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]),
3563 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]),
3564 # shortcuts:
3565 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []),
3566 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []),
3567}
3570def _decompression_bomb_check(size: tuple[int, int]) -> None:
3571 if MAX_IMAGE_PIXELS is None:
3572 return
3574 pixels = max(1, size[0]) * max(1, size[1])
3576 if pixels > 2 * MAX_IMAGE_PIXELS:
3577 msg = (
3578 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} "
3579 "pixels, could be decompression bomb DOS attack."
3580 )
3581 raise DecompressionBombError(msg)
3583 if pixels > MAX_IMAGE_PIXELS:
3584 warnings.warn(
3585 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, "
3586 "could be decompression bomb DOS attack.",
3587 DecompressionBombWarning,
3588 )
3591def open(
3592 fp: StrOrBytesPath | IO[bytes],
3593 mode: Literal["r"] = "r",
3594 formats: list[str] | tuple[str, ...] | None = None,
3595) -> ImageFile.ImageFile:
3596 """
3597 Opens and identifies the given image file.
3599 This is a lazy operation; this function identifies the file, but
3600 the file remains open and the actual image data is not read from
3601 the file until you try to process the data (or call the
3602 :py:meth:`~PIL.Image.Image.load` method). See
3603 :py:func:`~PIL.Image.new`. See :ref:`file-handling`.
3605 :param fp: A filename (string), os.PathLike object or a file object.
3606 The file object must implement ``file.read``,
3607 ``file.seek``, and ``file.tell`` methods,
3608 and be opened in binary mode. The file object will also seek to zero
3609 before reading.
3610 :param mode: The mode. If given, this argument must be "r".
3611 :param formats: A list or tuple of formats to attempt to load the file in.
3612 This can be used to restrict the set of formats checked.
3613 Pass ``None`` to try all supported formats. You can print the set of
3614 available formats by running ``python3 -m PIL`` or using
3615 the :py:func:`PIL.features.pilinfo` function.
3616 :returns: An :py:class:`~PIL.Image.Image` object.
3617 :exception FileNotFoundError: If the file cannot be found.
3618 :exception PIL.UnidentifiedImageError: If the image cannot be opened and
3619 identified.
3620 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO``
3621 instance is used for ``fp``.
3622 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple.
3623 """
3625 if mode != "r":
3626 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
3627 raise ValueError(msg)
3628 elif isinstance(fp, io.StringIO):
3629 msg = ( # type: ignore[unreachable]
3630 "StringIO cannot be used to open an image. "
3631 "Binary data must be used instead."
3632 )
3633 raise ValueError(msg)
3635 if formats is None:
3636 formats = ID
3637 elif not isinstance(formats, (list, tuple)):
3638 msg = "formats must be a list or tuple" # type: ignore[unreachable]
3639 raise TypeError(msg)
3641 exclusive_fp = False
3642 filename: str | bytes = ""
3643 if is_path(fp):
3644 filename = os.fspath(fp)
3645 fp = builtins.open(filename, "rb")
3646 exclusive_fp = True
3647 else:
3648 fp = cast("IO[bytes]", fp)
3650 try:
3651 fp.seek(0)
3652 except (AttributeError, io.UnsupportedOperation):
3653 fp = io.BytesIO(fp.read())
3654 exclusive_fp = True
3656 prefix = fp.read(16)
3658 # Try to import just the plugin needed for this file extension
3659 # before falling back to preinit() which imports common plugins
3660 ext = os.path.splitext(filename)[1] if filename else ""
3661 if not _import_plugin_for_extension(ext):
3662 preinit()
3664 warning_messages: list[str] = []
3666 def _open_core(
3667 fp: IO[bytes],
3668 filename: str | bytes,
3669 prefix: bytes,
3670 formats: list[str] | tuple[str, ...],
3671 ) -> ImageFile.ImageFile | None:
3672 for i in formats:
3673 i = i.upper()
3674 if i not in OPEN:
3675 init()
3676 try:
3677 factory, accept = OPEN[i]
3678 result = not accept or accept(prefix)
3679 if isinstance(result, str):
3680 warning_messages.append(result)
3681 elif result:
3682 fp.seek(0)
3683 im = factory(fp, filename)
3684 _decompression_bomb_check(im.size)
3685 return im
3686 except (SyntaxError, IndexError, TypeError, struct.error) as e:
3687 if WARN_POSSIBLE_FORMATS:
3688 warning_messages.append(i + " opening failed. " + str(e))
3689 except BaseException:
3690 if exclusive_fp:
3691 fp.close()
3692 raise
3693 return None
3695 im = _open_core(fp, filename, prefix, formats)
3697 if im is None and formats is ID:
3698 # Try preinit (few common plugins) then init (all plugins)
3699 for loader in (preinit, init):
3700 checked_formats = ID.copy()
3701 loader()
3702 if formats != checked_formats:
3703 im = _open_core(
3704 fp,
3705 filename,
3706 prefix,
3707 tuple(f for f in formats if f not in checked_formats),
3708 )
3709 if im is not None:
3710 break
3712 if im:
3713 im._exclusive_fp = exclusive_fp
3714 return im
3716 if exclusive_fp:
3717 fp.close()
3718 for message in warning_messages:
3719 warnings.warn(message)
3720 msg = "cannot identify image file %r" % (filename if filename else fp)
3721 raise UnidentifiedImageError(msg)
3724#
3725# Image processing.
3728def alpha_composite(im1: Image, im2: Image) -> Image:
3729 """
3730 Alpha composite im2 over im1.
3732 :param im1: The first image. Must have mode RGBA or LA.
3733 :param im2: The second image. Must have the same mode and size as the first image.
3734 :returns: An :py:class:`~PIL.Image.Image` object.
3735 """
3737 im1.load()
3738 im2.load()
3739 return im1._new(core.alpha_composite(im1.im, im2.im))
3742def blend(im1: Image, im2: Image, alpha: float) -> Image:
3743 """
3744 Creates a new image by interpolating between two input images, using
3745 a constant alpha::
3747 out = image1 * (1.0 - alpha) + image2 * alpha
3749 :param im1: The first image.
3750 :param im2: The second image. Must have the same mode and size as
3751 the first image.
3752 :param alpha: The interpolation alpha factor. If alpha is 0.0, a
3753 copy of the first image is returned. If alpha is 1.0, a copy of
3754 the second image is returned. There are no restrictions on the
3755 alpha value. If necessary, the result is clipped to fit into
3756 the allowed output range.
3757 :returns: An :py:class:`~PIL.Image.Image` object.
3758 """
3760 im1.load()
3761 im2.load()
3762 return im1._new(core.blend(im1.im, im2.im, alpha))
3765def composite(image1: Image, image2: Image, mask: Image) -> Image:
3766 """
3767 Create composite image by blending images using a transparency mask.
3769 :param image1: The first image.
3770 :param image2: The second image. Must have the same mode and
3771 size as the first image.
3772 :param mask: A mask image. This image can have mode
3773 "1", "L", or "RGBA", and must have the same size as the
3774 other two images.
3775 """
3777 image = image2.copy()
3778 image.paste(image1, None, mask)
3779 return image
3782def eval(image: Image, *args: Callable[[int], float]) -> Image:
3783 """
3784 Applies the function (which should take one argument) to each pixel
3785 in the given image. If the image has more than one band, the same
3786 function is applied to each band. Note that the function is
3787 evaluated once for each possible pixel value, so you cannot use
3788 random components or other generators.
3790 :param image: The input image.
3791 :param function: A function object, taking one integer argument.
3792 :returns: An :py:class:`~PIL.Image.Image` object.
3793 """
3795 return image.point(args[0])
3798def merge(mode: str, bands: Sequence[Image]) -> Image:
3799 """
3800 Merge a set of single band images into a new multiband image.
3802 :param mode: The mode to use for the output image. See:
3803 :ref:`concept-modes`.
3804 :param bands: A sequence containing one single-band image for
3805 each band in the output image. All bands must have the
3806 same size.
3807 :returns: An :py:class:`~PIL.Image.Image` object.
3808 """
3810 if getmodebands(mode) != len(bands):
3811 msg = "wrong number of bands"
3812 raise ValueError(msg)
3813 for band in bands[1:]:
3814 if band.mode != getmodetype(mode):
3815 msg = "mode mismatch"
3816 raise ValueError(msg)
3817 if band.size != bands[0].size:
3818 msg = "size mismatch"
3819 raise ValueError(msg)
3820 for band in bands:
3821 band.load()
3822 return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
3825# --------------------------------------------------------------------
3826# Plugin registry
3829def register_open(
3830 id: str,
3831 factory: (
3832 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile]
3833 | type[ImageFile.ImageFile]
3834 ),
3835 accept: Callable[[bytes], bool | str] | None = None,
3836) -> None:
3837 """
3838 Register an image file plugin. This function should not be used
3839 in application code.
3841 :param id: An image format identifier.
3842 :param factory: An image file factory method.
3843 :param accept: An optional function that can be used to quickly
3844 reject images having another format.
3845 """
3846 id = id.upper()
3847 if id not in ID:
3848 ID.append(id)
3849 OPEN[id] = factory, accept
3852def register_mime(id: str, mimetype: str) -> None:
3853 """
3854 Registers an image MIME type by populating ``Image.MIME``. This function
3855 should not be used in application code.
3857 ``Image.MIME`` provides a mapping from image format identifiers to mime
3858 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can
3859 provide a different result for specific images.
3861 :param id: An image format identifier.
3862 :param mimetype: The image MIME type for this format.
3863 """
3864 MIME[id.upper()] = mimetype
3867def register_save(
3868 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3869) -> None:
3870 """
3871 Registers an image save function. This function should not be
3872 used in application code.
3874 :param id: An image format identifier.
3875 :param driver: A function to save images in this format.
3876 """
3877 SAVE[id.upper()] = driver
3880def register_save_all(
3881 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3882) -> None:
3883 """
3884 Registers an image function to save all the frames
3885 of a multiframe format. This function should not be
3886 used in application code.
3888 :param id: An image format identifier.
3889 :param driver: A function to save images in this format.
3890 """
3891 SAVE_ALL[id.upper()] = driver
3894def register_extension(id: str, extension: str) -> None:
3895 """
3896 Registers an image extension. This function should not be
3897 used in application code.
3899 :param id: An image format identifier.
3900 :param extension: An extension used for this format.
3901 """
3902 EXTENSION[extension.lower()] = id.upper()
3905def register_extensions(id: str, extensions: list[str]) -> None:
3906 """
3907 Registers image extensions. This function should not be
3908 used in application code.
3910 :param id: An image format identifier.
3911 :param extensions: A list of extensions used for this format.
3912 """
3913 for extension in extensions:
3914 register_extension(id, extension)
3917def registered_extensions() -> dict[str, str]:
3918 """
3919 Returns a dictionary containing all file extensions belonging
3920 to registered plugins
3921 """
3922 init()
3923 return EXTENSION
3926def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None:
3927 """
3928 Registers an image decoder. This function should not be
3929 used in application code.
3931 :param name: The name of the decoder
3932 :param decoder: An ImageFile.PyDecoder object
3934 .. versionadded:: 4.1.0
3935 """
3936 DECODERS[name] = decoder
3939def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None:
3940 """
3941 Registers an image encoder. This function should not be
3942 used in application code.
3944 :param name: The name of the encoder
3945 :param encoder: An ImageFile.PyEncoder object
3947 .. versionadded:: 4.1.0
3948 """
3949 ENCODERS[name] = encoder
3952# --------------------------------------------------------------------
3953# Effects
3956def effect_mandelbrot(
3957 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int
3958) -> Image:
3959 """
3960 Generate a Mandelbrot set covering the given extent.
3962 :param size: The requested size in pixels, as a 2-tuple:
3963 (width, height).
3964 :param extent: The extent to cover, as a 4-tuple:
3965 (x0, y0, x1, y1).
3966 :param quality: Quality.
3967 """
3968 return Image()._new(core.effect_mandelbrot(size, extent, quality))
3971def effect_noise(size: tuple[int, int], sigma: float) -> Image:
3972 """
3973 Generate Gaussian noise centered around 128.
3975 :param size: The requested size in pixels, as a 2-tuple:
3976 (width, height).
3977 :param sigma: Standard deviation of noise.
3978 """
3979 return Image()._new(core.effect_noise(size, sigma))
3982def linear_gradient(mode: str) -> Image:
3983 """
3984 Generate 256x256 linear gradient from black to white, top to bottom.
3986 :param mode: Input mode.
3987 """
3988 return Image()._new(core.linear_gradient(mode))
3991def radial_gradient(mode: str) -> Image:
3992 """
3993 Generate 256x256 radial gradient from black to white, centre to edge.
3995 :param mode: Input mode.
3996 """
3997 return Image()._new(core.radial_gradient(mode))
4000# --------------------------------------------------------------------
4001# Resources
4004def _apply_env_variables(env: dict[str, str] | None = None) -> None:
4005 env_dict = env if env is not None else os.environ
4007 for var_name, setter in [
4008 ("PILLOW_ALIGNMENT", core.set_alignment),
4009 ("PILLOW_BLOCK_SIZE", core.set_block_size),
4010 ("PILLOW_BLOCKS_MAX", core.set_blocks_max),
4011 ]:
4012 if var_name not in env_dict:
4013 continue
4015 var = env_dict[var_name].lower()
4017 units = 1
4018 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]:
4019 if var.endswith(postfix):
4020 units = mul
4021 var = var[: -len(postfix)]
4023 try:
4024 var_int = int(var) * units
4025 except ValueError:
4026 warnings.warn(f"{var_name} is not int")
4027 continue
4029 try:
4030 setter(var_int)
4031 except ValueError as e:
4032 warnings.warn(f"{var_name}: {e}")
4035_apply_env_variables()
4036atexit.register(core.clear_cache)
4039if TYPE_CHECKING:
4040 _ExifBase = MutableMapping[int, Any]
4041else:
4042 _ExifBase = MutableMapping
4045class Exif(_ExifBase):
4046 """
4047 This class provides read and write access to EXIF image data::
4049 from PIL import Image
4050 im = Image.open("exif.png")
4051 exif = im.getexif() # Returns an instance of this class
4053 Information can be read and written, iterated over or deleted::
4055 print(exif[274]) # 1
4056 exif[274] = 2
4057 for k, v in exif.items():
4058 print("Tag", k, "Value", v) # Tag 274 Value 2
4059 del exif[274]
4061 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd`
4062 returns a dictionary::
4064 from PIL import ExifTags
4065 im = Image.open("exif_gps.jpg")
4066 exif = im.getexif()
4067 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo)
4068 print(gps_ifd)
4070 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``,
4071 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``.
4073 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data::
4075 print(exif[ExifTags.Base.Software]) # PIL
4076 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99
4077 """
4079 endian: str | None = None
4080 bigtiff = False
4081 _loaded = False
4083 def __init__(self) -> None:
4084 self._data: dict[int, Any] = {}
4085 self._hidden_data: dict[int, Any] = {}
4086 self._ifds: dict[int, dict[int, Any]] = {}
4087 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None
4088 self._loaded_exif: bytes | None = None
4090 def _fixup(self, value: Any) -> Any:
4091 try:
4092 if len(value) == 1 and isinstance(value, tuple):
4093 return value[0]
4094 except Exception:
4095 pass
4096 return value
4098 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]:
4099 # Helper function
4100 # returns a dict with any single item tuples/lists as individual values
4101 return {k: self._fixup(v) for k, v in src_dict.items()}
4103 def _get_ifd_dict(
4104 self, offset: int, group: int | None = None
4105 ) -> dict[int, Any] | None:
4106 try:
4107 # an offset pointer to the location of the nested embedded IFD.
4108 # It should be a long, but may be corrupted.
4109 self.fp.seek(offset)
4110 except (KeyError, TypeError):
4111 return None
4112 else:
4113 from . import TiffImagePlugin
4115 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group)
4116 info.load(self.fp)
4117 return self._fixup_dict(dict(info))
4119 def _get_head(self) -> bytes:
4120 version = b"\x2b" if self.bigtiff else b"\x2a"
4121 if self.endian == "<":
4122 head = b"II" + version + b"\x00" + o32le(8)
4123 else:
4124 head = b"MM\x00" + version + o32be(8)
4125 if self.bigtiff:
4126 head += o32le(8) if self.endian == "<" else o32be(8)
4127 head += b"\x00\x00\x00\x00"
4128 return head
4130 def load(self, data: bytes) -> None:
4131 # Extract EXIF information. This is highly experimental,
4132 # and is likely to be replaced with something better in a future
4133 # version.
4135 # The EXIF record consists of a TIFF file embedded in a JPEG
4136 # application marker (!).
4137 if data == self._loaded_exif:
4138 return
4139 self._loaded_exif = data
4140 self._data.clear()
4141 self._hidden_data.clear()
4142 self._ifds.clear()
4143 while data and data.startswith(b"Exif\x00\x00"):
4144 data = data[6:]
4145 if not data:
4146 self._info = None
4147 return
4149 self.fp: IO[bytes] = io.BytesIO(data)
4150 self.head = self.fp.read(8)
4151 # process dictionary
4152 from . import TiffImagePlugin
4154 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4155 self.endian = self._info._endian
4156 self.fp.seek(self._info.next)
4157 self._info.load(self.fp)
4159 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None:
4160 self._loaded_exif = None
4161 self._data.clear()
4162 self._hidden_data.clear()
4163 self._ifds.clear()
4165 # process dictionary
4166 from . import TiffImagePlugin
4168 self.fp = fp
4169 if offset is not None:
4170 self.head = self._get_head()
4171 else:
4172 self.head = self.fp.read(8)
4173 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4174 if self.endian is None:
4175 self.endian = self._info._endian
4176 if offset is None:
4177 offset = self._info.next
4178 self.fp.tell()
4179 self.fp.seek(offset)
4180 self._info.load(self.fp)
4182 def _get_merged_dict(self) -> dict[int, Any]:
4183 merged_dict = dict(self)
4185 # get EXIF extension
4186 if ExifTags.IFD.Exif in self:
4187 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif)
4188 if ifd:
4189 merged_dict.update(ifd)
4191 # GPS
4192 if ExifTags.IFD.GPSInfo in self:
4193 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict(
4194 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo
4195 )
4197 return merged_dict
4199 def tobytes(self, offset: int = 8) -> bytes:
4200 from . import TiffImagePlugin
4202 head = self._get_head()
4203 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head)
4204 for tag, ifd_dict in self._ifds.items():
4205 if tag not in self:
4206 ifd[tag] = ifd_dict
4207 for tag, value in self.items():
4208 if tag in [
4209 ExifTags.IFD.Exif,
4210 ExifTags.IFD.GPSInfo,
4211 ] and not isinstance(value, dict):
4212 value = self.get_ifd(tag)
4213 if (
4214 tag == ExifTags.IFD.Exif
4215 and ExifTags.IFD.Interop in value
4216 and not isinstance(value[ExifTags.IFD.Interop], dict)
4217 ):
4218 value = value.copy()
4219 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop)
4220 ifd[tag] = value
4221 return b"Exif\x00\x00" + head + ifd.tobytes(offset)
4223 def get_ifd(self, tag: int) -> dict[int, Any]:
4224 if tag not in self._ifds:
4225 if tag == ExifTags.IFD.IFD1:
4226 if self._info is not None and self._info.next != 0:
4227 ifd = self._get_ifd_dict(self._info.next)
4228 if ifd is not None:
4229 self._ifds[tag] = ifd
4230 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
4231 offset = self._hidden_data.get(tag, self.get(tag))
4232 if offset is not None:
4233 ifd = self._get_ifd_dict(offset, tag)
4234 if ifd is not None:
4235 self._ifds[tag] = ifd
4236 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]:
4237 if ExifTags.IFD.Exif not in self._ifds:
4238 self.get_ifd(ExifTags.IFD.Exif)
4239 tag_data = self._ifds[ExifTags.IFD.Exif][tag]
4240 if tag == ExifTags.IFD.MakerNote:
4241 from .TiffImagePlugin import ImageFileDirectory_v2
4243 try:
4244 if tag_data.startswith(b"FUJIFILM"):
4245 ifd_offset = i32le(tag_data, 8)
4246 ifd_data = tag_data[ifd_offset:]
4248 makernote = {}
4249 for i in range(struct.unpack("<H", ifd_data[:2])[0]):
4250 ifd_tag, typ, count, data = struct.unpack(
4251 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
4252 )
4253 try:
4254 (
4255 unit_size,
4256 handler,
4257 ) = ImageFileDirectory_v2._load_dispatch[typ]
4258 except KeyError:
4259 continue
4260 size = count * unit_size
4261 if size > 4:
4262 (offset,) = struct.unpack("<L", data)
4263 data = ifd_data[offset - 12 : offset + size - 12]
4264 else:
4265 data = data[:size]
4267 if len(data) != size:
4268 warnings.warn(
4269 "Possibly corrupt EXIF MakerNote data. "
4270 f"Expecting to read {size} bytes but only got "
4271 f"{len(data)}. Skipping tag {ifd_tag}"
4272 )
4273 continue
4275 if not data:
4276 continue
4278 makernote[ifd_tag] = handler(
4279 ImageFileDirectory_v2(), data, False
4280 )
4281 self._ifds[tag] = dict(self._fixup_dict(makernote))
4282 elif self.get(0x010F) == "Nintendo":
4283 makernote = {}
4284 for i in range(struct.unpack(">H", tag_data[:2])[0]):
4285 ifd_tag, typ, count, data = struct.unpack(
4286 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2]
4287 )
4288 if ifd_tag == 0x1101:
4289 # CameraInfo
4290 (offset,) = struct.unpack(">L", data)
4291 self.fp.seek(offset)
4293 camerainfo: dict[str, int | bytes] = {
4294 "ModelID": self.fp.read(4)
4295 }
4297 self.fp.read(4)
4298 # Seconds since 2000
4299 camerainfo["TimeStamp"] = i32le(self.fp.read(12))
4301 self.fp.read(4)
4302 camerainfo["InternalSerialNumber"] = self.fp.read(4)
4304 self.fp.read(12)
4305 parallax = self.fp.read(4)
4306 handler = ImageFileDirectory_v2._load_dispatch[
4307 TiffTags.FLOAT
4308 ][1]
4309 camerainfo["Parallax"] = handler(
4310 ImageFileDirectory_v2(), parallax, False
4311 )[0]
4313 self.fp.read(4)
4314 camerainfo["Category"] = self.fp.read(2)
4316 makernote = {0x1101: camerainfo}
4317 self._ifds[tag] = makernote
4318 except struct.error:
4319 pass
4320 else:
4321 # Interop
4322 ifd = self._get_ifd_dict(tag_data, tag)
4323 if ifd is not None:
4324 self._ifds[tag] = ifd
4325 ifd = self._ifds.setdefault(tag, {})
4326 if tag == ExifTags.IFD.Exif and self._hidden_data:
4327 ifd = {
4328 k: v
4329 for (k, v) in ifd.items()
4330 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote)
4331 }
4332 return ifd
4334 def hide_offsets(self) -> None:
4335 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo):
4336 if tag in self:
4337 self._hidden_data[tag] = self[tag]
4338 del self[tag]
4340 def __str__(self) -> str:
4341 if self._info is not None:
4342 # Load all keys into self._data
4343 for tag in self._info:
4344 self[tag]
4346 return str(self._data)
4348 def __len__(self) -> int:
4349 keys = set(self._data)
4350 if self._info is not None:
4351 keys.update(self._info)
4352 return len(keys)
4354 def __getitem__(self, tag: int) -> Any:
4355 if self._info is not None and tag not in self._data and tag in self._info:
4356 self._data[tag] = self._fixup(self._info[tag])
4357 del self._info[tag]
4358 return self._data[tag]
4360 def __contains__(self, tag: object) -> bool:
4361 return tag in self._data or (self._info is not None and tag in self._info)
4363 def __setitem__(self, tag: int, value: Any) -> None:
4364 if self._info is not None and tag in self._info:
4365 del self._info[tag]
4366 self._data[tag] = value
4368 def __delitem__(self, tag: int) -> None:
4369 if self._info is not None and tag in self._info:
4370 del self._info[tag]
4371 else:
4372 del self._data[tag]
4373 if tag in self._ifds:
4374 del self._ifds[tag]
4376 def __iter__(self) -> Iterator[int]:
4377 keys = set(self._data)
4378 if self._info is not None:
4379 keys.update(self._info)
4380 return iter(keys)