Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PIL/Image.py: 44%
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 def _copy_info(self) -> dict[str | tuple[int, int], Any]:
671 return {k: v.copy() if isinstance(v, list) else v for k, v in self.info.items()}
673 def _new(self, im: core.ImagingCore) -> Image:
674 new = Image()
675 new.im = im
676 new.readonly = im.readonly
677 new._mode = im.mode
678 new._size = im.size
679 if im.mode in ("P", "PA"):
680 if self.palette:
681 new.palette = self.palette.copy()
682 new.palette.dirty = 1
683 else:
684 from . import ImagePalette
686 new.palette = ImagePalette.ImagePalette()
687 new.info = self._copy_info()
688 return new
690 # Context manager support
691 def __enter__(self) -> Self:
692 return self
694 def __exit__(self, *args: object) -> None:
695 pass
697 def close(self) -> None:
698 """
699 This operation will destroy the image core and release its memory.
700 The image data will be unusable afterward.
702 This function is required to close images that have multiple frames or
703 have not had their file read and closed by the
704 :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for
705 more information.
706 """
707 if getattr(self, "map", None):
708 if sys.platform == "win32" and sys.implementation.name == "pypy":
709 self.map.close()
710 self.map: mmap.mmap | None = None
712 # Instead of simply setting to None, we're setting up a
713 # deferred error that will better explain that the core image
714 # object is gone.
715 self._im = DeferredError(ValueError("Operation on closed image"))
717 def _copy(self) -> None:
718 self.im = self.im.copy()
719 self.readonly = 0
721 def _ensure_mutable(self) -> None:
722 self.load()
723 if self.readonly:
724 self._copy()
726 def _dump(
727 self, file: str | None = None, format: str | None = None, **options: Any
728 ) -> str:
729 suffix = f".{format}" if format else ""
731 if file:
732 filename = file
733 if not filename.endswith(suffix):
734 filename += suffix
735 else:
736 import tempfile
738 f, filename = tempfile.mkstemp(suffix)
739 os.close(f)
741 self.save(filename, format or "PPM", **options)
743 return filename
745 def __eq__(self, other: object) -> bool:
746 if self.__class__ is not other.__class__:
747 return False
748 assert isinstance(other, Image)
749 return (
750 self.mode == other.mode
751 and self.size == other.size
752 and self.info == other.info
753 and self.getpalette() == other.getpalette()
754 and self.tobytes() == other.tobytes()
755 )
757 def __repr__(self) -> str:
758 return (
759 f"<{self.__class__.__module__}.{self.__class__.__name__} "
760 f"image mode={self.mode} size={self.size[0]}x{self.size[1]} "
761 f"at 0x{id(self):X}>"
762 )
764 def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None:
765 """IPython plain text display support"""
767 # Same as __repr__ but without unpredictable id(self),
768 # to keep Jupyter notebook `text/plain` output stable.
769 p.text(
770 f"<{self.__class__.__module__}.{self.__class__.__name__} "
771 f"image mode={self.mode} size={self.size[0]}x{self.size[1]}>"
772 )
774 def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None:
775 """Helper function for iPython display hook.
777 :param image_format: Image format.
778 :returns: image as bytes, saved into the given format.
779 """
780 b = io.BytesIO()
781 try:
782 self.save(b, image_format, **kwargs)
783 except Exception:
784 return None
785 return b.getvalue()
787 def _repr_png_(self) -> bytes | None:
788 """iPython display hook support for PNG format.
790 :returns: PNG version of the image as bytes
791 """
792 return self._repr_image("PNG", compress_level=1)
794 def _repr_jpeg_(self) -> bytes | None:
795 """iPython display hook support for JPEG format.
797 :returns: JPEG version of the image as bytes
798 """
799 return self._repr_image("JPEG")
801 @property
802 def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]:
803 # numpy array interface support
804 new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3}
805 if self.mode == "1":
806 # Binary images need to be extended from bits to bytes
807 # See: https://github.com/python-pillow/Pillow/issues/350
808 new["data"] = self.tobytes("raw", "L")
809 else:
810 new["data"] = self.tobytes()
811 new["shape"], new["typestr"] = _conv_type_shape(self)
812 return new
814 def __arrow_c_schema__(self) -> object:
815 self.load()
816 return self.im.__arrow_c_schema__()
818 def __arrow_c_array__(
819 self, requested_schema: object | None = None
820 ) -> tuple[object, object]:
821 self.load()
822 return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__())
824 def __getstate__(self) -> list[Any]:
825 im_data = self.tobytes() # load image first
826 return [self.info, self.mode, self.size, self.getpalette(), im_data]
828 def __setstate__(self, state: list[Any]) -> None:
829 Image.__init__(self)
830 info, mode, size, palette, data = state[:5]
831 self.info = info
832 self._mode = mode
833 self._size = size
834 self.im = core.new(mode, size)
835 if mode in ("L", "LA", "P", "PA") and palette:
836 self.putpalette(palette)
837 self.frombytes(data)
839 def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes:
840 """
841 Return image as a bytes object.
843 .. warning::
845 This method returns raw image data derived from Pillow's internal
846 storage. For compressed image data (e.g. PNG, JPEG) use
847 :meth:`~.save`, with a BytesIO parameter for in-memory data.
849 :param encoder_name: What encoder to use.
851 The default is to use the standard "raw" encoder.
852 To see how this packs pixel data into the returned
853 bytes, see :file:`libImaging/Pack.c`.
855 A list of C encoders can be seen under codecs
856 section of the function array in
857 :file:`_imaging.c`. Python encoders are registered
858 within the relevant plugins.
859 :param args: Extra arguments to the encoder.
860 :returns: A :py:class:`bytes` object.
861 """
863 encoder_args: Any = args
864 if len(encoder_args) == 1 and isinstance(encoder_args[0], tuple):
865 # may pass tuple instead of argument list
866 encoder_args = encoder_args[0]
868 if encoder_name == "raw" and encoder_args == ():
869 encoder_args = self.mode
871 self.load()
873 if self.width == 0 or self.height == 0:
874 return b""
876 # unpack data
877 e = _getencoder(self.mode, encoder_name, encoder_args)
878 try:
879 e.setimage(self.im)
881 from . import ImageFile
883 bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c
885 output = []
886 while True:
887 bytes_consumed, errcode, data = e.encode(bufsize)
888 output.append(data)
889 if errcode:
890 break
891 if errcode < 0:
892 msg = f"encoder error {errcode} in tobytes"
893 raise RuntimeError(msg)
894 finally:
895 e.cleanup()
897 return b"".join(output)
899 def tobitmap(self, name: str = "image") -> bytes:
900 """
901 Returns the image converted to an X11 bitmap.
903 .. note:: This method only works for mode "1" images.
905 :param name: The name prefix to use for the bitmap variables.
906 :returns: A string containing an X11 bitmap.
907 :raises ValueError: If the mode is not "1"
908 """
910 self.load()
911 if self.mode != "1":
912 msg = "not a bitmap"
913 raise ValueError(msg)
914 data = self.tobytes("xbm")
915 return b"".join(
916 [
917 f"#define {name}_width {self.size[0]}\n".encode("ascii"),
918 f"#define {name}_height {self.size[1]}\n".encode("ascii"),
919 f"static char {name}_bits[] = {{\n".encode("ascii"),
920 data,
921 b"};",
922 ]
923 )
925 def frombytes(
926 self,
927 data: DecoderInput,
928 decoder_name: str = "raw",
929 *args: Any,
930 ) -> None:
931 """
932 Loads this image with pixel data from a bytes object.
934 This method is similar to the :py:func:`~PIL.Image.frombytes` function,
935 but loads data into this image instead of creating a new image object.
936 """
938 if self.width == 0 or self.height == 0:
939 return
941 decoder_args: Any = args
942 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
943 # may pass tuple instead of argument list
944 decoder_args = decoder_args[0]
946 # default format
947 if decoder_name == "raw" and decoder_args == ():
948 decoder_args = self.mode
950 # unpack data
951 d = _getdecoder(self.mode, decoder_name, decoder_args)
952 if self._im is None:
953 self.im = core.new(self.mode, self.size)
954 # Plugins may call this from load() while ImageFile.readonly is still set,
955 # so check whether the image memory itself is read-only
956 elif self.im.readonly:
957 self._copy()
958 d.setimage(self.im)
959 s = d.decode(data)
961 if s[0] >= 0:
962 msg = "not enough image data"
963 raise ValueError(msg)
964 if s[1] != 0:
965 msg = "cannot decode image data"
966 raise ValueError(msg)
968 def load(self) -> core.PixelAccess | None:
969 """
970 Allocates storage for the image and loads the pixel data. In
971 normal cases, you don't need to call this method, since the
972 Image class automatically loads an opened image when it is
973 accessed for the first time.
975 If the file associated with the image was opened by Pillow, then this
976 method will close it. The exception to this is if the image has
977 multiple frames, in which case the file will be left open for seek
978 operations. See :ref:`file-handling` for more information.
980 :returns: An image access object.
981 """
982 if self._im is not None and self.palette and self.palette.dirty:
983 # realize palette
984 mode, arr = self.palette.getdata()
985 self.im.putpalette(self.palette.mode, mode, arr)
986 self.palette.dirty = 0
987 self.palette.rawmode = None
988 if "transparency" in self.info and mode in ("LA", "PA"):
989 if isinstance(self.info["transparency"], int):
990 self.im.putpalettealpha(self.info["transparency"], 0)
991 else:
992 self.im.putpalettealphas(self.info["transparency"])
993 self.palette.mode = "RGBA"
994 elif self.palette.mode != mode:
995 # If the palette rawmode is different to the mode,
996 # then update the Python palette data
997 self.palette.palette = self.im.getpalette(self.palette.mode)
999 if self._im is not None:
1000 return self.im.pixel_access(self.readonly)
1001 return None
1003 def verify(self) -> None:
1004 """
1005 Verifies the contents of a file. For data read from a file, this
1006 method attempts to determine if the file is broken, without
1007 actually decoding the image data. If this method finds any
1008 problems, it raises suitable exceptions. If you need to load
1009 the image after using this method, you must reopen the image
1010 file.
1011 """
1012 pass
1014 def convert(
1015 self,
1016 mode: str | None = None,
1017 matrix: list[float] | tuple[float, ...] | None = None,
1018 dither: Dither | None = None,
1019 palette: Palette = Palette.WEB,
1020 colors: int = 256,
1021 ) -> Image:
1022 """
1023 Returns a converted copy of this image. For the "P" mode, this
1024 method translates pixels through the palette. If mode is
1025 omitted, a mode is chosen so that all information in the image
1026 and the palette can be represented without a palette.
1028 This supports all possible conversions between "L", "RGB" and "CMYK". The
1029 ``matrix`` argument only supports "L" and "RGB".
1031 When translating a color image to grayscale (mode "L"),
1032 the library uses the ITU-R 601-2 luma transform::
1034 L = R * 299/1000 + G * 587/1000 + B * 114/1000
1036 The default method of converting a grayscale ("L") or "RGB"
1037 image into a bilevel (mode "1") image uses Floyd-Steinberg
1038 dither to approximate the original image luminosity levels. If
1039 dither is ``None``, all values larger than 127 are set to 255 (white),
1040 all other values to 0 (black). To use other thresholds, use the
1041 :py:meth:`~PIL.Image.Image.point` method.
1043 When converting from "RGBA" to "P" without a ``matrix`` argument,
1044 this passes the operation to :py:meth:`~PIL.Image.Image.quantize`,
1045 and ``dither`` and ``palette`` are ignored.
1047 When converting from "PA", if an "RGBA" palette is present, the alpha
1048 channel from the image will be used instead of the values from the palette.
1050 :param mode: The requested mode. See: :ref:`concept-modes`.
1051 :param matrix: An optional conversion matrix containing floating point values.
1052 When converting to L mode, the sequence should have length 4. For RGB, it
1053 should have length 12.
1054 :param dither: Dithering method, used when converting from
1055 mode "RGB" to "P" or from "RGB" or "L" to "1".
1056 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1057 (default). Note that this is not used when ``matrix`` is supplied.
1058 :param palette: Palette to use when converting from mode "RGB"
1059 to "P". Available palettes are :data:`Palette.WEB` or
1060 :data:`Palette.ADAPTIVE`.
1061 :param colors: Number of colors to use for the :data:`Palette.ADAPTIVE`
1062 palette. Defaults to 256.
1063 :returns: An :py:class:`~PIL.Image.Image` object.
1064 """
1066 self.load()
1068 has_transparency = "transparency" in self.info
1069 if not mode and self.mode == "P":
1070 # determine default mode
1071 if self.palette:
1072 mode = self.palette.mode
1073 else:
1074 mode = "RGB"
1075 if mode == "RGB" and has_transparency:
1076 mode = "RGBA"
1077 if not mode or (mode == self.mode and not matrix):
1078 return self.copy()
1080 if matrix:
1081 # matrix conversion
1082 try:
1083 matrix_length = {"L": 4, "RGB": 12}[mode]
1084 except KeyError:
1085 msg = "illegal conversion"
1086 raise ValueError(msg)
1087 if matrix_length != len(matrix):
1088 msg = f"matrix must have length {matrix_length} for mode {mode}"
1089 raise TypeError(msg)
1090 im = self.im.convert_matrix(mode, matrix)
1091 new_im = self._new(im)
1092 if has_transparency and self.im.bands == 3:
1093 transparency = new_im.info["transparency"]
1095 def convert_transparency(
1096 m: list[float] | tuple[float, ...], v: tuple[int, int, int]
1097 ) -> int:
1098 value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] + 0.5
1099 return max(0, min(255, int(value)))
1101 if mode == "L":
1102 transparency = convert_transparency(matrix, transparency)
1103 elif len(mode) == 3:
1104 transparency = tuple(
1105 convert_transparency(matrix[i * 4 : i * 4 + 4], transparency)
1106 for i in range(len(transparency))
1107 )
1108 new_im.info["transparency"] = transparency
1109 return new_im
1111 if self.mode == "RGBA":
1112 if mode == "P":
1113 return self.quantize(colors)
1114 elif mode == "PA":
1115 r, g, b, a = self.split()
1116 rgb = merge("RGB", (r, g, b))
1117 p = rgb.quantize(colors)
1118 return merge("PA", (p, a))
1120 if "LAB" in (self.mode, mode):
1121 im = self
1122 if mode == "LAB":
1123 if im.mode not in {"RGB", "RGBA", "RGBX"}:
1124 im = im.convert("RGBA")
1125 other_mode = im.mode
1126 else:
1127 other_mode = mode
1128 if other_mode in {"RGB", "RGBA", "RGBX"}:
1129 from . import ImageCms
1131 srgb = ImageCms.createProfile("sRGB")
1132 lab = ImageCms.createProfile("LAB")
1133 profiles = [lab, srgb] if im.mode == "LAB" else [srgb, lab]
1134 transform = ImageCms.buildTransform(
1135 profiles[0], profiles[1], im.mode, mode
1136 )
1137 return transform.apply(im)
1139 im = self.im
1141 trns = None
1142 delete_trns = False
1143 # transparency handling
1144 if has_transparency:
1145 if (self.mode in {"1", "L", "I", "I;16"} and mode in {"LA", "RGBA"}) or (
1146 self.mode == "RGB" and mode in {"La", "LA", "RGBa", "RGBA"}
1147 ):
1148 # Use transparent conversion to promote from transparent
1149 # color to an alpha channel.
1150 new_im = self._new(
1151 im.convert_transparent(mode, self.info["transparency"])
1152 )
1153 del new_im.info["transparency"]
1154 return new_im
1155 elif self.mode in {"1", "L", "I", "I;16", "RGB", "P"} and (
1156 mode in {"L", "RGB", "P"}
1157 ):
1158 t = self.info["transparency"]
1159 if isinstance(t, bytes):
1160 # Dragons. This can't be represented by a single color
1161 warnings.warn(
1162 "Palette images with Transparency expressed in bytes should be "
1163 "converted to RGBA images"
1164 )
1165 delete_trns = True
1166 else:
1167 # get the new transparency color.
1168 # use existing conversions
1169 trns_im = new(self.mode, (1, 1))
1170 if self.mode == "P":
1171 assert self.palette is not None
1172 trns_im.putpalette(self.palette)
1173 if isinstance(t, tuple):
1174 err = "Couldn't allocate a palette color for transparency"
1175 assert trns_im.palette is not None
1176 try:
1177 t = trns_im.palette.getcolor(t, self)
1178 except ValueError as e:
1179 if str(e) == "cannot allocate more than 256 colors":
1180 # If all 256 colors are in use,
1181 # then there is no need for transparency
1182 t = None
1183 else:
1184 raise ValueError(err) from e
1185 if t is None:
1186 trns = None
1187 else:
1188 trns_im.putpixel((0, 0), t)
1190 if mode in {"L", "RGB"}:
1191 trns_im = trns_im.convert(mode)
1192 else:
1193 # can't just retrieve the palette number, got to do it
1194 # after quantization.
1195 trns_im = trns_im.convert("RGB")
1196 trns = trns_im.getpixel((0, 0))
1198 elif self.mode == "P" and mode in {"LA", "PA", "RGBA"}:
1199 t = self.info["transparency"]
1200 delete_trns = True
1202 if isinstance(t, bytes):
1203 im = im.copy()
1204 im.putpalettealphas(t)
1205 elif isinstance(t, int):
1206 im = im.copy()
1207 im.putpalettealpha(t, 0)
1208 else:
1209 msg = "Transparency for P mode should be bytes or int"
1210 raise ValueError(msg)
1211 elif self.mode in {"1", "L", "I", "I;16", "RGB"} and mode == "PA":
1212 im_without_trns = self.copy()
1213 del im_without_trns.info["transparency"]
1214 new_im = im_without_trns.convert(mode, dither=dither)
1215 new_im.putalpha(self.convert("RGBA").getchannel("A"))
1216 return new_im
1218 if mode == "P" and palette == Palette.ADAPTIVE:
1219 im = self.im.quantize(colors)
1220 new_im = self._new(im)
1221 from . import ImagePalette
1223 new_im.palette = ImagePalette.ImagePalette(
1224 "RGB", new_im.im.getpalette("RGB")
1225 )
1226 if delete_trns:
1227 # This could possibly happen if we requantize to fewer colors.
1228 # The transparency would be totally off in that case.
1229 del new_im.info["transparency"]
1230 if trns is not None:
1231 try:
1232 new_im.info["transparency"] = new_im.palette.getcolor(
1233 cast("tuple[int, ...]", trns), # trns was converted to RGB
1234 new_im,
1235 )
1236 except Exception:
1237 # if we can't make a transparent color, don't leave the old
1238 # transparency hanging around to mess us up.
1239 del new_im.info["transparency"]
1240 warnings.warn("Couldn't allocate palette entry for transparency")
1241 return new_im
1243 # colorspace conversion
1244 if dither is None:
1245 dither = Dither.FLOYDSTEINBERG
1247 try:
1248 im = im.convert(mode, dither)
1249 except ValueError:
1250 try:
1251 # normalize source image and try again
1252 modebase = getmodebase(self.mode)
1253 if modebase == self.mode:
1254 raise
1255 im = im.convert(modebase)
1256 im = im.convert(mode, dither)
1257 except KeyError as e:
1258 msg = "illegal conversion"
1259 raise ValueError(msg) from e
1261 new_im = self._new(im)
1262 if mode in ("P", "PA") and palette != Palette.ADAPTIVE:
1263 from . import ImagePalette
1265 new_im.palette = ImagePalette.raw("RGB", im.getpalette("RGB"))
1266 if delete_trns:
1267 # crash fail if we leave a bytes transparency in an rgb/l mode.
1268 del new_im.info["transparency"]
1269 if trns is not None:
1270 if new_im.mode == "P" and new_im.palette:
1271 try:
1272 new_im.info["transparency"] = new_im.palette.getcolor(
1273 cast("tuple[int, ...]", trns), # trns was converted to RGB
1274 new_im,
1275 )
1276 except ValueError as e:
1277 del new_im.info["transparency"]
1278 if str(e) != "cannot allocate more than 256 colors":
1279 # If all 256 colors are in use,
1280 # then there is no need for transparency
1281 warnings.warn(
1282 "Couldn't allocate palette entry for transparency"
1283 )
1284 else:
1285 new_im.info["transparency"] = trns
1286 return new_im
1288 def quantize(
1289 self,
1290 colors: int = 256,
1291 method: int | None = None,
1292 kmeans: int = 0,
1293 palette: Image | None = None,
1294 dither: Dither = Dither.FLOYDSTEINBERG,
1295 ) -> Image:
1296 """
1297 Convert the image to 'P' mode with the specified number
1298 of colors.
1300 :param colors: The desired number of colors, <= 256
1301 :param method: :data:`Quantize.MEDIANCUT` (median cut),
1302 :data:`Quantize.MAXCOVERAGE` (maximum coverage),
1303 :data:`Quantize.FASTOCTREE` (fast octree),
1304 :data:`Quantize.LIBIMAGEQUANT` (libimagequant; check support
1305 using :py:func:`PIL.features.check_feature` with
1306 ``feature="libimagequant"``).
1308 By default, :data:`Quantize.MEDIANCUT` will be used.
1310 The exception to this is RGBA images. :data:`Quantize.MEDIANCUT`
1311 and :data:`Quantize.MAXCOVERAGE` do not support RGBA images, so
1312 :data:`Quantize.FASTOCTREE` is used by default instead.
1313 :param kmeans: Integer greater than or equal to zero.
1314 :param palette: Quantize to the palette of given
1315 :py:class:`PIL.Image.Image`.
1316 :param dither: Dithering method, used when converting from
1317 mode "RGB" to "P" or from "RGB" or "L" to "1".
1318 Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG`
1319 (default).
1320 :returns: A new image
1321 """
1323 self.load()
1325 if method is None:
1326 # defaults:
1327 method = Quantize.MEDIANCUT
1328 if self.mode == "RGBA":
1329 method = Quantize.FASTOCTREE
1331 if self.mode == "RGBA" and method not in (
1332 Quantize.FASTOCTREE,
1333 Quantize.LIBIMAGEQUANT,
1334 ):
1335 # Caller specified an invalid mode.
1336 msg = (
1337 "Fast Octree (method == 2) and libimagequant (method == 3) "
1338 "are the only valid methods for quantizing RGBA images"
1339 )
1340 raise ValueError(msg)
1342 if palette:
1343 # use palette from reference image
1344 palette.load()
1345 if palette.mode != "P":
1346 msg = "bad mode for palette image"
1347 raise ValueError(msg)
1348 if self.mode not in {"RGB", "L"}:
1349 msg = "only RGB or L mode images can be quantized to a palette"
1350 raise ValueError(msg)
1351 im = self.im.convert("P", dither, palette.im)
1352 new_im = self._new(im)
1353 assert palette.palette is not None
1354 new_im.palette = palette.palette.copy()
1355 return new_im
1357 if kmeans < 0:
1358 msg = "kmeans must not be negative"
1359 raise ValueError(msg)
1361 im = self._new(self.im.quantize(colors, method, kmeans))
1363 from . import ImagePalette
1365 mode = im.im.getpalettemode()
1366 palette_data = im.im.getpalette()[: colors * len(mode)]
1367 im.palette = ImagePalette.ImagePalette(mode, palette_data)
1369 return im
1371 def copy(self) -> Image:
1372 """
1373 Copies this image. Use this method if you wish to paste things
1374 into an image, but still retain the original.
1376 :returns: An :py:class:`~PIL.Image.Image` object.
1377 """
1378 self.load()
1379 return self._new(self.im.copy())
1381 __copy__ = copy
1383 def crop(self, box: tuple[float, float, float, float] | None = None) -> Image:
1384 """
1385 Returns a rectangular region from this image. The box is a
1386 4-tuple defining the left, upper, right, and lower pixel
1387 coordinate. See :ref:`coordinate-system`.
1389 Note: Prior to Pillow 3.4.0, this was a lazy operation.
1391 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1392 :returns: An :py:class:`~PIL.Image.Image` object.
1393 """
1395 if box is None:
1396 box = (0, 0, *self.size)
1397 if box[2] - box[0] == 0 or box[3] - box[1] == 0:
1398 return self._new(core.new(self.mode, (box[2] - box[0], box[3] - box[1])))
1399 if box == (0, 0, *self.size):
1400 return self.copy()
1402 if box[2] < box[0]:
1403 msg = "Coordinate 'right' is less than 'left'"
1404 raise ValueError(msg)
1405 elif box[3] < box[1]:
1406 msg = "Coordinate 'lower' is less than 'upper'"
1407 raise ValueError(msg)
1409 self.load()
1410 return self._new(self._crop(self.im, box))
1412 def _crop(
1413 self, im: core.ImagingCore, box: tuple[float, float, float, float]
1414 ) -> core.ImagingCore:
1415 """
1416 Returns a rectangular region from the core image object im.
1418 This is equivalent to calling im.crop((x0, y0, x1, y1)), but
1419 includes additional sanity checks.
1421 :param im: a core image object
1422 :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
1423 :returns: A core image object.
1424 """
1426 x0, y0, x1, y1 = map(int, map(round, box))
1428 absolute_values = (abs(x1 - x0), abs(y1 - y0))
1430 _decompression_bomb_check(absolute_values)
1432 return im.crop((x0, y0, x1, y1))
1434 def draft(
1435 self, mode: str | None, size: tuple[int, int] | None
1436 ) -> tuple[str, tuple[int, int, float, float]] | None:
1437 """
1438 Configures the image file loader so it returns a version of the
1439 image that as closely as possible matches the given mode and
1440 size. For example, you can use this method to convert a color
1441 JPEG to grayscale while loading it.
1443 If any changes are made, returns a tuple with the chosen ``mode`` and
1444 ``box`` with coordinates of the original image within the altered one.
1446 Note that this method modifies the :py:class:`~PIL.Image.Image` object
1447 in place. If the image has already been loaded, this method has no
1448 effect.
1450 Note: This method is not implemented for most images. It is
1451 currently implemented only for JPEG and MPO images.
1453 :param mode: The requested mode.
1454 :param size: The requested size in pixels, as a 2-tuple:
1455 (width, height).
1456 """
1457 pass
1459 def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image:
1460 """
1461 Filters this image using the given filter. For a list of
1462 available filters, see the :py:mod:`~PIL.ImageFilter` module.
1464 :param filter: Filter kernel.
1465 :returns: An :py:class:`~PIL.Image.Image` object."""
1467 from . import ImageFilter
1469 self.load()
1471 if callable(filter):
1472 filter = filter()
1473 if not hasattr(filter, "filter"):
1474 msg = "filter argument should be ImageFilter.Filter instance or class"
1475 raise TypeError(msg)
1477 multiband = isinstance(filter, ImageFilter.MultibandFilter)
1478 if self.im.bands == 1 or multiband:
1479 return self._new(filter.filter(self.im))
1481 ims = [
1482 self._new(filter.filter(self.im.getband(c))) for c in range(self.im.bands)
1483 ]
1484 return merge(self.mode, ims)
1486 def getbands(self) -> tuple[str, ...]:
1487 """
1488 Returns a tuple containing the name of each band in this image.
1489 For example, ``getbands`` on an RGB image returns ("R", "G", "B").
1491 :returns: A tuple containing band names.
1492 """
1493 return ImageMode.getmode(self.mode).bands
1495 def getbbox(self, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None:
1496 """
1497 Calculates the bounding box of the non-zero regions in the
1498 image.
1500 :param alpha_only: Optional flag, defaulting to ``True``.
1501 If ``True`` and the image has an alpha channel, trim transparent pixels.
1502 Otherwise, trim pixels when all channels are zero.
1503 Keyword-only argument.
1504 :returns: The bounding box is returned as a 4-tuple defining the
1505 left, upper, right, and lower pixel coordinate. See
1506 :ref:`coordinate-system`. If the image is completely empty, this
1507 method returns None.
1509 """
1511 self.load()
1512 return self.im.getbbox(alpha_only)
1514 def getcolors(
1515 self, maxcolors: int = 256
1516 ) -> list[tuple[int, tuple[int, ...]]] | list[tuple[int, float]] | None:
1517 """
1518 Returns a list of colors used in this image.
1520 The colors will be in the image's mode. For example, an RGB image will
1521 return a tuple of (red, green, blue) color values, and a P image will
1522 return the index of the color in the palette.
1524 :param maxcolors: Maximum number of colors. If this number is
1525 exceeded, this method returns None. The default limit is
1526 256 colors.
1527 :returns: An unsorted list of (count, pixel) values.
1528 """
1529 if maxcolors < 0:
1530 return None
1532 self.load()
1533 if self.mode in {"1", "L", "P"}:
1534 h = self.im.histogram()
1535 out: list[tuple[int, float]] = [(h[i], i) for i in range(256) if h[i]]
1536 if len(out) > maxcolors:
1537 return None
1538 return out
1539 return self.im.getcolors(maxcolors)
1541 def getdata(self, band: int | None = None) -> core.ImagingCore:
1542 """
1543 Returns the contents of this image as a sequence object
1544 containing pixel values. The sequence object is flattened, so
1545 that values for line one follow directly after the values of
1546 line zero, and so on.
1548 Note that the sequence object returned by this method is an
1549 internal PIL data type, which only supports certain sequence
1550 operations. To convert it to an ordinary sequence (e.g. for
1551 printing), use ``list(im.getdata())``.
1553 :param band: What band to return. The default is to return
1554 all bands. To return a single band, pass in the index
1555 value (e.g. 0 to get the "R" band from an "RGB" image).
1556 :returns: A sequence-like object.
1557 """
1558 deprecate("Image.Image.getdata", 14, "get_flattened_data")
1560 self.load()
1561 if band is not None:
1562 return self.im.getband(band)
1563 return self.im # could be abused
1565 def get_flattened_data(
1566 self, band: int | None = None
1567 ) -> tuple[tuple[int, ...], ...] | tuple[float, ...]:
1568 """
1569 Returns the contents of this image as a tuple containing pixel values.
1570 The sequence object is flattened, so that values for line one follow
1571 directly after the values of line zero, and so on.
1573 :param band: What band to return. The default is to return
1574 all bands. To return a single band, pass in the index
1575 value (e.g. 0 to get the "R" band from an "RGB" image).
1576 :returns: A tuple containing pixel values.
1577 """
1578 self.load()
1579 if band is not None:
1580 return tuple(self.im.getband(band))
1581 return tuple(self.im)
1583 def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]:
1584 """
1585 Gets the minimum and maximum pixel values for each band in
1586 the image.
1588 :returns: For a single-band image, a 2-tuple containing the
1589 minimum and maximum pixel value. For a multi-band image,
1590 a tuple containing one 2-tuple for each band.
1591 """
1593 self.load()
1594 return self.im.getextrema()
1596 def getxmp(self, *, strip_namespaces: bool = True) -> dict[str, Any]:
1597 """
1598 Returns a dictionary containing the XMP tags.
1599 Requires defusedxml to be installed.
1601 :param strip_namespaces: If ``False``, keep each tag's full
1602 ``{namespace-uri}local-name`` form instead of stripping the namespace
1603 prefix.
1605 .. versionadded:: 13.0.0
1607 :returns: XMP tags in a dictionary.
1608 """
1609 try:
1610 from defusedxml import ElementTree
1611 except ImportError:
1612 warnings.warn("XMP data cannot be read without defusedxml dependency")
1613 return {}
1615 if strip_namespaces:
1617 def get_name(tag: str) -> str:
1618 return re.sub("^{[^}]+}", "", tag)
1620 else:
1622 def get_name(tag: str) -> str:
1623 return tag
1625 def get_value(element: Element) -> str | dict[str, Any] | None:
1626 value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()}
1627 children = list(element)
1628 if children:
1629 for child in children:
1630 name = get_name(child.tag)
1631 child_value = get_value(child)
1632 if name in value:
1633 if not isinstance(value[name], list):
1634 value[name] = [value[name]]
1635 value[name].append(child_value)
1636 else:
1637 value[name] = child_value
1638 elif value:
1639 if element.text:
1640 value["text"] = element.text
1641 else:
1642 return element.text
1643 return value
1645 if "xmp" not in self.info:
1646 return {}
1647 root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 "))
1648 return {get_name(root.tag): get_value(root)}
1650 def getexif(self) -> Exif:
1651 """
1652 Gets EXIF data from the image.
1654 :returns: an :py:class:`~PIL.Image.Exif` object.
1655 """
1656 if self._exif is None:
1657 self._exif = Exif()
1658 elif self._exif._loaded:
1659 return self._exif
1660 self._exif._loaded = True
1662 exif_info = self.info.get("exif")
1663 if exif_info is None:
1664 if "Raw profile type exif" in self.info:
1665 exif_info = bytes.fromhex(
1666 "".join(self.info["Raw profile type exif"].split("\n")[3:])
1667 )
1668 elif hasattr(self, "tag_v2"):
1669 from . import TiffImagePlugin
1671 assert isinstance(self, TiffImagePlugin.TiffImageFile)
1672 self._exif.bigtiff = self.tag_v2._bigtiff
1673 self._exif.endian = self.tag_v2._endian
1675 assert self.fp is not None
1676 self._exif.load_from_fp(self.fp, self.tag_v2._offset)
1677 if exif_info is not None:
1678 self._exif.load(exif_info)
1680 # XMP tags
1681 if ExifTags.Base.Orientation not in self._exif:
1682 xmp_tags = self.info.get("XML:com.adobe.xmp")
1683 pattern: str | bytes = r'tiff:Orientation(="|>)([0-9])'
1684 if not xmp_tags and (xmp_tags := self.info.get("xmp")):
1685 pattern = rb'tiff:Orientation(="|>)([0-9])'
1686 if xmp_tags:
1687 match = re.search(pattern, xmp_tags)
1688 if match:
1689 self._exif[ExifTags.Base.Orientation] = int(match[2])
1691 return self._exif
1693 def _reload_exif(self) -> None:
1694 if self._exif is None or not self._exif._loaded:
1695 return
1696 self._exif._loaded = False
1697 self.getexif()
1699 def getim(self) -> CapsuleType:
1700 """
1701 Returns a capsule that points to the internal image memory.
1703 :returns: A capsule object.
1704 """
1706 self.load()
1707 return self.im.ptr
1709 def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None:
1710 """
1711 Returns the image palette as a list.
1713 :param rawmode: The mode in which to return the palette. ``None`` will
1714 return the palette in its current mode.
1716 .. versionadded:: 9.1.0
1718 :returns: A list of color values [r, g, b, ...], or None if the
1719 image has no palette.
1720 """
1722 self.load()
1723 try:
1724 palette = (
1725 self.im.getpalette(rawmode)
1726 if rawmode is not None
1727 else self.im.getpalette()
1728 )
1729 except ValueError:
1730 return None # no palette
1731 return list(palette)
1733 @property
1734 def has_transparency_data(self) -> bool:
1735 """
1736 Determine if an image has transparency data, whether in the form of an
1737 alpha channel, a palette with an alpha channel, or a "transparency" key
1738 in the info dictionary.
1740 Note the image might still appear solid, if all of the values shown
1741 within are opaque.
1743 :returns: A boolean.
1744 """
1745 if (
1746 self.mode in ("LA", "La", "PA", "RGBA", "RGBa")
1747 or "transparency" in self.info
1748 ):
1749 return True
1750 if self.mode == "P":
1751 assert self.palette is not None
1752 return self.palette.mode.endswith("A")
1753 return False
1755 def apply_transparency(self) -> None:
1756 """
1757 If a P mode image has a "transparency" key in the info dictionary,
1758 remove the key and instead apply the transparency to the palette.
1759 Otherwise, the image is unchanged.
1760 """
1761 if self.mode != "P" or "transparency" not in self.info:
1762 return
1764 from . import ImagePalette
1766 palette = self.getpalette("RGBA")
1767 assert palette is not None
1768 transparency = self.info["transparency"]
1769 if isinstance(transparency, bytes):
1770 for i, alpha in enumerate(transparency):
1771 palette[i * 4 + 3] = alpha
1772 else:
1773 palette[transparency * 4 + 3] = 0
1774 self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette))
1775 self.palette.dirty = 1
1777 del self.info["transparency"]
1779 def getpixel(
1780 self, xy: tuple[int, int] | list[int]
1781 ) -> float | tuple[int, ...] | None:
1782 """
1783 Returns the pixel value at a given position.
1785 :param xy: The coordinate, given as (x, y). See
1786 :ref:`coordinate-system`.
1787 :returns: The pixel value. If the image is a multi-layer image,
1788 this method returns a tuple.
1789 """
1791 self.load()
1792 return self.im.getpixel(tuple(xy))
1794 def getprojection(self) -> tuple[list[int], list[int]]:
1795 """
1796 Get projection to x and y axes
1798 :returns: Two sequences, indicating where there are non-zero
1799 pixels along the X-axis and the Y-axis, respectively.
1800 """
1802 self.load()
1803 x, y = self.im.getprojection()
1804 return list(x), list(y)
1806 def histogram(
1807 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1808 ) -> list[int]:
1809 """
1810 Returns a histogram for the image. The histogram is returned as a
1811 list of pixel counts, one for each pixel value in the source
1812 image. Counts are grouped into 256 bins for each band, even if
1813 the image has more than 8 bits per band. If the image has more
1814 than one band, the histograms for all bands are concatenated (for
1815 example, the histogram for an "RGB" image contains 768 values).
1817 A bilevel image (mode "1") is treated as a grayscale ("L") image
1818 by this method.
1820 If a mask is provided, the method returns a histogram for those
1821 parts of the image where the mask image is non-zero. The mask
1822 image must have the same size as the image, and be either a
1823 bi-level image (mode "1") or a grayscale image ("L").
1825 :param mask: An optional mask.
1826 :param extrema: An optional tuple of manually-specified extrema.
1827 :returns: A list containing pixel counts.
1828 """
1829 if min(self.size) == 0:
1830 return [0] * 256 * getmodebands(self.mode)
1832 self.load()
1833 if mask:
1834 mask.load()
1835 return self.im.histogram(None, mask.im)
1836 if self.mode in ("I", "I;16", "I;16L", "I;16B", "I;16N", "F"):
1837 return self.im.histogram(
1838 extrema if extrema is not None else self.getextrema()
1839 )
1840 return self.im.histogram()
1842 def entropy(
1843 self, mask: Image | None = None, extrema: tuple[float, float] | None = None
1844 ) -> float:
1845 """
1846 Calculates and returns the entropy for the image.
1848 A bilevel image (mode "1") is treated as a grayscale ("L")
1849 image by this method.
1851 If a mask is provided, the method employs the histogram for
1852 those parts of the image where the mask image is non-zero.
1853 The mask image must have the same size as the image, and be
1854 either a bi-level image (mode "1") or a grayscale image ("L").
1856 :param mask: An optional mask.
1857 :param extrema: An optional tuple of manually-specified extrema.
1858 :returns: A float value representing the image entropy
1859 """
1860 if min(self.size) == 0:
1861 return 0.0
1863 self.load()
1864 if mask:
1865 mask.load()
1866 return self.im.entropy(None, mask.im)
1867 if self.mode in ("I", "I;16", "I;16L", "I;16B", "I;16N", "F"):
1868 return self.im.entropy(
1869 extrema if extrema is not None else self.getextrema()
1870 )
1871 return self.im.entropy()
1873 def paste(
1874 self,
1875 im: Image | str | float | tuple[float, ...],
1876 box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None,
1877 mask: Image | None = None,
1878 ) -> None:
1879 """
1880 Pastes another image into this image. The box argument is either
1881 a 2-tuple giving the upper left corner, a 4-tuple defining the
1882 left, upper, right, and lower pixel coordinate, or None (same as
1883 (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size
1884 of the pasted image must match the size of the region.
1886 If the modes don't match, the pasted image is converted to the mode of
1887 this image (see the :py:meth:`~PIL.Image.Image.convert` method for
1888 details).
1890 Instead of an image, the source can be a integer or tuple
1891 containing pixel values. The method then fills the region
1892 with the given color. When creating RGB images, you can
1893 also use color strings as supported by the ImageColor module. See
1894 :ref:`colors` for more information.
1896 If a mask is given, this method updates only the regions
1897 indicated by the mask. You can use either "1", "L", "LA", "RGBA"
1898 or "RGBa" images (if present, the alpha band is used as mask).
1899 Where the mask is 255, the given image is copied as is. Where
1900 the mask is 0, the current value is preserved. Intermediate
1901 values will mix the two images together, including their alpha
1902 channels if they have them.
1904 See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
1905 combine images with respect to their alpha channels.
1907 :param im: Source image or pixel value (integer, float or tuple).
1908 :param box: An optional 4-tuple giving the region to paste into.
1909 If a 2-tuple is used instead, it's treated as the upper left
1910 corner. If omitted or None, the source is pasted into the
1911 upper left corner.
1913 If an image is given as the second argument and there is no
1914 third, the box defaults to (0, 0), and the second argument
1915 is interpreted as a mask image.
1916 :param mask: An optional mask image.
1917 """
1919 if isinstance(box, Image):
1920 if mask is not None:
1921 msg = "If using second argument as mask, third argument must be None"
1922 raise ValueError(msg)
1923 # abbreviated paste(im, mask) syntax
1924 mask = box
1925 box = None
1927 if box is None:
1928 box = (0, 0)
1930 if len(box) == 2:
1931 # upper left corner given; get size from image or mask
1932 if isinstance(im, Image):
1933 size = im.size
1934 elif isinstance(mask, Image):
1935 size = mask.size
1936 else:
1937 # FIXME: use self.size here?
1938 msg = "cannot determine region size; use 4-item box"
1939 raise ValueError(msg)
1940 box += (box[0] + size[0], box[1] + size[1])
1942 source: core.ImagingCore | str | float | tuple[float, ...]
1943 if isinstance(im, str):
1944 from . import ImageColor
1946 source = ImageColor.getcolor(im, self.mode)
1947 elif isinstance(im, Image):
1948 if self.mode != im.mode and (
1949 self.mode != "RGB" or im.mode not in {"LA", "RGBA", "RGBa"}
1950 ):
1951 # should use an adapter for this!
1952 im = im.convert(self.mode)
1953 else:
1954 im.load()
1955 source = im.im
1956 else:
1957 source = im
1959 self._ensure_mutable()
1961 if mask:
1962 mask.load()
1963 self.im.paste(source, box, mask.im)
1964 else:
1965 self.im.paste(source, box)
1967 def alpha_composite(
1968 self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0)
1969 ) -> None:
1970 """'In-place' analog of Image.alpha_composite. Composites an image
1971 onto this image.
1973 :param im: image to composite over this one
1974 :param dest: Optional 2 tuple (left, top) specifying the upper
1975 left corner in this (destination) image.
1976 :param source: Optional 2 (left, top) tuple for the upper left
1977 corner in the overlay source image, or 4 tuple (left, top, right,
1978 bottom) for the bounds of the source rectangle
1980 Performance Note: Not currently implemented in-place in the core layer.
1981 """
1983 if not isinstance(source, (list, tuple)):
1984 msg = "Source must be a list or tuple"
1985 raise ValueError(msg)
1986 if not isinstance(dest, (list, tuple)):
1987 msg = "Destination must be a list or tuple"
1988 raise ValueError(msg)
1990 if len(source) == 4:
1991 overlay_crop_box = tuple(source)
1992 elif len(source) == 2:
1993 overlay_crop_box = tuple(source) + im.size
1994 else:
1995 msg = "Source must be a sequence of length 2 or 4"
1996 raise ValueError(msg)
1998 if not len(dest) == 2:
1999 msg = "Destination must be a sequence of length 2"
2000 raise ValueError(msg)
2001 if min(source) < 0:
2002 msg = "Source must be non-negative"
2003 raise ValueError(msg)
2005 # over image, crop if it's not the whole image.
2006 if overlay_crop_box == (0, 0, *im.size):
2007 overlay = im
2008 else:
2009 overlay = im.crop(overlay_crop_box)
2011 # target for the paste
2012 box = tuple(dest) + (dest[0] + overlay.width, dest[1] + overlay.height)
2014 # destination image. don't copy if we're using the whole image.
2015 if box == (0, 0, *self.size):
2016 background = self
2017 else:
2018 background = self.crop(box)
2020 result = alpha_composite(background, overlay)
2021 self.paste(result, box)
2023 def point(
2024 self,
2025 lut: (
2026 Sequence[float]
2027 | NumpyArray
2028 | Callable[[int], float]
2029 | Callable[[ImagePointTransform], ImagePointTransform | float]
2030 | ImagePointHandler
2031 ),
2032 mode: str | None = None,
2033 ) -> Image:
2034 """
2035 Maps this image through a lookup table or function.
2037 :param lut: A lookup table, containing 256 (or 65536 if
2038 self.mode=="I" and mode == "L") values per band in the
2039 image. A function can be used instead, it should take a
2040 single argument. The function is called once for each
2041 possible pixel value, and the resulting table is applied to
2042 all bands of the image.
2044 It may also be an :py:class:`~PIL.Image.ImagePointHandler`
2045 object::
2047 class Example(Image.ImagePointHandler):
2048 def point(self, im: Image) -> Image:
2049 # Return result
2050 :param mode: Output mode (default is same as input). This can only be used if
2051 the source image has mode "L" or "P", and the output has mode "1" or the
2052 source image mode is "I" and the output mode is "L".
2053 :returns: An :py:class:`~PIL.Image.Image` object.
2054 """
2056 self.load()
2058 if isinstance(lut, ImagePointHandler):
2059 return lut.point(self)
2061 if callable(lut):
2062 # if it isn't a list, it should be a function
2063 if self.mode in ("I", "I;16", "I;16L", "I;16B", "I;16N", "F"):
2064 # check if the function can be used with point_transform
2065 # UNDONE wiredfool -- I think this prevents us from ever doing
2066 # a gamma function point transform on > 8bit images.
2067 scale, offset = _getscaleoffset(lut) # type: ignore[arg-type]
2068 return self._new(self.im.point_transform(scale, offset))
2069 # for other modes, convert the function to a table
2070 flatLut = [lut(i) for i in range(256)] * self.im.bands # type: ignore[arg-type]
2071 else:
2072 flatLut = lut
2074 if self.mode == "F":
2075 # FIXME: _imaging returns a confusing error message for this case
2076 msg = "point operation not supported for this mode"
2077 raise ValueError(msg)
2079 if mode != "F":
2080 flatLut = [round(i) for i in flatLut]
2081 return self._new(self.im.point(flatLut, mode))
2083 def putalpha(self, alpha: Image | int) -> None:
2084 """
2085 Adds or replaces the alpha layer in this image. If the image
2086 does not have an alpha layer, it's converted to "LA" or "RGBA".
2087 The new layer must be either "L" or "1".
2089 :param alpha: The new alpha layer. This can either be an "L" or "1"
2090 image having the same size as this image, or an integer.
2091 """
2093 self._ensure_mutable()
2095 if self.mode in ("RGB", "RGBX"):
2096 # promote self to RGBA
2097 self.im.setalpha()
2098 self._mode = "RGBA"
2099 elif self.mode not in ("LA", "PA", "RGBA"):
2100 try:
2101 # do things the hard way
2102 mode = getmodebase(self.mode) + "A"
2103 im = self.im.convert(mode)
2104 if im.mode not in ("LA", "PA", "RGBA"):
2105 msg = "alpha channel could not be added"
2106 raise ValueError(msg) # sanity check
2107 self.im = im
2108 self._mode = self.im.mode
2109 except KeyError as e:
2110 msg = "illegal image mode"
2111 raise ValueError(msg) from e
2113 if self.mode in ("LA", "PA"):
2114 band = 1
2115 else:
2116 band = 3
2118 if isinstance(alpha, Image):
2119 # alpha layer
2120 if alpha.mode not in ("1", "L"):
2121 msg = "illegal image mode"
2122 raise ValueError(msg)
2123 alpha.load()
2124 if alpha.mode == "1":
2125 alpha = alpha.convert("L")
2126 else:
2127 # constant alpha
2128 try:
2129 self.im.fillband(band, alpha)
2130 except (AttributeError, ValueError):
2131 # do things the hard way
2132 alpha = new("L", self.size, alpha)
2133 else:
2134 return
2136 self.im.putband(alpha.im, band)
2138 def putdata(
2139 self,
2140 data: Sequence[float] | Sequence[Sequence[int]] | NumpyArray,
2141 scale: float = 1.0,
2142 offset: float = 0.0,
2143 ) -> None:
2144 """
2145 Copies pixel data from a flattened sequence object into the image. The
2146 values should start at the upper left corner (0, 0), continue to the
2147 end of the line, followed directly by the first value of the second
2148 line, and so on. Data will be read until either the image or the
2149 sequence ends. The scale and offset values are used to adjust the
2150 sequence values: **pixel = value*scale + offset**.
2152 :param data: A flattened sequence object. See :ref:`colors` for more
2153 information about values.
2154 :param scale: An optional scale value. The default is 1.0.
2155 :param offset: An optional offset value. The default is 0.0.
2156 """
2158 self._ensure_mutable()
2160 self.im.putdata(data, scale, offset)
2162 def putpalette(
2163 self,
2164 data: ImagePalette.ImagePalette | bytes | Sequence[int],
2165 rawmode: str = "RGB",
2166 ) -> None:
2167 """
2168 Attaches a palette to this image. The image must be a "P", "PA", "L"
2169 or "LA" image.
2171 The palette sequence must contain at most 256 colors, made up of one
2172 integer value for each channel in the raw mode.
2173 For example, if the raw mode is "RGB", then it can contain at most 768
2174 values, made up of red, green and blue values for the corresponding pixel
2175 index in the 256 colors.
2176 If the raw mode is "RGBA", then it can contain at most 1024 values,
2177 containing red, green, blue and alpha values.
2179 Alternatively, an 8-bit string may be used instead of an integer sequence.
2181 :param data: A palette sequence (either a list or a string) or an ImagePalette.
2182 :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", "CMYK", or a
2183 mode that can be transformed to one of those modes (e.g. "R", "RGBA;L").
2184 Ignored if ``data`` is an ImagePalette.
2185 """
2186 from . import ImagePalette
2188 if self.mode not in ("L", "LA", "P", "PA"):
2189 msg = "illegal image mode"
2190 raise ValueError(msg)
2191 if isinstance(data, ImagePalette.ImagePalette):
2192 palette = data.copy()
2193 palette.dirty = 1
2194 else:
2195 palette = ImagePalette.raw(rawmode, data)
2196 if rawmode.startswith("CMYK"):
2197 palette.mode = "CMYK"
2198 elif "A" in rawmode:
2199 palette.mode = "RGBA"
2200 if palette.mode == palette.rawmode:
2201 palette.rawmode = None
2202 self._mode = "PA" if "A" in self.mode else "P"
2203 self.palette = palette
2204 if self.palette.rawmode or (
2205 self._im is not None and self._im.mode != self.mode
2206 ):
2207 # either raw palette data needs to be decoded,
2208 # or the core image needs its mode updated
2209 self.load()
2211 def _get_palette_color(self, value: tuple[int, ...]) -> tuple[int, ...] | int:
2212 if len(value) in {3, 4}:
2213 # RGB or RGBA value for a P or PA image
2214 if self.mode == "PA":
2215 alpha = value[3] if len(value) == 4 else 255
2216 value = value[:3]
2217 assert self.palette is not None
2218 palette_index = self.palette.getcolor(value, self)
2219 return (palette_index, alpha) if self.mode == "PA" else palette_index
2220 return value
2222 def putpixel(
2223 self,
2224 xy: tuple[int, int] | list[int],
2225 value: float | tuple[int, ...],
2226 ) -> None:
2227 """
2228 Modifies the pixel at the given position. The color is given as
2229 a single numerical value for single-band images, and a tuple for
2230 multi-band images. In addition to this, RGB and RGBA tuples are
2231 accepted for P and PA images. See :ref:`colors` for more information.
2233 Note that this method is relatively slow. For more extensive changes,
2234 use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
2235 module instead.
2237 See:
2239 * :py:meth:`~PIL.Image.Image.paste`
2240 * :py:meth:`~PIL.Image.Image.putdata`
2241 * :py:mod:`~PIL.ImageDraw`
2243 :param xy: The pixel coordinate, given as (x, y). See
2244 :ref:`coordinate-system`.
2245 :param value: The pixel value.
2246 """
2248 self._ensure_mutable()
2250 if self.mode in {"P", "PA"}:
2251 if isinstance(value, list) and len(value) in {3, 4}: # type: ignore[unreachable]
2252 deprecate("'value' lists", 15, "tuples", plural=True) # type: ignore[unreachable]
2254 value = tuple(value)
2255 if isinstance(value, tuple):
2256 value = self._get_palette_color(value)
2257 return self.im.putpixel(xy, value)
2259 def remap_palette(
2260 self, dest_map: list[int], source_palette: bytes | bytearray | None = None
2261 ) -> Image:
2262 """
2263 Rewrites the image to reorder the palette.
2265 :param dest_map: A list of indexes into the original palette.
2266 e.g. ``[1,0]`` would swap a two item palette, and ``list(range(256))``
2267 is the identity transform.
2268 :param source_palette: Bytes or None.
2269 :returns: An :py:class:`~PIL.Image.Image` object.
2271 """
2272 from . import ImagePalette
2274 if self.mode not in ("L", "P"):
2275 msg = "illegal image mode"
2276 raise ValueError(msg)
2278 bands = 3
2279 palette_mode = "RGB"
2280 if source_palette is None:
2281 if self.mode == "P":
2282 self.load()
2283 palette_mode = self.im.getpalettemode()
2284 if palette_mode == "RGBA":
2285 bands = 4
2286 source_palette = self.im.getpalette()
2287 else: # L-mode
2288 source_palette = bytearray(i // 3 for i in range(768))
2289 elif len(source_palette) > 768:
2290 bands = 4
2291 palette_mode = "RGBA"
2293 palette_bytes = b""
2294 new_positions = [0] * 256
2296 # pick only the used colors from the palette
2297 for i, oldPosition in enumerate(dest_map):
2298 palette_bytes += source_palette[
2299 oldPosition * bands : oldPosition * bands + bands
2300 ]
2301 new_positions[oldPosition] = i
2303 # replace the palette color id of all pixel with the new id
2305 # Palette images are [0..255], mapped through a 1 or 3
2306 # byte/color map. We need to remap the whole image
2307 # from palette 1 to palette 2. New_positions is
2308 # an array of indexes into palette 1. Palette 2 is
2309 # palette 1 with any holes removed.
2311 # We're going to leverage the convert mechanism to use the
2312 # C code to remap the image from palette 1 to palette 2,
2313 # by forcing the source image into 'L' mode and adding a
2314 # mapping 'L' mode palette, then converting back to 'L'
2315 # sans palette thus converting the image bytes, then
2316 # assigning the optimized RGB palette.
2318 # perf reference, 9500x4000 gif, w/~135 colors
2319 # 14 sec prepatch, 1 sec postpatch with optimization forced.
2321 mapping_palette = bytearray(new_positions)
2323 m_im = self.copy()
2324 m_im._mode = "P"
2326 m_im.palette = ImagePalette.ImagePalette(
2327 palette_mode, palette=mapping_palette * bands
2328 )
2329 # possibly set palette dirty, then
2330 # m_im.putpalette(mapping_palette, 'L') # converts to 'P'
2331 # or just force it.
2332 # UNDONE -- this is part of the general issue with palettes
2333 m_im.im.putpalette(palette_mode, palette_mode + ";L", m_im.palette.tobytes())
2335 m_im = m_im.convert("L")
2337 m_im.putpalette(palette_bytes, palette_mode)
2339 if "transparency" in self.info:
2340 try:
2341 m_im.info["transparency"] = dest_map.index(self.info["transparency"])
2342 except ValueError:
2343 if "transparency" in m_im.info:
2344 del m_im.info["transparency"]
2346 return m_im
2348 def _get_safe_box(
2349 self,
2350 size: tuple[int, int],
2351 resample: Resampling,
2352 box: tuple[float, float, float, float],
2353 ) -> tuple[int, int, int, int]:
2354 """Expands the box so it includes adjacent pixels
2355 that may be used by resampling with the given resampling filter.
2356 """
2357 filter_support = _filters_support[resample] - 0.5
2358 scale_x = (box[2] - box[0]) / size[0]
2359 scale_y = (box[3] - box[1]) / size[1]
2360 support_x = filter_support * scale_x
2361 support_y = filter_support * scale_y
2363 return (
2364 max(0, int(box[0] - support_x)),
2365 max(0, int(box[1] - support_y)),
2366 min(self.size[0], math.ceil(box[2] + support_x)),
2367 min(self.size[1], math.ceil(box[3] + support_y)),
2368 )
2370 def resize(
2371 self,
2372 size: tuple[int, int] | list[int] | NumpyArray,
2373 resample: int | None = None,
2374 box: tuple[float, float, float, float] | None = None,
2375 reducing_gap: float | None = None,
2376 ) -> Image:
2377 """
2378 Returns a resized copy of this image.
2380 :param size: The requested size in pixels, as a tuple or array:
2381 (width, height).
2382 :param resample: An optional resampling filter. This can be
2383 one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2384 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2385 :py:data:`Resampling.BICUBIC`, :py:data:`Resampling.LANCZOS`,
2386 :py:data:`Resampling.MKS2013`, or :py:data:`Resampling.MKS2021`.
2387 If the image has mode "1", "P" or "PA", it is always set to
2388 :py:data:`Resampling.NEAREST`. Otherwise, the default filter is
2389 :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`.
2390 :param box: An optional 4-tuple of floats providing
2391 the source image region to be scaled.
2392 The values must be within (0, 0, width, height) rectangle.
2393 If omitted or None, the entire source is used.
2394 :param reducing_gap: Apply optimization by resizing the image
2395 in two steps. First, reducing the image by integer times
2396 using :py:meth:`~PIL.Image.Image.reduce`.
2397 Second, resizing using regular resampling. The last step
2398 changes size no less than by ``reducing_gap`` times.
2399 ``reducing_gap`` may be None (no first step is performed)
2400 or should be greater than 1.0. The bigger ``reducing_gap``,
2401 the closer the result to the fair resampling.
2402 The smaller ``reducing_gap``, the faster resizing.
2403 With ``reducing_gap`` greater or equal to 3.0, the result is
2404 indistinguishable from fair resampling in most cases.
2405 The default value is None (no optimization).
2406 :returns: An :py:class:`~PIL.Image.Image` object.
2407 """
2409 if resample is None:
2410 resample = Resampling.BICUBIC
2411 elif resample not in (
2412 Resampling.NEAREST,
2413 Resampling.BILINEAR,
2414 Resampling.BICUBIC,
2415 Resampling.LANCZOS,
2416 Resampling.BOX,
2417 Resampling.HAMMING,
2418 Resampling.MKS2013,
2419 Resampling.MKS2021,
2420 ):
2421 msg = f"Unknown resampling filter ({resample})."
2423 filters = [
2424 f"{filter[1]} ({filter[0]})"
2425 for filter in (
2426 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
2427 (Resampling.LANCZOS, "Image.Resampling.LANCZOS"),
2428 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
2429 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
2430 (Resampling.BOX, "Image.Resampling.BOX"),
2431 (Resampling.HAMMING, "Image.Resampling.HAMMING"),
2432 (Resampling.MKS2013, "Image.Resampling.MKS2013"),
2433 (Resampling.MKS2021, "Image.Resampling.MKS2021"),
2434 )
2435 ]
2436 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
2437 raise ValueError(msg)
2439 if reducing_gap is not None and reducing_gap < 1.0:
2440 msg = "reducing_gap must be 1.0 or greater"
2441 raise ValueError(msg)
2443 if box is None:
2444 box = (0, 0, *self.size)
2446 size = tuple(size)
2447 if self.size == size and box == (0, 0, *self.size):
2448 return self.copy()
2450 if self.mode in {"1", "P", "PA"}:
2451 resample = Resampling.NEAREST
2453 if self.mode in {"LA", "RGBA"} and resample != Resampling.NEAREST:
2454 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2455 im = im.resize(size, resample, box, reducing_gap)
2456 return im.convert(self.mode)
2458 self.load()
2460 if reducing_gap is not None and resample != Resampling.NEAREST:
2461 factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1
2462 factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1
2463 if factor_x > 1 or factor_y > 1:
2464 reduce_box = self._get_safe_box(size, cast("Resampling", resample), box)
2465 factor = (factor_x, factor_y)
2466 self = (
2467 self.reduce(factor, box=reduce_box)
2468 if callable(self.reduce)
2469 else Image.reduce(self, factor, box=reduce_box)
2470 )
2471 box = (
2472 (box[0] - reduce_box[0]) / factor_x,
2473 (box[1] - reduce_box[1]) / factor_y,
2474 (box[2] - reduce_box[0]) / factor_x,
2475 (box[3] - reduce_box[1]) / factor_y,
2476 )
2478 return self._new(self.im.resize(size, resample, box))
2480 def reduce(
2481 self,
2482 factor: int | tuple[int, int],
2483 box: tuple[int, int, int, int] | None = None,
2484 ) -> Image:
2485 """
2486 Returns a copy of the image reduced ``factor`` times.
2487 If the size of the image is not dividable by ``factor``,
2488 the resulting size will be rounded up.
2490 :param factor: A greater than 0 integer or tuple of two integers
2491 for width and height separately.
2492 :param box: An optional 4-tuple of ints providing
2493 the source image region to be reduced.
2494 The values must be within ``(0, 0, width, height)`` rectangle.
2495 If omitted or ``None``, the entire source is used.
2496 """
2497 if not isinstance(factor, (list, tuple)):
2498 factor = (factor, factor)
2500 if factor == (1, 1):
2501 return self.crop(box)
2503 if box is None:
2504 box = (0, 0, *self.size)
2506 if self.mode in ["LA", "RGBA"]:
2507 im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
2508 im = im.reduce(factor, box)
2509 return im.convert(self.mode)
2511 self.load()
2513 return self._new(self.im.reduce(factor, box))
2515 def rotate(
2516 self,
2517 angle: float,
2518 resample: Resampling = Resampling.NEAREST,
2519 expand: int | bool = False,
2520 center: tuple[float, float] | None = None,
2521 translate: tuple[int, int] | None = None,
2522 fillcolor: float | tuple[float, ...] | str | None = None,
2523 ) -> Image:
2524 """
2525 Returns a rotated copy of this image. This method returns a
2526 copy of this image, rotated the given number of degrees counter
2527 clockwise around its centre.
2529 :param angle: In degrees counterclockwise.
2530 :param resample: An optional resampling filter. This can be
2531 one of :py:data:`Resampling.NEAREST` (use nearest neighbour),
2532 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
2533 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
2534 interpolation in a 4x4 environment). If omitted, or if the image has
2535 mode "1", "P" or "PA", it is set to :py:data:`Resampling.NEAREST`.
2536 See :ref:`concept-filters`.
2537 :param expand: Optional expansion flag. If true, expands the output
2538 image to make it large enough to hold the entire rotated image.
2539 If false or omitted, make the output image the same size as the
2540 input image. Note that the expand flag assumes rotation around
2541 the center and no translation.
2542 :param center: Optional center of rotation (a 2-tuple). Origin is
2543 the upper left corner. Default is the center of the image.
2544 :param translate: An optional post-rotate translation (a 2-tuple).
2545 :param fillcolor: An optional color for area outside the rotated image.
2546 :returns: An :py:class:`~PIL.Image.Image` object.
2547 """
2549 angle = angle % 360.0
2550 if math.isnan(angle):
2551 msg = "invalid angle"
2552 raise ValueError(msg)
2554 # Fast paths regardless of filter, as long as we're not
2555 # translating or changing the center.
2556 if not (center or translate):
2557 if angle == 0:
2558 return self.copy()
2559 if angle == 180:
2560 return self.transpose(Transpose.ROTATE_180)
2561 if angle in (90, 270) and (expand or self.width == self.height):
2562 return self.transpose(
2563 Transpose.ROTATE_90 if angle == 90 else Transpose.ROTATE_270
2564 )
2566 # Calculate the affine matrix. Note that this is the reverse
2567 # transformation (from destination image to source) because we
2568 # want to interpolate the (discrete) destination pixel from
2569 # the local area around the (floating) source pixel.
2571 # The matrix we actually want (note that it operates from the right):
2572 # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx)
2573 # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
2574 # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1)
2576 # The reverse matrix is thus:
2577 # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx)
2578 # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
2579 # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1)
2581 # In any case, the final translation may be updated at the end to
2582 # compensate for the expand flag.
2584 w, h = self.size
2586 if translate is None:
2587 post_trans = (0, 0)
2588 else:
2589 post_trans = translate
2590 if center is None:
2591 center = (w / 2, h / 2)
2593 angle = -math.radians(angle)
2594 matrix = [
2595 round(math.cos(angle), 15),
2596 round(math.sin(angle), 15),
2597 0.0,
2598 round(-math.sin(angle), 15),
2599 round(math.cos(angle), 15),
2600 0.0,
2601 ]
2603 def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]:
2604 a, b, c, d, e, f = matrix
2605 return a * x + b * y + c, d * x + e * y + f
2607 matrix[2], matrix[5] = transform(
2608 -center[0] - post_trans[0], -center[1] - post_trans[1], matrix
2609 )
2610 matrix[2] += center[0]
2611 matrix[5] += center[1]
2613 if expand:
2614 # calculate output size
2615 xx = []
2616 yy = []
2617 for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
2618 transformed_x, transformed_y = transform(x, y, matrix)
2619 xx.append(transformed_x)
2620 yy.append(transformed_y)
2621 nw = math.ceil(max(xx)) - math.floor(min(xx))
2622 nh = math.ceil(max(yy)) - math.floor(min(yy))
2624 # We multiply a translation matrix from the right. Because of its
2625 # special form, this is the same as taking the image of the
2626 # translation vector as new translation vector.
2627 matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
2628 w, h = nw, nh
2630 return self.transform(
2631 (w, h), Transform.AFFINE, matrix, resample, fillcolor=fillcolor
2632 )
2634 def save(
2635 self, fp: StrOrBytesPath | IO[bytes], format: str | None = None, **params: Any
2636 ) -> None:
2637 """
2638 Saves this image under the given filename. If no format is
2639 specified, the format to use is determined from the filename
2640 extension, if possible.
2642 Keyword options can be used to provide additional instructions
2643 to the writer. If a writer doesn't recognise an option, it is
2644 silently ignored. The available options are described in the
2645 :doc:`image format documentation
2646 <../handbook/image-file-formats>` for each writer.
2648 You can use a file object instead of a filename. In this case,
2649 you must always specify the format. The file object must
2650 implement the ``seek``, ``tell``, and ``write``
2651 methods, and be opened in binary mode.
2653 :param fp: A filename (string), os.PathLike object or file object.
2654 :param format: Optional format override. If omitted, the
2655 format to use is determined from the filename extension.
2656 If a file object was used instead of a filename, this
2657 parameter should always be used.
2658 :param params: Extra parameters to the image writer. These can also be
2659 set on the image itself through ``encoderinfo``. This is useful when
2660 saving multiple images::
2662 # Saving XMP data to a single image
2663 from PIL import Image
2664 red = Image.new("RGB", (1, 1), "#f00")
2665 red.save("out.mpo", xmp=b"test")
2667 # Saving XMP data to the second frame of an image
2668 from PIL import Image
2669 black = Image.new("RGB", (1, 1))
2670 red = Image.new("RGB", (1, 1), "#f00")
2671 red.encoderinfo = {"xmp": b"test"}
2672 black.save("out.mpo", save_all=True, append_images=[red])
2673 :returns: None
2674 :exception ValueError: If the output format could not be determined
2675 from the file name. Use the format option to solve this.
2676 :exception OSError: If the file could not be written. The file
2677 may have been created, and may contain partial data.
2678 """
2680 filename: str | bytes = ""
2681 open_fp = False
2682 if is_path(fp):
2683 filename = os.fspath(fp)
2684 open_fp = True
2685 elif fp == sys.stdout and isinstance(sys.stdout, io.TextIOWrapper):
2686 fp = sys.stdout.buffer
2687 if not filename and hasattr(fp, "name") and is_path(fp.name):
2688 # only set the name for metadata purposes
2689 filename = os.fspath(fp.name)
2691 if format:
2692 preinit()
2693 else:
2694 filename_ext = os.path.splitext(filename)[1].lower()
2695 ext = (
2696 filename_ext.decode()
2697 if isinstance(filename_ext, bytes)
2698 else filename_ext
2699 )
2701 # Try importing only the plugin for this extension first
2702 if not _import_plugin_for_extension(ext):
2703 preinit()
2705 if ext not in EXTENSION:
2706 init()
2707 try:
2708 format = EXTENSION[ext]
2709 except KeyError as e:
2710 msg = f"unknown file extension: {ext}"
2711 raise ValueError(msg) from e
2713 from . import ImageFile
2715 # may mutate self!
2716 if isinstance(self, ImageFile.ImageFile) and os.path.abspath(
2717 filename
2718 ) == os.path.abspath(self.filename):
2719 self._ensure_mutable()
2720 else:
2721 self.load()
2723 save_all = params.pop("save_all", None)
2724 self._default_encoderinfo = params
2725 encoderinfo = getattr(self, "encoderinfo", {})
2726 self._attach_default_encoderinfo(self)
2727 self.encoderconfig: tuple[Any, ...] = ()
2729 if format.upper() not in SAVE:
2730 init()
2731 if save_all or (
2732 save_all is None
2733 and params.get("append_images")
2734 and format.upper() in SAVE_ALL
2735 ):
2736 save_handler = SAVE_ALL[format.upper()]
2737 else:
2738 save_handler = SAVE[format.upper()]
2740 created = False
2741 if open_fp:
2742 created = not os.path.exists(filename)
2743 if params.get("append", False):
2744 # Open also for reading ("+"), because TIFF save_all
2745 # writer needs to go back and edit the written data.
2746 fp = builtins.open(filename, "r+b")
2747 else:
2748 fp = builtins.open(filename, "w+b")
2749 else:
2750 fp = cast("IO[bytes]", fp)
2752 try:
2753 save_handler(self, fp, filename)
2754 except Exception:
2755 if open_fp:
2756 fp.close()
2757 if created:
2758 try:
2759 os.remove(filename)
2760 except PermissionError:
2761 pass
2762 raise
2763 finally:
2764 self.encoderinfo = encoderinfo
2765 if open_fp:
2766 fp.close()
2768 def _attach_default_encoderinfo(self, im: Image) -> dict[str, Any]:
2769 encoderinfo = getattr(self, "encoderinfo", {})
2770 self.encoderinfo = {**im._default_encoderinfo, **encoderinfo}
2771 return encoderinfo
2773 def seek(self, frame: int) -> None:
2774 """
2775 Seeks to the given frame in this sequence file. If you seek
2776 beyond the end of the sequence, the method raises an
2777 ``EOFError`` exception. When a sequence file is opened, the
2778 library automatically seeks to frame 0.
2780 See :py:meth:`~PIL.Image.Image.tell`.
2782 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2783 number of available frames.
2785 :param frame: Frame number, starting at 0.
2786 :exception EOFError: If the call attempts to seek beyond the end
2787 of the sequence.
2788 """
2790 # overridden by file handlers
2791 if frame != self.tell():
2792 # The file handler likely did not override this method
2793 msg = "no more images in file"
2794 raise EOFError(msg)
2796 if self._im is not None and (
2797 self.im.size != self.size or self.im.mode != self.mode
2798 ):
2799 self._im = None
2801 def show(self, title: str | None = None) -> None:
2802 """
2803 Displays this image. This method is mainly intended for debugging purposes.
2805 This method calls :py:func:`PIL.ImageShow.show` internally. You can use
2806 :py:func:`PIL.ImageShow.register` to override its default behaviour.
2808 The image is first saved to a temporary file. By default, it will be in
2809 PNG format.
2811 On Unix, the image is then opened using the **xdg-open**, **display**,
2812 **gm**, **eog** or **xv** utility, depending on which one can be found.
2814 On macOS, the image is opened with the native Preview application.
2816 On Windows, the image is opened with the standard PNG display utility.
2818 :param title: Optional title to use for the image window, where possible.
2819 """
2821 from . import ImageShow
2823 ImageShow.show(self, title)
2825 def split(self) -> tuple[Image, ...]:
2826 """
2827 Split this image into individual bands. This method returns a
2828 tuple of individual image bands from an image. For example,
2829 splitting an "RGB" image creates three new images each
2830 containing a copy of one of the original bands (red, green,
2831 blue).
2833 If you need only one band, :py:meth:`~PIL.Image.Image.getchannel`
2834 method can be more convenient and faster.
2836 :returns: A tuple containing bands.
2837 """
2839 self.load()
2840 if self.im.bands == 1:
2841 return (self.copy(),)
2842 return tuple(map(self._new, self.im.split()))
2844 def getchannel(self, channel: int | str) -> Image:
2845 """
2846 Returns an image containing a single channel of the source image.
2848 :param channel: What channel to return. Could be index
2849 (0 for "R" channel of "RGB") or channel name
2850 ("A" for alpha channel of "RGBA").
2851 :returns: An image in "L" mode.
2853 .. versionadded:: 4.3.0
2854 """
2855 self.load()
2857 if isinstance(channel, str):
2858 try:
2859 channel = self.getbands().index(channel)
2860 except ValueError as e:
2861 msg = f'The image has no channel "{channel}"'
2862 raise ValueError(msg) from e
2864 return self._new(self.im.getband(channel))
2866 def tell(self) -> int:
2867 """
2868 Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
2870 If defined, :attr:`~PIL.Image.Image.n_frames` refers to the
2871 number of available frames.
2873 :returns: Frame number, starting with 0.
2874 """
2875 return 0
2877 def thumbnail(
2878 self,
2879 size: tuple[float, float],
2880 resample: Resampling = Resampling.BICUBIC,
2881 reducing_gap: float | None = 2.0,
2882 ) -> None:
2883 """
2884 Make this image into a thumbnail. This method modifies the
2885 image to contain a thumbnail version of itself, no larger than
2886 the given size. This method calculates an appropriate thumbnail
2887 size to preserve the aspect of the image, calls the
2888 :py:meth:`~PIL.Image.Image.draft` method to configure the file reader
2889 (where applicable), and finally resizes the image.
2891 Note that this function modifies the :py:class:`~PIL.Image.Image`
2892 object in place. If you need to use the full resolution image as well,
2893 apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
2894 image.
2896 :param size: The requested size in pixels, as a 2-tuple:
2897 (width, height).
2898 :param resample: Optional resampling filter. This can be one
2899 of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
2900 :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
2901 :py:data:`Resampling.BICUBIC`, :py:data:`Resampling.LANCZOS`,
2902 :py:data:`Resampling.MKS2013`, or :py:data:`Resampling.MKS2021`.
2903 If omitted, it defaults to :py:data:`Resampling.BICUBIC`.
2904 (was :py:data:`Resampling.NEAREST` prior to version 2.5.0).
2905 See: :ref:`concept-filters`.
2906 :param reducing_gap: Apply optimization by resizing the image
2907 in two steps. First, reducing the image by integer times
2908 using :py:meth:`~PIL.Image.Image.reduce` or
2909 :py:meth:`~PIL.Image.Image.draft` for JPEG images.
2910 Second, resizing using regular resampling. The last step
2911 changes size no less than by ``reducing_gap`` times.
2912 ``reducing_gap`` may be None (no first step is performed)
2913 or should be greater than 1.0. The bigger ``reducing_gap``,
2914 the closer the result to the fair resampling.
2915 The smaller ``reducing_gap``, the faster resizing.
2916 With ``reducing_gap`` greater or equal to 3.0, the result is
2917 indistinguishable from fair resampling in most cases.
2918 The default value is 2.0 (very close to fair resampling
2919 while still being faster in many cases).
2920 :returns: None
2921 """
2923 provided_size = tuple(map(math.floor, size))
2925 def preserve_aspect_ratio() -> tuple[int, int] | None:
2926 def round_aspect(number: float, key: Callable[[int], float]) -> int:
2927 return min(math.floor(number), math.ceil(number), key=key)
2929 x, y = provided_size
2930 if x >= self.width and y >= self.height:
2931 return None
2932 if self.height == 0:
2933 return x, self.height
2935 aspect = self.width / self.height
2936 if x / y >= aspect:
2937 x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y))
2938 else:
2939 y = round_aspect(
2940 x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n)
2941 )
2942 return x, y
2944 preserved_size = preserve_aspect_ratio()
2945 if preserved_size is None:
2946 return
2947 final_size = preserved_size
2949 box = None
2950 if reducing_gap is not None:
2951 res = self.draft(
2952 None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
2953 )
2954 if res is not None:
2955 box = res[1]
2957 if self.size != final_size:
2958 if min(final_size) == 0:
2959 im = self.crop((0, 0, *final_size))
2960 else:
2961 im = self.resize(
2962 final_size, resample, box=box, reducing_gap=reducing_gap
2963 )
2965 self.im = im.im
2966 self._size = final_size
2967 self._mode = self.im.mode
2969 self.readonly = 0
2971 # FIXME: the different transform methods need further explanation
2972 # instead of bloating the method docs, add a separate chapter.
2973 def transform(
2974 self,
2975 size: tuple[int, int],
2976 method: Transform | ImageTransformHandler | SupportsGetData,
2977 data: Sequence[Any] | None = None,
2978 resample: int = Resampling.NEAREST,
2979 fill: int = 1,
2980 fillcolor: float | tuple[float, ...] | str | None = None,
2981 ) -> Image:
2982 """
2983 Transforms this image. This method creates a new image with the
2984 given size, and the same mode as the original, and copies data
2985 to the new image using the given transform.
2987 :param size: The output size in pixels, as a 2-tuple:
2988 (width, height).
2989 :param method: The transformation method. This is one of
2990 :py:data:`Transform.EXTENT` (cut out a rectangular subregion),
2991 :py:data:`Transform.AFFINE` (affine transform),
2992 :py:data:`Transform.PERSPECTIVE` (perspective transform),
2993 :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or
2994 :py:data:`Transform.MESH` (map a number of source quadrilaterals
2995 in one operation).
2997 It may also be an :py:class:`~PIL.Image.ImageTransformHandler`
2998 object::
3000 class Example(Image.ImageTransformHandler):
3001 def transform(self, size, data, resample, fill=1):
3002 # Return result
3004 Implementations of :py:class:`~PIL.Image.ImageTransformHandler`
3005 for some of the :py:class:`Transform` methods are provided
3006 in :py:mod:`~PIL.ImageTransform`.
3008 It may also be an object with a ``method.getdata`` method
3009 that returns a tuple supplying new ``method`` and ``data`` values::
3011 class Example:
3012 def getdata(self):
3013 method = Image.Transform.EXTENT
3014 data = (0, 0, 100, 100)
3015 return method, data
3016 :param data: Extra data to the transformation method.
3017 :param resample: Optional resampling filter. It can be one of
3018 :py:data:`Resampling.NEAREST` (use nearest neighbour),
3019 :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2
3020 environment), or :py:data:`Resampling.BICUBIC` (cubic spline
3021 interpolation in a 4x4 environment). If omitted, or if the image
3022 has mode "1", "P" or "PA", it is set to :py:data:`Resampling.NEAREST`.
3023 See: :ref:`concept-filters`.
3024 :param fill: If ``method`` is an
3025 :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of
3026 the arguments passed to it. Otherwise, it is unused.
3027 :param fillcolor: Optional fill color for the area outside the
3028 transform in the output image.
3029 :returns: An :py:class:`~PIL.Image.Image` object.
3030 """
3032 if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST:
3033 return (
3034 self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode])
3035 .transform(size, method, data, resample, fill, fillcolor)
3036 .convert(self.mode)
3037 )
3039 if isinstance(method, ImageTransformHandler):
3040 return method.transform(size, self, resample=resample, fill=fill)
3042 if hasattr(method, "getdata"):
3043 # compatibility w. old-style transform objects
3044 method, data = method.getdata()
3046 if data is None:
3047 msg = "missing method data"
3048 raise ValueError(msg)
3050 palette = None
3051 if self.mode in {"P", "PA"} and self.palette:
3052 palette = self.palette.copy()
3053 if isinstance(fillcolor, str):
3054 from . import ImageColor
3056 fillcolor = ImageColor.getcolor(fillcolor, self.mode)
3057 if isinstance(fillcolor, tuple) and all(
3058 isinstance(i, int) for i in fillcolor
3059 ):
3060 fillcolor = palette.getcolor(cast("tuple[int, ...]", fillcolor), self)
3062 im = new(self.mode, size, fillcolor)
3063 im.info = self._copy_info()
3064 if method == Transform.MESH:
3065 # list of quads
3066 for box, quad in data:
3067 im.__transformer(
3068 box, self, Transform.QUAD, quad, resample, fillcolor is None
3069 )
3070 else:
3071 im.__transformer(
3072 (0, 0, *size), self, method, data, resample, fillcolor is None
3073 )
3074 if palette:
3075 im.palette = palette
3077 return im
3079 def __transformer(
3080 self,
3081 box: tuple[int, int, int, int],
3082 image: Image,
3083 method: Transform,
3084 data: Sequence[float],
3085 resample: int = Resampling.NEAREST,
3086 fill: bool = True,
3087 ) -> None:
3088 w = box[2] - box[0]
3089 h = box[3] - box[1]
3091 if method == Transform.AFFINE:
3092 data = data[:6]
3094 elif method == Transform.EXTENT:
3095 # convert extent to an affine transform
3096 x0, y0, x1, y1 = data
3097 xs = (x1 - x0) / w
3098 ys = (y1 - y0) / h
3099 method = Transform.AFFINE
3100 data = (xs, 0, x0, 0, ys, y0)
3102 elif method == Transform.PERSPECTIVE:
3103 data = data[:8]
3105 elif method == Transform.QUAD:
3106 # quadrilateral warp. data specifies the four corners
3107 # given as NW, SW, SE, and NE.
3108 nw = data[:2]
3109 sw = data[2:4]
3110 se = data[4:6]
3111 ne = data[6:8]
3112 x0, y0 = nw
3113 As = 1.0 / w
3114 At = 1.0 / h
3115 data = (
3116 x0,
3117 (ne[0] - x0) * As,
3118 (sw[0] - x0) * At,
3119 (se[0] - sw[0] - ne[0] + x0) * As * At,
3120 y0,
3121 (ne[1] - y0) * As,
3122 (sw[1] - y0) * At,
3123 (se[1] - sw[1] - ne[1] + y0) * As * At,
3124 )
3126 else:
3127 msg = "unknown transformation method"
3128 raise ValueError(msg)
3130 if resample not in (
3131 Resampling.NEAREST,
3132 Resampling.BILINEAR,
3133 Resampling.BICUBIC,
3134 ):
3135 if resample in (
3136 Resampling.BOX,
3137 Resampling.HAMMING,
3138 Resampling.LANCZOS,
3139 Resampling.MKS2013,
3140 Resampling.MKS2021,
3141 ):
3142 unusable: dict[int, str] = {
3143 Resampling.BOX: "Image.Resampling.BOX",
3144 Resampling.HAMMING: "Image.Resampling.HAMMING",
3145 Resampling.LANCZOS: "Image.Resampling.LANCZOS",
3146 Resampling.MKS2013: "Image.Resampling.MKS2013",
3147 Resampling.MKS2021: "Image.Resampling.MKS2021",
3148 }
3149 msg = unusable[resample] + f" ({resample}) cannot be used."
3150 else:
3151 msg = f"Unknown resampling filter ({resample})."
3153 filters = [
3154 f"{filter[1]} ({filter[0]})"
3155 for filter in (
3156 (Resampling.NEAREST, "Image.Resampling.NEAREST"),
3157 (Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
3158 (Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
3159 )
3160 ]
3161 msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
3162 raise ValueError(msg)
3164 image.load()
3166 self.load()
3168 if image.mode in {"1", "P", "PA"}:
3169 resample = Resampling.NEAREST
3171 self.im.transform(box, image.im, method, data, resample, fill)
3173 def transpose(self, method: Transpose) -> Image:
3174 """
3175 Transpose image (flip or rotate in 90 degree steps)
3177 :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`,
3178 :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`,
3179 :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`,
3180 :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`.
3181 :returns: Returns a flipped or rotated copy of this image.
3182 """
3184 self.load()
3185 return self._new(self.im.transpose(method))
3187 def effect_spread(self, distance: int) -> Image:
3188 """
3189 Randomly spread pixels in an image.
3191 :param distance: Distance to spread pixels.
3192 """
3193 self.load()
3194 return self._new(self.im.effect_spread(distance))
3196 def toqimage(self) -> ImageQt.ImageQt:
3197 """Returns a QImage copy of this image"""
3198 from . import ImageQt
3200 if not ImageQt.qt_is_installed:
3201 msg = "Qt bindings are not installed"
3202 raise ImportError(msg)
3203 return ImageQt.toqimage(self)
3205 def toqpixmap(self) -> ImageQt.QPixmap:
3206 """Returns a QPixmap copy of this image"""
3207 from . import ImageQt
3209 if not ImageQt.qt_is_installed:
3210 msg = "Qt bindings are not installed"
3211 raise ImportError(msg)
3212 return ImageQt.toqpixmap(self)
3215# --------------------------------------------------------------------
3216# Abstract handlers.
3219class ImagePointHandler(abc.ABC):
3220 """
3221 Used as a mixin by point transforms
3222 (for use with :py:meth:`~PIL.Image.Image.point`)
3223 """
3225 @abc.abstractmethod
3226 def point(self, im: Image) -> Image:
3227 pass
3230class ImageTransformHandler(abc.ABC):
3231 """
3232 Used as a mixin by geometry transforms
3233 (for use with :py:meth:`~PIL.Image.Image.transform`)
3234 """
3236 @abc.abstractmethod
3237 def transform(
3238 self,
3239 size: tuple[int, int],
3240 image: Image,
3241 **options: Any,
3242 ) -> Image:
3243 pass
3246# --------------------------------------------------------------------
3247# Factories
3250def _check_size(size: Any) -> None:
3251 """
3252 Common check to enforce type and sanity check on size tuples
3254 :param size: Should be a 2 tuple of (width, height)
3255 :returns: None, or raises a ValueError
3256 """
3258 if not isinstance(size, (list, tuple)):
3259 msg = "Size must be a list or tuple"
3260 raise ValueError(msg)
3261 if len(size) != 2:
3262 msg = "Size must be a sequence of length 2"
3263 raise ValueError(msg)
3264 if size[0] < 0 or size[1] < 0:
3265 msg = "Width and height must be >= 0"
3266 raise ValueError(msg)
3269def new(
3270 mode: str,
3271 size: tuple[int, int] | list[int],
3272 color: float | tuple[float, ...] | str | None = 0,
3273) -> Image:
3274 """
3275 Creates a new image with the given mode and size.
3277 :param mode: The mode to use for the new image. See: :ref:`concept-modes`.
3278 :param size: A 2-tuple, containing (width, height) in pixels.
3279 :param color: What color to use for the image. If given, this should be a single
3280 integer or floating point value for single-band modes, and a tuple for
3281 multi-band modes (one value per band). When creating RGB or HSV images, you can
3282 also use color strings as supported by the ImageColor module. See :ref:`colors`
3283 for more information. The default color is zero, which appears as black in
3284 single band or RGB-based images. ``None`` is also treated as zero.
3285 :returns: An :py:class:`~PIL.Image.Image` object.
3286 """
3288 _check_size(size)
3290 if color is None:
3291 # core.new() returns zeroed memory, so there is nothing to fill
3292 return Image()._new(core.new(mode, size))
3294 if isinstance(color, str):
3295 # css3-style specifier
3297 from . import ImageColor
3299 color = ImageColor.getcolor(color, mode)
3301 im = Image()
3302 if (
3303 mode in {"P", "PA"}
3304 and isinstance(color, tuple)
3305 and all(isinstance(i, int) for i in color)
3306 ):
3307 from . import ImagePalette
3309 im._mode = mode
3310 im.palette = ImagePalette.ImagePalette()
3311 color = im._get_palette_color(cast("tuple[int, ...]", color))
3312 return im._new(core.fill(mode, size, color))
3315def frombytes(
3316 mode: str,
3317 size: tuple[int, int],
3318 data: DecoderInput,
3319 decoder_name: str = "raw",
3320 *args: Any,
3321) -> Image:
3322 """
3323 Creates a copy of an image memory from pixel data in a buffer.
3325 In its simplest form, this function takes three arguments
3326 (mode, size, and unpacked pixel data).
3328 You can also use any pixel decoder supported by PIL. For more
3329 information on available decoders, see the section
3330 :ref:`Writing Your Own File Codec <file-codecs>`.
3332 Note that this function decodes pixel data only, not entire images.
3333 If you have an entire image in a string, wrap it in a
3334 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load
3335 it.
3337 :param mode: The image mode. See: :ref:`concept-modes`.
3338 :param size: The image size.
3339 :param data: A byte buffer containing raw data for the given mode.
3340 :param decoder_name: What decoder to use.
3341 :param args: Additional parameters for the given decoder.
3342 :returns: An :py:class:`~PIL.Image.Image` object.
3343 """
3345 _check_size(size)
3347 im = new(mode, size)
3348 if im.width != 0 and im.height != 0:
3349 decoder_args: Any = args
3350 if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple):
3351 # may pass tuple instead of argument list
3352 decoder_args = decoder_args[0]
3354 if decoder_name == "raw" and decoder_args == ():
3355 decoder_args = mode
3357 im.frombytes(data, decoder_name, decoder_args)
3358 return im
3361def frombuffer(
3362 mode: str,
3363 size: tuple[int, int],
3364 data: bytes | bytearray | SupportsArrayInterface,
3365 decoder_name: str = "raw",
3366 *args: Any,
3367) -> Image:
3368 """
3369 Creates an image memory referencing pixel data in a byte buffer.
3371 This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data
3372 in the byte buffer, where possible. This means that changes to the
3373 original buffer object are reflected in this image). Not all modes can
3374 share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK".
3376 Note that this function decodes pixel data only, not entire images.
3377 If you have an entire image file in a string, wrap it in a
3378 :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it.
3380 The default parameters used for the "raw" decoder differs from that used for
3381 :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a
3382 future release. The current release issues a warning if you do this; to disable
3383 the warning, you should provide the full set of parameters. See below for details.
3385 :param mode: The image mode. See: :ref:`concept-modes`.
3386 :param size: The image size.
3387 :param data: A bytes or other buffer object containing raw
3388 data for the given mode.
3389 :param decoder_name: What decoder to use.
3390 :param args: Additional parameters for the given decoder. For the
3391 default encoder ("raw"), it's recommended that you provide the
3392 full set of parameters::
3394 frombuffer(mode, size, data, "raw", mode, 0, 1)
3396 :returns: An :py:class:`~PIL.Image.Image` object.
3398 .. versionadded:: 1.1.4
3399 """
3401 _check_size(size)
3403 # may pass tuple instead of argument list
3404 if len(args) == 1 and isinstance(args[0], tuple):
3405 args = args[0]
3407 if decoder_name == "raw" and min(size) != 0:
3408 if args == ():
3409 args = mode, 0, 1
3410 if args[0] == mode and args[0] in _MAPMODES:
3411 im = Image()._new(core.map_buffer(data, size, decoder_name, 0, args))
3412 if mode == "P":
3413 from . import ImagePalette
3415 im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB"))
3416 return im
3418 return frombytes(mode, size, data, decoder_name, args)
3421class SupportsArrayInterface(Protocol):
3422 """
3423 An object that has an ``__array_interface__`` dictionary.
3424 """
3426 @property
3427 def __array_interface__(self) -> dict[str, Any]:
3428 raise NotImplementedError()
3431DecoderInput = bytes | bytearray | memoryview | SupportsArrayInterface
3434class SupportsArrowArrayInterface(Protocol):
3435 """
3436 An object that has an ``__arrow_c_array__`` method corresponding to the arrow c
3437 data interface.
3438 """
3440 def __arrow_c_array__(
3441 self, requested_schema: PyCapsule = None # type: ignore[name-defined] # noqa: F821
3442 ) -> tuple[PyCapsule, PyCapsule]: # type: ignore[name-defined] # noqa: F821
3443 raise NotImplementedError()
3446def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
3447 """
3448 Creates an image memory from an object exporting the array interface
3449 (using the buffer protocol)::
3451 from PIL import Image
3452 import numpy as np
3453 a = np.zeros((5, 5))
3454 im = Image.fromarray(a)
3456 If ``obj`` is not contiguous, then the ``tobytes`` method is called
3457 and :py:func:`~PIL.Image.frombuffer` is used.
3459 In the case of NumPy, be aware that Pillow modes do not always correspond
3460 to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels,
3461 32-bit signed integer pixels, and 32-bit floating point pixels.
3463 Pillow images can also be converted to arrays::
3465 from PIL import Image
3466 import numpy as np
3467 im = Image.open("hopper.jpg")
3468 a = np.asarray(im)
3470 When converting Pillow images to arrays however, only pixel values are
3471 transferred. This means that P and PA mode images will lose their palette.
3473 :param obj: Object with array interface
3474 :param mode: Optional mode to use when reading ``obj``. Since pixel values do not
3475 contain information about palettes or color spaces, this can be used to place
3476 grayscale L mode data within a P mode image, or read RGB data as YCbCr for
3477 example.
3479 See: :ref:`concept-modes` for general information about modes.
3480 :returns: An image object.
3482 .. versionadded:: 1.1.6
3483 """
3484 arr = obj.__array_interface__
3485 shape = arr["shape"]
3486 ndim = len(shape)
3487 strides = arr.get("strides", None)
3488 try:
3489 typekey = (1, 1) + shape[2:], arr["typestr"]
3490 except KeyError as e:
3491 if mode is not None:
3492 typekey = None
3493 color_modes: list[str] = []
3494 else:
3495 msg = "Cannot handle this data type"
3496 raise TypeError(msg) from e
3497 if typekey is not None:
3498 try:
3499 typemode, rawmode, color_modes = _fromarray_typemap[typekey]
3500 except KeyError as e:
3501 typekey_shape, typestr = typekey
3502 msg = f"Cannot handle this data type: {typekey_shape}, {typestr}"
3503 raise TypeError(msg) from e
3504 if mode is not None:
3505 if mode != typemode and mode not in color_modes:
3506 msg = "Invalid mode for data type"
3507 raise ValueError(msg)
3508 rawmode = mode
3509 else:
3510 mode = typemode
3511 if mode in ["1", "L", "I", "P", "F"]:
3512 ndmax = 2
3513 elif mode == "RGB":
3514 ndmax = 3
3515 else:
3516 ndmax = 4
3517 if ndim > ndmax:
3518 msg = f"Too many dimensions: {ndim} > {ndmax}."
3519 raise ValueError(msg)
3521 size = 1 if ndim == 1 else shape[1], shape[0]
3522 if strides is not None:
3523 if hasattr(obj, "tobytes"):
3524 obj = obj.tobytes()
3525 elif hasattr(obj, "tostring"):
3526 obj = obj.tostring()
3527 else:
3528 msg = "'strides' requires either tobytes() or tostring()"
3529 raise ValueError(msg)
3531 return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
3534def fromarrow(
3535 obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int]
3536) -> Image:
3537 """Creates an image with zero-copy shared memory from an object exporting
3538 the arrow_c_array interface protocol::
3540 from PIL import Image
3541 import pyarrow as pa
3542 arr = pa.array([0]*(5*5*4), type=pa.uint8())
3543 im = Image.fromarrow(arr, 'RGBA', (5, 5))
3545 If the data representation of the ``obj`` is not compatible with
3546 Pillow internal storage, a ValueError is raised.
3548 Pillow images can also be converted to Arrow objects::
3550 from PIL import Image
3551 import pyarrow as pa
3552 im = Image.open('hopper.jpg')
3553 arr = pa.array(im)
3555 As with array support, when converting Pillow images to arrays,
3556 only pixel values are transferred. This means that P and PA mode
3557 images will lose their palette.
3559 :param obj: Object with an arrow_c_array interface
3560 :param mode: Image mode.
3561 :param size: Image size. This must match the storage of the arrow object.
3562 :returns: An Image object
3564 Note that according to the Arrow spec, both the producer and the
3565 consumer should consider the exported array to be immutable, as
3566 unsynchronized updates will potentially cause inconsistent data.
3568 See: :ref:`arrow-support` for more detailed information
3570 .. versionadded:: 11.2.1
3572 """
3573 if not hasattr(obj, "__arrow_c_array__"):
3574 msg = "arrow_c_array interface not found"
3575 raise ValueError(msg)
3577 schema_capsule, array_capsule = obj.__arrow_c_array__()
3578 _im = core.new_arrow(mode, size, schema_capsule, array_capsule)
3579 if _im is not None:
3580 return Image()._new(_im)
3582 msg = "new_arrow returned None without an exception"
3583 raise ValueError(msg)
3586def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile:
3587 """Creates an image instance from a QImage image"""
3588 from . import ImageQt
3590 if not ImageQt.qt_is_installed:
3591 msg = "Qt bindings are not installed"
3592 raise ImportError(msg)
3593 return ImageQt.fromqimage(im)
3596def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile:
3597 """Creates an image instance from a QPixmap image"""
3598 from . import ImageQt
3600 if not ImageQt.qt_is_installed:
3601 msg = "Qt bindings are not installed"
3602 raise ImportError(msg)
3603 return ImageQt.fromqpixmap(im)
3606_fromarray_typemap = {
3607 # (shape, typestr) => mode, rawmode, color modes
3608 # first two members of shape are set to one
3609 ((1, 1), "|b1"): ("1", "1;8", []),
3610 ((1, 1), "|u1"): ("L", "L", ["P"]),
3611 ((1, 1), "|i1"): ("I", "I;8", []),
3612 ((1, 1), "<u2"): ("I;16", "I;16", []),
3613 ((1, 1), ">u2"): ("I;16B", "I;16B", []),
3614 ((1, 1), "<i2"): ("I", "I;16S", []),
3615 ((1, 1), ">i2"): ("I", "I;16BS", []),
3616 ((1, 1), "<u4"): ("I", "I;32", []),
3617 ((1, 1), ">u4"): ("I", "I;32B", []),
3618 ((1, 1), "<i4"): ("I", "I;32S", []),
3619 ((1, 1), ">i4"): ("I", "I;32BS", []),
3620 ((1, 1), "<f4"): ("F", "F;32F", []),
3621 ((1, 1), ">f4"): ("F", "F;32BF", []),
3622 ((1, 1), "<f8"): ("F", "F;64F", []),
3623 ((1, 1), ">f8"): ("F", "F;64BF", []),
3624 ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]),
3625 ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]),
3626 ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]),
3627 # shortcuts:
3628 ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []),
3629 ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []),
3630}
3633def _decompression_bomb_check(
3634 size: tuple[int, int], *, error_only: bool = False
3635) -> None:
3636 if MAX_IMAGE_PIXELS is None:
3637 return
3639 pixels = max(1, size[0]) * max(1, size[1])
3641 if pixels > 2 * MAX_IMAGE_PIXELS:
3642 msg = (
3643 f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} "
3644 "pixels, could be decompression bomb DOS attack."
3645 )
3646 raise DecompressionBombError(msg)
3648 if not error_only and pixels > MAX_IMAGE_PIXELS:
3649 warnings.warn(
3650 f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, "
3651 "could be decompression bomb DOS attack.",
3652 DecompressionBombWarning,
3653 )
3656def open(
3657 fp: StrOrBytesPath | IO[bytes],
3658 mode: Literal["r"] = "r",
3659 formats: list[str] | tuple[str, ...] | None = None,
3660) -> ImageFile.ImageFile:
3661 """
3662 Opens and identifies the given image file.
3664 This is a lazy operation; this function identifies the file, but
3665 the file remains open and the actual image data is not read from
3666 the file until you try to process the data (or call the
3667 :py:meth:`~PIL.Image.Image.load` method). See
3668 :py:func:`~PIL.Image.new`. See :ref:`file-handling`.
3670 :param fp: A filename (string), os.PathLike object or a file object.
3671 The file object must implement ``file.read``,
3672 ``file.seek``, and ``file.tell`` methods,
3673 and be opened in binary mode. The file object will also seek to zero
3674 before reading.
3675 :param mode: The mode. If given, this argument must be "r".
3676 :param formats: A list or tuple of formats to attempt to load the file in.
3677 This can be used to restrict the set of formats checked.
3678 Pass ``None`` to try all supported formats. You can print the set of
3679 available formats by running ``python3 -m PIL`` or using
3680 the :py:func:`PIL.features.pilinfo` function.
3681 :returns: An :py:class:`~PIL.Image.Image` object.
3682 :exception FileNotFoundError: If the file cannot be found.
3683 :exception PIL.UnidentifiedImageError: If the image cannot be opened and
3684 identified.
3685 :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO``
3686 instance is used for ``fp``.
3687 :exception TypeError: If ``formats`` is not ``None``, a list or a tuple.
3688 """
3690 if mode != "r":
3691 msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
3692 raise ValueError(msg)
3693 elif isinstance(fp, io.StringIO):
3694 msg = ( # type: ignore[unreachable]
3695 "StringIO cannot be used to open an image. "
3696 "Binary data must be used instead."
3697 )
3698 raise ValueError(msg)
3700 if formats is None:
3701 formats = ID
3702 elif not isinstance(formats, (list, tuple)):
3703 msg = "formats must be a list or tuple" # type: ignore[unreachable]
3704 raise TypeError(msg)
3706 exclusive_fp = False
3707 filename: str | bytes = ""
3708 if is_path(fp):
3709 filename = os.fspath(fp)
3710 fp = builtins.open(filename, "rb")
3711 exclusive_fp = True
3712 else:
3713 fp = cast("IO[bytes]", fp)
3715 try:
3716 fp.seek(0)
3717 except (AttributeError, io.UnsupportedOperation):
3718 fp = io.BytesIO(fp.read())
3719 exclusive_fp = True
3721 prefix = fp.read(16)
3723 # Try to import just the plugin needed for this file extension
3724 # before falling back to preinit() which imports common plugins
3725 ext = os.path.splitext(filename)[1] if filename else ""
3726 if not _import_plugin_for_extension(ext):
3727 preinit()
3729 warning_messages: list[str] = []
3731 def _open_core(
3732 fp: IO[bytes],
3733 filename: str | bytes,
3734 prefix: bytes,
3735 formats: list[str] | tuple[str, ...],
3736 ) -> ImageFile.ImageFile | None:
3737 for i in formats:
3738 i = i.upper()
3739 if i not in OPEN:
3740 init()
3741 try:
3742 factory, accept = OPEN[i]
3743 result = not accept or accept(prefix)
3744 if isinstance(result, str):
3745 warning_messages.append(result)
3746 elif result:
3747 fp.seek(0)
3748 im = factory(fp, filename)
3749 _decompression_bomb_check(im.size)
3750 return im
3751 except (SyntaxError, IndexError, TypeError, struct.error) as e:
3752 if WARN_POSSIBLE_FORMATS:
3753 warning_messages.append(i + " opening failed. " + str(e))
3754 except BaseException:
3755 if exclusive_fp:
3756 fp.close()
3757 raise
3758 return None
3760 im = _open_core(fp, filename, prefix, formats)
3762 if im is None and formats is ID:
3763 # Try preinit (few common plugins) then init (all plugins)
3764 for loader in (preinit, init):
3765 checked_formats = ID.copy()
3766 loader()
3767 if formats != checked_formats:
3768 im = _open_core(
3769 fp,
3770 filename,
3771 prefix,
3772 tuple(f for f in formats if f not in checked_formats),
3773 )
3774 if im is not None:
3775 break
3777 if im:
3778 im._exclusive_fp = exclusive_fp
3779 return im
3781 if exclusive_fp:
3782 fp.close()
3783 for message in warning_messages:
3784 warnings.warn(message)
3785 msg = "cannot identify image file %r" % (filename if filename else fp)
3786 raise UnidentifiedImageError(msg)
3789#
3790# Image processing.
3793def alpha_composite(im1: Image, im2: Image) -> Image:
3794 """
3795 Alpha composite im2 over im1.
3797 :param im1: The first image. Must have mode RGBA or LA.
3798 :param im2: The second image. Must have the same mode and size as the first image.
3799 :returns: An :py:class:`~PIL.Image.Image` object.
3800 """
3802 im1.load()
3803 im2.load()
3804 return im1._new(core.alpha_composite(im1.im, im2.im))
3807def blend(im1: Image, im2: Image, alpha: float) -> Image:
3808 """
3809 Creates a new image by interpolating between two input images, using
3810 a constant alpha::
3812 out = image1 * (1.0 - alpha) + image2 * alpha
3814 :param im1: The first image.
3815 :param im2: The second image. Must have the same mode and size as
3816 the first image.
3817 :param alpha: The interpolation alpha factor. If alpha is 0.0, a
3818 copy of the first image is returned. If alpha is 1.0, a copy of
3819 the second image is returned. There are no restrictions on the
3820 alpha value. If necessary, the result is clipped to fit into
3821 the allowed output range.
3822 :returns: An :py:class:`~PIL.Image.Image` object.
3823 """
3825 im1.load()
3826 im2.load()
3827 return im1._new(core.blend(im1.im, im2.im, alpha))
3830def composite(image1: Image, image2: Image, mask: Image) -> Image:
3831 """
3832 Create composite image by blending images using a transparency mask.
3834 :param image1: The first image.
3835 :param image2: The second image. Must have the same mode and
3836 size as the first image.
3837 :param mask: A mask image. This image can have mode
3838 "1", "L", or "RGBA", and must have the same size as the
3839 other two images.
3840 """
3842 image = image2.copy()
3843 image.paste(image1, None, mask)
3844 return image
3847def eval(image: Image, *args: Callable[[int], float]) -> Image:
3848 r"""
3849 Applies the function (which should take one argument) to each pixel
3850 in the given image. If the image has more than one band, the same
3851 function is applied to each band. Note that the function is
3852 evaluated once for each possible pixel value, so you cannot use
3853 random components or other generators.
3855 :param image: The input image.
3856 :param \*args: A function object, taking one integer argument.
3857 :returns: An :py:class:`~PIL.Image.Image` object.
3858 """
3860 return image.point(args[0])
3863def merge(mode: str, bands: Sequence[Image]) -> Image:
3864 """
3865 Merge a set of single band images into a new multiband image.
3867 :param mode: The mode to use for the output image. See:
3868 :ref:`concept-modes`.
3869 :param bands: A sequence containing one single-band image for
3870 each band in the output image. All bands must have the
3871 same size.
3872 :returns: An :py:class:`~PIL.Image.Image` object.
3873 """
3875 if getmodebands(mode) != len(bands):
3876 msg = "wrong number of bands"
3877 raise ValueError(msg)
3878 for band in bands[1:]:
3879 if band.mode != getmodetype(mode):
3880 msg = "mode mismatch"
3881 raise ValueError(msg)
3882 if band.size != bands[0].size:
3883 msg = "size mismatch"
3884 raise ValueError(msg)
3885 for band in bands:
3886 band.load()
3887 return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
3890# --------------------------------------------------------------------
3891# Plugin registry
3894def register_open(
3895 id: str,
3896 factory: (
3897 Callable[[IO[bytes], str | bytes], ImageFile.ImageFile]
3898 | type[ImageFile.ImageFile]
3899 ),
3900 accept: Callable[[bytes], bool | str] | None = None,
3901) -> None:
3902 """
3903 Register an image file plugin. This function should not be used
3904 in application code.
3906 :param id: An image format identifier.
3907 :param factory: An image file factory method.
3908 :param accept: An optional function that can be used to quickly
3909 reject images having another format.
3910 """
3911 id = id.upper()
3912 if id not in ID:
3913 ID.append(id)
3914 OPEN[id] = factory, accept
3917def register_mime(id: str, mimetype: str) -> None:
3918 """
3919 Registers an image MIME type by populating ``Image.MIME``. This function
3920 should not be used in application code.
3922 ``Image.MIME`` provides a mapping from image format identifiers to mime
3923 formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can
3924 provide a different result for specific images.
3926 :param id: An image format identifier.
3927 :param mimetype: The image MIME type for this format.
3928 """
3929 MIME[id.upper()] = mimetype
3932def register_save(
3933 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3934) -> None:
3935 """
3936 Registers an image save function. This function should not be
3937 used in application code.
3939 :param id: An image format identifier.
3940 :param driver: A function to save images in this format.
3941 """
3942 SAVE[id.upper()] = driver
3945def register_save_all(
3946 id: str, driver: Callable[[Image, IO[bytes], str | bytes], None]
3947) -> None:
3948 """
3949 Registers an image function to save all the frames
3950 of a multiframe format. This function should not be
3951 used in application code.
3953 :param id: An image format identifier.
3954 :param driver: A function to save images in this format.
3955 """
3956 SAVE_ALL[id.upper()] = driver
3959def register_extension(id: str, extension: str) -> None:
3960 """
3961 Registers an image extension. This function should not be
3962 used in application code.
3964 :param id: An image format identifier.
3965 :param extension: An extension used for this format.
3966 """
3967 EXTENSION[extension.lower()] = id.upper()
3970def register_extensions(id: str, extensions: list[str]) -> None:
3971 """
3972 Registers image extensions. This function should not be
3973 used in application code.
3975 :param id: An image format identifier.
3976 :param extensions: A list of extensions used for this format.
3977 """
3978 for extension in extensions:
3979 register_extension(id, extension)
3982def registered_extensions() -> dict[str, str]:
3983 """
3984 Returns a dictionary containing all file extensions belonging
3985 to registered plugins
3986 """
3987 init()
3988 return EXTENSION
3991def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None:
3992 """
3993 Registers an image decoder. This function should not be
3994 used in application code.
3996 :param name: The name of the decoder
3997 :param decoder: An ImageFile.PyDecoder object
3999 .. versionadded:: 4.1.0
4000 """
4001 DECODERS[name] = decoder
4004def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None:
4005 """
4006 Registers an image encoder. This function should not be
4007 used in application code.
4009 :param name: The name of the encoder
4010 :param encoder: An ImageFile.PyEncoder object
4012 .. versionadded:: 4.1.0
4013 """
4014 ENCODERS[name] = encoder
4017# --------------------------------------------------------------------
4018# Effects
4021def effect_mandelbrot(
4022 size: tuple[int, int], extent: tuple[float, float, float, float], quality: int
4023) -> Image:
4024 """
4025 Generate a Mandelbrot set covering the given extent.
4027 :param size: The requested size in pixels, as a 2-tuple:
4028 (width, height).
4029 :param extent: The extent to cover, as a 4-tuple:
4030 (x0, y0, x1, y1).
4031 :param quality: Quality.
4032 """
4033 return Image()._new(core.effect_mandelbrot(size, extent, quality))
4036def effect_noise(size: tuple[int, int], sigma: float) -> Image:
4037 """
4038 Generate Gaussian noise centered around 128.
4040 :param size: The requested size in pixels, as a 2-tuple:
4041 (width, height).
4042 :param sigma: Standard deviation of noise.
4043 """
4044 return Image()._new(core.effect_noise(size, sigma))
4047def linear_gradient(mode: str) -> Image:
4048 """
4049 Generate 256x256 linear gradient from black to white, top to bottom.
4051 :param mode: Input mode.
4052 """
4053 return Image()._new(core.linear_gradient(mode))
4056def radial_gradient(mode: str) -> Image:
4057 """
4058 Generate 256x256 radial gradient from black to white, centre to edge.
4060 :param mode: Input mode.
4061 """
4062 return Image()._new(core.radial_gradient(mode))
4065# --------------------------------------------------------------------
4066# Resources
4069def _apply_env_variables(env: dict[str, str] | None = None) -> None:
4070 env_dict = env if env is not None else os.environ
4072 for var_name, setter in [
4073 ("PILLOW_ALIGNMENT", core.set_alignment),
4074 ("PILLOW_BLOCK_SIZE", core.set_block_size),
4075 ("PILLOW_BLOCKS_MAX", core.set_blocks_max),
4076 ]:
4077 if var_name not in env_dict:
4078 continue
4080 var = env_dict[var_name].lower()
4082 units = 1
4083 for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]:
4084 if var.endswith(postfix):
4085 units = mul
4086 var = var[: -len(postfix)]
4088 try:
4089 var_int = int(var) * units
4090 except ValueError:
4091 warnings.warn(f"{var_name} is not int")
4092 continue
4094 try:
4095 setter(var_int)
4096 except ValueError as e:
4097 warnings.warn(f"{var_name}: {e}")
4100_apply_env_variables()
4101atexit.register(core.clear_cache)
4104if TYPE_CHECKING:
4105 _ExifBase = MutableMapping[int, Any]
4106else:
4107 _ExifBase = MutableMapping
4110class Exif(_ExifBase):
4111 """
4112 This class provides read and write access to EXIF image data::
4114 from PIL import Image
4115 im = Image.open("exif.png")
4116 exif = im.getexif() # Returns an instance of this class
4118 Information can be read and written, iterated over or deleted::
4120 print(exif[274]) # 1
4121 exif[274] = 2
4122 for k, v in exif.items():
4123 print("Tag", k, "Value", v) # Tag 274 Value 2
4124 del exif[274]
4126 To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd`
4127 returns a dictionary::
4129 from PIL import ExifTags
4130 im = Image.open("exif_gps.jpg")
4131 exif = im.getexif()
4132 gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo)
4133 print(gps_ifd)
4135 Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``,
4136 ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``.
4138 :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data::
4140 print(exif[ExifTags.Base.Software]) # PIL
4141 print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99
4142 """
4144 endian: str | None = None
4145 bigtiff = False
4146 _loaded = False
4148 def __init__(self) -> None:
4149 self._data: dict[int, Any] = {}
4150 self._hidden_data: dict[int, Any] = {}
4151 self._ifds: dict[int, dict[int, Any]] = {}
4152 self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None
4153 self._loaded_exif: bytes | None = None
4155 def _fixup(self, value: Any) -> Any:
4156 try:
4157 if len(value) == 1 and isinstance(value, tuple):
4158 return value[0]
4159 except Exception:
4160 pass
4161 return value
4163 def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]:
4164 # Helper function
4165 # returns a dict with any single item tuples/lists as individual values
4166 return {k: self._fixup(v) for k, v in src_dict.items()}
4168 def _get_ifd_dict(
4169 self, offset: int, group: int | None = None
4170 ) -> dict[int, Any] | None:
4171 try:
4172 # an offset pointer to the location of the nested embedded IFD.
4173 # It should be a long, but may be corrupted.
4174 self.fp.seek(offset)
4175 except (KeyError, TypeError):
4176 return None
4177 else:
4178 from . import TiffImagePlugin
4180 info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group)
4181 info.load(self.fp)
4182 return self._fixup_dict(dict(info))
4184 def _get_head(self) -> bytes:
4185 version = b"\x2b" if self.bigtiff else b"\x2a"
4186 if self.endian == "<":
4187 head = b"II" + version + b"\x00" + o32le(8)
4188 else:
4189 head = b"MM\x00" + version + o32be(8)
4190 if self.bigtiff:
4191 head += o32le(8) if self.endian == "<" else o32be(8)
4192 head += b"\x00\x00\x00\x00"
4193 return head
4195 def load(self, data: bytes) -> None:
4196 # Extract EXIF information. This is highly experimental,
4197 # and is likely to be replaced with something better in a future
4198 # version.
4200 # The EXIF record consists of a TIFF file embedded in a JPEG
4201 # application marker (!).
4202 if data == self._loaded_exif:
4203 return
4204 self._loaded_exif = data
4205 self._data.clear()
4206 self._hidden_data.clear()
4207 self._ifds.clear()
4208 data = re.sub(b"^(Exif\x00\x00){1,2}", b"", data)
4209 if not data:
4210 self._info = None
4211 return
4213 self.fp: IO[bytes] = io.BytesIO(data)
4214 self.head = self.fp.read(8)
4215 # process dictionary
4216 from . import TiffImagePlugin
4218 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4219 self.endian = self._info._endian
4220 self.fp.seek(self._info.next)
4221 self._info.load(self.fp)
4223 def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None:
4224 self._loaded_exif = None
4225 self._data.clear()
4226 self._hidden_data.clear()
4227 self._ifds.clear()
4229 # process dictionary
4230 from . import TiffImagePlugin
4232 self.fp = fp
4233 if offset is not None:
4234 self.head = self._get_head()
4235 else:
4236 self.head = self.fp.read(8)
4237 self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head)
4238 if self.endian is None:
4239 self.endian = self._info._endian
4240 if offset is None:
4241 offset = self._info.next
4242 self.fp.tell()
4243 self.fp.seek(offset)
4244 self._info.load(self.fp)
4246 def _get_merged_dict(self) -> dict[int, Any]:
4247 merged_dict = dict(self)
4249 # get EXIF extension
4250 if ExifTags.IFD.Exif in self:
4251 ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif)
4252 if ifd:
4253 merged_dict.update(ifd)
4255 # GPS
4256 if ExifTags.IFD.GPSInfo in self:
4257 merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict(
4258 self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo
4259 )
4261 return merged_dict
4263 def tobytes(self, offset: int = 8) -> bytes:
4264 from . import TiffImagePlugin
4266 head = self._get_head()
4267 ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head)
4268 for tag, ifd_dict in self._ifds.items():
4269 if tag in {ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo} and tag not in self:
4270 ifd[tag] = ifd_dict
4271 for tag, value in self.items():
4272 if tag in [
4273 ExifTags.IFD.Exif,
4274 ExifTags.IFD.GPSInfo,
4275 ] and not isinstance(value, dict):
4276 value = self.get_ifd(tag)
4277 if (
4278 tag == ExifTags.IFD.Exif
4279 and ExifTags.IFD.Interop in value
4280 and not isinstance(value[ExifTags.IFD.Interop], dict)
4281 ):
4282 value = value.copy()
4283 value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop)
4284 ifd[tag] = value
4285 return b"Exif\x00\x00" + head + ifd.tobytes(offset)
4287 def get_ifd(self, tag: int) -> dict[int, Any]:
4288 if tag not in self._ifds:
4289 if tag == ExifTags.IFD.IFD1:
4290 if self._info is not None and self._info.next != 0:
4291 ifd = self._get_ifd_dict(self._info.next)
4292 if ifd is not None:
4293 self._ifds[tag] = ifd
4294 elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
4295 offset = self._hidden_data.get(tag, self.get(tag))
4296 if offset is not None:
4297 ifd = self._get_ifd_dict(offset, tag)
4298 if ifd is not None:
4299 self._ifds[tag] = ifd
4300 elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]:
4301 if ExifTags.IFD.Exif not in self._ifds:
4302 self.get_ifd(ExifTags.IFD.Exif)
4303 tag_data = self._ifds[ExifTags.IFD.Exif].get(tag)
4304 if tag_data is None:
4305 pass
4306 elif tag == ExifTags.IFD.MakerNote:
4307 from .TiffImagePlugin import ImageFileDirectory_v2
4309 try:
4310 if tag_data.startswith(b"FUJIFILM"):
4311 ifd_offset = i32le(tag_data, 8)
4312 ifd_data = tag_data[ifd_offset:]
4314 makernote = {}
4315 for i in range(struct.unpack("<H", ifd_data[:2])[0]):
4316 ifd_tag, typ, count, data = struct.unpack(
4317 "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
4318 )
4319 try:
4320 (
4321 unit_size,
4322 handler,
4323 ) = ImageFileDirectory_v2._load_dispatch[typ]
4324 except KeyError:
4325 continue
4326 size = count * unit_size
4327 if size > 4:
4328 (offset,) = struct.unpack("<L", data)
4329 data = ifd_data[offset - 12 : offset + size - 12]
4330 else:
4331 data = data[:size]
4333 if len(data) != size:
4334 warnings.warn(
4335 "Possibly corrupt EXIF MakerNote data. "
4336 f"Expecting to read {size} bytes but only got "
4337 f"{len(data)}. Skipping tag {ifd_tag}"
4338 )
4339 continue
4341 if not data:
4342 continue
4344 makernote[ifd_tag] = handler(
4345 ImageFileDirectory_v2(), data, False
4346 )
4347 self._ifds[tag] = dict(self._fixup_dict(makernote))
4348 elif self.get(0x010F) == "Nintendo":
4349 makernote = {}
4350 for i in range(struct.unpack(">H", tag_data[:2])[0]):
4351 ifd_tag, typ, count, data = struct.unpack(
4352 ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2]
4353 )
4354 if ifd_tag == 0x1101:
4355 # CameraInfo
4356 (offset,) = struct.unpack(">L", data)
4357 self.fp.seek(offset)
4359 camerainfo: dict[str, int | bytes] = {
4360 "ModelID": self.fp.read(4)
4361 }
4363 self.fp.read(4)
4364 # Seconds since 2000
4365 camerainfo["TimeStamp"] = i32le(self.fp.read(12))
4367 self.fp.read(4)
4368 camerainfo["InternalSerialNumber"] = self.fp.read(4)
4370 self.fp.read(12)
4371 parallax = self.fp.read(4)
4372 handler = ImageFileDirectory_v2._load_dispatch[
4373 TiffTags.FLOAT
4374 ][1]
4375 camerainfo["Parallax"] = handler(
4376 ImageFileDirectory_v2(), parallax, False
4377 )[0]
4379 self.fp.read(4)
4380 camerainfo["Category"] = self.fp.read(2)
4382 makernote = {0x1101: camerainfo}
4383 self._ifds[tag] = makernote
4384 except struct.error:
4385 pass
4386 else:
4387 # Interop
4388 ifd = self._get_ifd_dict(tag_data, tag)
4389 if ifd is not None:
4390 self._ifds[tag] = ifd
4391 ifd = self._ifds.setdefault(tag, {})
4392 if tag == ExifTags.IFD.Exif and self._hidden_data:
4393 ifd = {
4394 k: v
4395 for (k, v) in ifd.items()
4396 if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote)
4397 }
4398 return ifd
4400 def hide_offsets(self) -> None:
4401 for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo):
4402 if tag in self:
4403 self._hidden_data[tag] = self[tag]
4404 del self[tag]
4406 def __str__(self) -> str:
4407 if self._info is not None:
4408 # Load all keys into self._data
4409 for tag in self._info:
4410 self[tag]
4412 return str(self._data)
4414 def __len__(self) -> int:
4415 keys = set(self._data)
4416 if self._info is not None:
4417 keys.update(self._info)
4418 return len(keys)
4420 def __getitem__(self, tag: int) -> Any:
4421 if self._info is not None and tag not in self._data and tag in self._info:
4422 self._data[tag] = self._fixup(self._info[tag])
4423 del self._info[tag]
4424 return self._data[tag]
4426 def __contains__(self, tag: object) -> bool:
4427 return tag in self._data or (self._info is not None and tag in self._info)
4429 def __setitem__(self, tag: int, value: Any) -> None:
4430 if self._info is not None and tag in self._info:
4431 del self._info[tag]
4432 self._data[tag] = value
4434 def __delitem__(self, tag: int) -> None:
4435 if self._info is not None and tag in self._info:
4436 del self._info[tag]
4437 else:
4438 del self._data[tag]
4439 if tag in self._ifds:
4440 del self._ifds[tag]
4442 def __iter__(self) -> Iterator[int]:
4443 keys = set(self._data)
4444 if self._info is not None:
4445 keys.update(self._info)
4446 return iter(keys)