mirror of
https://github.com/python-pillow/Pillow.git
synced 2026-01-28 11:05:49 +03:00
Lazy import only required plugin
This commit is contained in:
parent
e2b87a0420
commit
6b9de40533
126
src/PIL/Image.py
126
src/PIL/Image.py
|
|
@ -323,6 +323,99 @@ def getmodebands(mode: str) -> int:
|
|||
|
||||
_initialized = 0
|
||||
|
||||
# Mapping from file extension to plugin module name for lazy loading
|
||||
_EXTENSION_PLUGIN: dict[str, str] = {
|
||||
# Common formats (preinit)
|
||||
".bmp": "BmpImagePlugin",
|
||||
".dib": "BmpImagePlugin",
|
||||
".gif": "GifImagePlugin",
|
||||
".jfif": "JpegImagePlugin",
|
||||
".jpe": "JpegImagePlugin",
|
||||
".jpg": "JpegImagePlugin",
|
||||
".jpeg": "JpegImagePlugin",
|
||||
".pbm": "PpmImagePlugin",
|
||||
".pgm": "PpmImagePlugin",
|
||||
".pnm": "PpmImagePlugin",
|
||||
".ppm": "PpmImagePlugin",
|
||||
".pfm": "PpmImagePlugin",
|
||||
".png": "PngImagePlugin",
|
||||
".apng": "PngImagePlugin",
|
||||
# Less common formats (init)
|
||||
".avif": "AvifImagePlugin",
|
||||
".avifs": "AvifImagePlugin",
|
||||
".blp": "BlpImagePlugin",
|
||||
".bufr": "BufrStubImagePlugin",
|
||||
".cur": "CurImagePlugin",
|
||||
".dcx": "DcxImagePlugin",
|
||||
".dds": "DdsImagePlugin",
|
||||
".ps": "EpsImagePlugin",
|
||||
".eps": "EpsImagePlugin",
|
||||
".fit": "FitsImagePlugin",
|
||||
".fits": "FitsImagePlugin",
|
||||
".fli": "FliImagePlugin",
|
||||
".flc": "FliImagePlugin",
|
||||
".fpx": "FpxImagePlugin",
|
||||
".ftc": "FtexImagePlugin",
|
||||
".ftu": "FtexImagePlugin",
|
||||
".gbr": "GbrImagePlugin",
|
||||
".grib": "GribStubImagePlugin",
|
||||
".h5": "Hdf5StubImagePlugin",
|
||||
".hdf": "Hdf5StubImagePlugin",
|
||||
".icns": "IcnsImagePlugin",
|
||||
".ico": "IcoImagePlugin",
|
||||
".im": "ImImagePlugin",
|
||||
".iim": "IptcImagePlugin",
|
||||
".jp2": "Jpeg2KImagePlugin",
|
||||
".j2k": "Jpeg2KImagePlugin",
|
||||
".jpc": "Jpeg2KImagePlugin",
|
||||
".jpf": "Jpeg2KImagePlugin",
|
||||
".jpx": "Jpeg2KImagePlugin",
|
||||
".j2c": "Jpeg2KImagePlugin",
|
||||
".mic": "MicImagePlugin",
|
||||
".mpg": "MpegImagePlugin",
|
||||
".mpeg": "MpegImagePlugin",
|
||||
".mpo": "MpoImagePlugin",
|
||||
".msp": "MspImagePlugin",
|
||||
".palm": "PalmImagePlugin",
|
||||
".pcd": "PcdImagePlugin",
|
||||
".pcx": "PcxImagePlugin",
|
||||
".pdf": "PdfImagePlugin",
|
||||
".pxr": "PixarImagePlugin",
|
||||
".psd": "PsdImagePlugin",
|
||||
".qoi": "QoiImagePlugin",
|
||||
".bw": "SgiImagePlugin",
|
||||
".rgb": "SgiImagePlugin",
|
||||
".rgba": "SgiImagePlugin",
|
||||
".sgi": "SgiImagePlugin",
|
||||
".ras": "SunImagePlugin",
|
||||
".tga": "TgaImagePlugin",
|
||||
".icb": "TgaImagePlugin",
|
||||
".vda": "TgaImagePlugin",
|
||||
".vst": "TgaImagePlugin",
|
||||
".tif": "TiffImagePlugin",
|
||||
".tiff": "TiffImagePlugin",
|
||||
".webp": "WebPImagePlugin",
|
||||
".wmf": "WmfImagePlugin",
|
||||
".emf": "WmfImagePlugin",
|
||||
".xbm": "XbmImagePlugin",
|
||||
".xpm": "XpmImagePlugin",
|
||||
}
|
||||
|
||||
|
||||
def _load_plugin_for_extension(ext: str | bytes) -> bool:
|
||||
"""Load only the plugin needed for a specific file extension."""
|
||||
if isinstance(ext, bytes):
|
||||
ext = ext.decode()
|
||||
plugin = _EXTENSION_PLUGIN.get(ext.lower())
|
||||
if plugin is None:
|
||||
return False
|
||||
|
||||
try:
|
||||
__import__(f"PIL.{plugin}", globals(), locals(), [])
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
def preinit() -> None:
|
||||
"""
|
||||
|
|
@ -2535,11 +2628,13 @@ class Image:
|
|||
# only set the name for metadata purposes
|
||||
filename = os.fspath(fp.name)
|
||||
|
||||
preinit()
|
||||
|
||||
filename_ext = os.path.splitext(filename)[1].lower()
|
||||
ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext
|
||||
|
||||
# Try loading only the plugin for this extension first
|
||||
if not _load_plugin_for_extension(ext):
|
||||
preinit()
|
||||
|
||||
if not format:
|
||||
if ext not in EXTENSION:
|
||||
init()
|
||||
|
|
@ -3524,7 +3619,11 @@ def open(
|
|||
|
||||
prefix = fp.read(16)
|
||||
|
||||
preinit()
|
||||
# Try to load just the plugin needed for this file extension
|
||||
# before falling back to preinit() which loads common plugins
|
||||
ext = os.path.splitext(filename)[1] if filename else ""
|
||||
if not (ext and _load_plugin_for_extension(ext)):
|
||||
preinit()
|
||||
|
||||
warning_messages: list[str] = []
|
||||
|
||||
|
|
@ -3560,14 +3659,19 @@ def open(
|
|||
im = _open_core(fp, filename, prefix, formats)
|
||||
|
||||
if im is None and formats is ID:
|
||||
checked_formats = ID.copy()
|
||||
if init():
|
||||
im = _open_core(
|
||||
fp,
|
||||
filename,
|
||||
prefix,
|
||||
tuple(format for format in formats if format not in checked_formats),
|
||||
)
|
||||
# Try preinit (few common plugins) then init (all plugins)
|
||||
for loader in (preinit, init):
|
||||
checked_formats = ID.copy()
|
||||
loader()
|
||||
if formats != checked_formats:
|
||||
im = _open_core(
|
||||
fp,
|
||||
filename,
|
||||
prefix,
|
||||
tuple(f for f in formats if f not in checked_formats),
|
||||
)
|
||||
if im is not None:
|
||||
break
|
||||
|
||||
if im:
|
||||
im._exclusive_fp = exclusive_fp
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user