@@ -3598,11 +3598,15 @@ def open(
35983598 and be opened in binary mode. The file object will also seek to zero
35993599 before reading.
36003600 :param mode: The mode. If given, this argument must be "r".
3601- :param formats: A list or tuple of formats to attempt to load the file in.
3602- This can be used to restrict the set of formats checked.
3603- Pass ``None`` to try all supported formats. You can print the set of
3604- available formats by running ``python3 -m PIL`` or using
3605- the :py:func:`PIL.features.pilinfo` function.
3601+ :param formats: A list or tuple of formats to attempt to load the file in, e.g.
3602+ ("JPEG", "GIF"). This can be used to restrict the set of formats checked.
3603+
3604+ To exclude a format, start the format with "!", e.g. ("!EPS", "!PSD").
3605+
3606+ Pass ``None`` to try all supported formats.
3607+
3608+ You can print the set of available formats by running ``python3 -m PIL`` or
3609+ using the :py:func:`PIL.features.pilinfo` function.
36063610 :returns: An :py:class:`~PIL.Image.Image` object.
36073611 :exception FileNotFoundError: If the file cannot be found.
36083612 :exception PIL.UnidentifiedImageError: If the image cannot be opened and
@@ -3622,11 +3626,12 @@ def open(
36223626 )
36233627 raise ValueError (msg )
36243628
3625- if formats is None :
3626- formats = ID
3627- elif not isinstance (formats , (list , tuple )):
3628- msg = "formats must be a list or tuple" # type: ignore[unreachable]
3629- raise TypeError (msg )
3629+ if formats is not None :
3630+ if not isinstance (formats , (list , tuple )):
3631+ msg = "formats must be a list or tuple" # type: ignore[unreachable]
3632+ raise TypeError (msg )
3633+ formats = tuple (format .upper () for format in formats )
3634+ exclude = all (format .startswith ("!" ) for format in formats )
36303635
36313636 exclusive_fp = False
36323637 filename : str | bytes = ""
@@ -3657,12 +3662,15 @@ def _open_core(
36573662 fp : IO [bytes ],
36583663 filename : str | bytes ,
36593664 prefix : bytes ,
3660- formats : list [str ] | tuple [ str , ... ],
3665+ check_formats : list [str ],
36613666 ) -> ImageFile .ImageFile | None :
3662- for i in formats :
3663- i = i .upper ()
3664- if i not in OPEN :
3665- init ()
3667+ for i in check_formats :
3668+ if formats is not None :
3669+ if exclude :
3670+ if "!" + i in formats :
3671+ continue
3672+ elif i not in formats or "!" + i in formats :
3673+ continue
36663674 try :
36673675 factory , accept = OPEN [i ]
36683676 result = not accept or accept (prefix )
@@ -3682,21 +3690,13 @@ def _open_core(
36823690 raise
36833691 return None
36843692
3685- im = _open_core (fp , filename , prefix , formats )
3686-
3687- if im is None and formats is ID :
3693+ if im := _open_core (fp , filename , prefix , ID ):
36883694 # Try preinit (few common plugins) then init (all plugins)
36893695 for loader in (preinit , init ):
36903696 checked_formats = ID .copy ()
36913697 loader ()
3692- if formats != checked_formats :
3693- im = _open_core (
3694- fp ,
3695- filename ,
3696- prefix ,
3697- tuple (f for f in formats if f not in checked_formats ),
3698- )
3699- if im is not None :
3698+ if check_formats := [f for f in ID if f not in checked_formats ]:
3699+ if im := _open_core (fp , filename , prefix , check_formats ):
37003700 break
37013701
37023702 if im :
0 commit comments