diff --git a/.changeset/major-zoos-write.md b/.changeset/major-zoos-write.md new file mode 100644 index 000000000000..7b40481c2ca9 --- /dev/null +++ b/.changeset/major-zoos-write.md @@ -0,0 +1,5 @@ +--- +"gradio": minor +--- + +feat:Fix PIL imports diff --git a/gradio/components/annotated_image.py b/gradio/components/annotated_image.py index ea01878ab610..5aea36c9eb85 100644 --- a/gradio/components/annotated_image.py +++ b/gradio/components/annotated_image.py @@ -15,8 +15,6 @@ set_documentation_group("component") -PIL.Image.init() # fixes https://github.com/gradio-app/gradio/issues/2843 - class Annotation(GradioModel): image: FileData diff --git a/gradio/components/base.py b/gradio/components/base.py index 223cb5e686aa..67247a40b2ee 100644 --- a/gradio/components/base.py +++ b/gradio/components/base.py @@ -15,7 +15,6 @@ from typing import TYPE_CHECKING, Any, Callable from gradio_client.documentation import set_documentation_group -from PIL import Image as _Image # using _ to minimize namespace pollution from gradio import utils from gradio.blocks import Block, BlockContext @@ -34,7 +33,6 @@ class DataframeData(TypedDict): set_documentation_group("component") -_Image.init() # fixes https://github.com/gradio-app/gradio/issues/2843 class _Keywords(Enum): diff --git a/gradio/components/gallery.py b/gradio/components/gallery.py index b61f5b54b96d..ab7858cd7d29 100644 --- a/gradio/components/gallery.py +++ b/gradio/components/gallery.py @@ -7,9 +7,9 @@ from urllib.parse import urlparse import numpy as np +import PIL.Image from gradio_client.documentation import document, set_documentation_group from gradio_client.utils import is_http_url_like -from PIL import Image as _Image # using _ to minimize namespace pollution from gradio import processing_utils, utils from gradio.components.base import Component @@ -19,7 +19,7 @@ set_documentation_group("component") -GalleryImageType = Union[np.ndarray, _Image.Image, Path, str] +GalleryImageType = Union[np.ndarray, PIL.Image.Image, Path, str] CaptionedGalleryImageType = Tuple[GalleryImageType, str] @@ -47,7 +47,7 @@ class Gallery(Component): def __init__( self, - value: list[np.ndarray | _Image.Image | str | Path | tuple] + value: list[np.ndarray | PIL.Image.Image | str | Path | tuple] | Callable | None = None, *, @@ -137,7 +137,7 @@ def preprocess( self, payload: GalleryData | None ) -> ( List[tuple[str, str | None]] - | List[tuple[_Image.Image, str | None]] + | List[tuple[PIL.Image.Image, str | None]] | List[tuple[np.ndarray, str | None]] | None ): @@ -179,7 +179,7 @@ def postprocess( img, cache_dir=self.GRADIO_CACHE ) file_path = str(utils.abspath(file)) - elif isinstance(img, _Image.Image): + elif isinstance(img, PIL.Image.Image): file = processing_utils.save_pil_to_cache( img, cache_dir=self.GRADIO_CACHE ) @@ -209,7 +209,7 @@ def convert_to_type(img: str, type: Literal["filepath", "numpy", "pil"]): if type == "filepath": return img else: - converted_image = _Image.open(img) + converted_image = PIL.Image.open(img) if type == "numpy": converted_image = np.array(converted_image) return converted_image diff --git a/gradio/components/image.py b/gradio/components/image.py index b56de66f3df8..4799f1632276 100644 --- a/gradio/components/image.py +++ b/gradio/components/image.py @@ -18,7 +18,6 @@ from gradio.events import Events set_documentation_group("component") -PIL.Image.init() # fixes https://github.com/gradio-app/gradio/issues/2843 @document() diff --git a/gradio/components/image_editor.py b/gradio/components/image_editor.py index 68c6f5c40164..a4e231e90323 100644 --- a/gradio/components/image_editor.py +++ b/gradio/components/image_editor.py @@ -8,8 +8,8 @@ from typing import Any, Iterable, List, Literal, Optional, TypedDict, Union, cast import numpy as np +import PIL.Image from gradio_client.documentation import document, set_documentation_group -from PIL import Image as _Image # using _ to minimize namespace pollution import gradio.image_utils as image_utils from gradio import utils @@ -18,10 +18,9 @@ from gradio.events import Events set_documentation_group("component") -_Image.init() # fixes https://github.com/gradio-app/gradio/issues/2843 -ImageType = Union[np.ndarray, _Image.Image, str] +ImageType = Union[np.ndarray, PIL.Image.Image, str] class EditorValue(TypedDict): @@ -218,11 +217,11 @@ def __init__( def convert_and_format_image( self, file: FileData | None, - ) -> np.ndarray | _Image.Image | str | None: + ) -> np.ndarray | PIL.Image.Image | str | None: if file is None: return None - im = _Image.open(file.path) + im = PIL.Image.open(file.path) if file.orig_name: p = Path(file.orig_name) @@ -282,7 +281,7 @@ def postprocess(self, value: EditorValue | ImageType | None) -> EditorData | Non return None elif isinstance(value, dict): pass - elif isinstance(value, (np.ndarray, _Image.Image, str)): + elif isinstance(value, (np.ndarray, PIL.Image.Image, str)): value = {"background": value, "layers": [], "composite": value} else: raise ValueError( @@ -293,7 +292,7 @@ def postprocess(self, value: EditorValue | ImageType | None) -> EditorData | Non [ FileData( path=image_utils.save_image( - cast(Union[np.ndarray, _Image.Image, str], layer), + cast(Union[np.ndarray, PIL.Image.Image, str], layer), self.GRADIO_CACHE, ) ) @@ -312,7 +311,7 @@ def postprocess(self, value: EditorValue | ImageType | None) -> EditorData | Non layers=layers, composite=FileData( path=image_utils.save_image( - cast(Union[np.ndarray, _Image.Image, str], value["composite"]), + cast(Union[np.ndarray, PIL.Image.Image, str], value["composite"]), self.GRADIO_CACHE, ) ) diff --git a/gradio/image_utils.py b/gradio/image_utils.py index 045f8212bcf2..06c169a9dd54 100644 --- a/gradio/image_utils.py +++ b/gradio/image_utils.py @@ -4,20 +4,20 @@ from typing import Literal import numpy as np -from PIL import Image as _Image # using _ to minimize namespace pollution +import PIL.Image from gradio import processing_utils -_Image.init() +PIL.Image.init() # fixes https://github.com/gradio-app/gradio/issues/2843 (remove when requiring Pillow 9.4+) def format_image( - im: _Image.Image | None, + im: PIL.Image.Image | None, type: Literal["numpy", "pil", "filepath"], cache_dir: str, name: str = "image", format: str = "png", -) -> np.ndarray | _Image.Image | str | None: +) -> np.ndarray | PIL.Image.Image | str | None: """Helper method to format an image based on self.type""" if im is None: return im @@ -51,12 +51,12 @@ def format_image( ) -def save_image(y: np.ndarray | _Image.Image | str | Path, cache_dir: str): +def save_image(y: np.ndarray | PIL.Image.Image | str | Path, cache_dir: str): # numpy gets saved to png as default format # PIL gets saved to its original format if possible if isinstance(y, np.ndarray): path = processing_utils.save_img_array_to_cache(y, cache_dir=cache_dir) - elif isinstance(y, _Image.Image): + elif isinstance(y, PIL.Image.Image): fmt = y.format try: path = processing_utils.save_pil_to_cache( @@ -81,7 +81,7 @@ def save_image(y: np.ndarray | _Image.Image | str | Path, cache_dir: str): return path -def crop_scale(img: _Image.Image, final_width: int, final_height: int): +def crop_scale(img: PIL.Image.Image, final_width: int, final_height: int): original_width, original_height = img.size target_aspect_ratio = final_width / final_height diff --git a/gradio/templates.py b/gradio/templates.py index 94d62358f6a4..0c5f5a1a30c9 100644 --- a/gradio/templates.py +++ b/gradio/templates.py @@ -4,7 +4,7 @@ from typing import Any, Callable, Iterable, Literal import numpy as np -from PIL import Image as _Image # using _ to minimize namespace pollution +import PIL.Image from gradio import components from gradio.components.audio import WaveformOptions @@ -79,7 +79,7 @@ class Sketchpad(components.ImageEditor): def __init__( self, - value: str | _Image.Image | np.ndarray | None = None, + value: str | PIL.Image.Image | np.ndarray | None = None, *, height: int | str | None = None, width: int | str | None = None, @@ -148,7 +148,7 @@ class Paint(components.ImageEditor): def __init__( self, - value: str | _Image.Image | np.ndarray | None = None, + value: str | PIL.Image.Image | np.ndarray | None = None, *, height: int | str | None = None, width: int | str | None = None, @@ -215,7 +215,7 @@ class ImageMask(components.ImageEditor): def __init__( self, - value: str | _Image.Image | np.ndarray | None = None, + value: str | PIL.Image.Image | np.ndarray | None = None, *, height: int | None = None, width: int | str | None = None,