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