|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import json |
|
import os.path |
|
import tempfile |
|
from pathlib import Path |
|
from typing import Union, Tuple, Optional |
|
|
|
import numpy as np |
|
from PIL import Image |
|
from gradio import processing_utils |
|
from gradio import utils |
|
from gradio.data_classes import FileData, GradioRootModel, JsonData |
|
from gradio_client import utils as client_utils |
|
from gradio_imageslider import ImageSlider |
|
from gradio_imageslider.imageslider import image_tuple, image_variants |
|
|
|
|
|
class ImageSliderPlusData(GradioRootModel): |
|
root: Union[ |
|
Tuple[FileData | None, FileData | None, JsonData | None], |
|
Tuple[FileData | None, FileData | None], |
|
None, |
|
] |
|
|
|
|
|
class ImageSliderPlus(ImageSlider): |
|
data_model = ImageSliderPlusData |
|
|
|
def as_example(self, value): |
|
return self.process_example_dims(value, 256, True) |
|
|
|
def _format_image(self, im: Image): |
|
if self.type != "filepath": |
|
raise ValueError("ImageSliderPlus can be only created with type='filepath'") |
|
if im is None: |
|
return im |
|
format = "png" |
|
path = processing_utils.save_pil_to_cache( |
|
im, cache_dir=self.GRADIO_CACHE, format=format |
|
) |
|
self.temp_files.add(path) |
|
return path |
|
|
|
def _postprocess_image(self, y: image_variants): |
|
if isinstance(y, np.ndarray): |
|
format = "png" |
|
path = processing_utils.save_img_array_to_cache( |
|
y, cache_dir=self.GRADIO_CACHE, format=format |
|
) |
|
elif isinstance(y, Image.Image): |
|
format = "png" |
|
path = processing_utils.save_pil_to_cache( |
|
y, cache_dir=self.GRADIO_CACHE, format=format |
|
) |
|
elif isinstance(y, (str, Path)): |
|
path = y if isinstance(y, str) else str(utils.abspath(y)) |
|
else: |
|
raise ValueError("Cannot process this value as an Image") |
|
|
|
return path |
|
|
|
def postprocess( |
|
self, |
|
y: image_tuple, |
|
) -> ImageSliderPlusData: |
|
if y is None: |
|
return ImageSliderPlusData(root=(None, None, None)) |
|
|
|
settings = None |
|
if type(y[0]) is str: |
|
settings_candidate_path = y[0] + ".settings.json" |
|
if os.path.isfile(settings_candidate_path): |
|
with open(settings_candidate_path, "r") as fp: |
|
settings = json.load(fp) |
|
|
|
return ImageSliderPlusData( |
|
root=( |
|
FileData(path=self._postprocess_image(y[0])), |
|
FileData(path=self._postprocess_image(y[1])), |
|
JsonData(settings), |
|
), |
|
) |
|
|
|
def preprocess(self, x: ImageSliderPlusData) -> image_tuple: |
|
if x is None: |
|
return x |
|
|
|
out_0 = self._preprocess_image(x.root[0]) |
|
out_1 = self._preprocess_image(x.root[1]) |
|
|
|
if len(x.root) > 2 and x.root[2] is not None: |
|
with open(out_0 + ".settings.json", "w") as fp: |
|
json.dump(x.root[2].root, fp) |
|
|
|
return out_0, out_1 |
|
|
|
@staticmethod |
|
def resize_and_save(image_path: str, max_dim: int, square: bool = False) -> str: |
|
img = Image.open(image_path).convert("RGB") |
|
if square: |
|
width, height = img.size |
|
min_side = min(width, height) |
|
left = (width - min_side) // 2 |
|
top = (height - min_side) // 2 |
|
right = left + min_side |
|
bottom = top + min_side |
|
img = img.crop((left, top, right, bottom)) |
|
img.thumbnail((max_dim, max_dim)) |
|
temp_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False) |
|
img.save(temp_file.name, "PNG") |
|
return temp_file.name |
|
|
|
def process_example_dims( |
|
self, input_data: tuple[str | Path | None] | None, max_dim: Optional[int] = None, square: bool = False |
|
) -> image_tuple: |
|
if input_data is None: |
|
return None |
|
input_data = (str(input_data[0]), str(input_data[1])) |
|
if self.proxy_url or client_utils.is_http_url_like(input_data[0]): |
|
return input_data[0] |
|
if max_dim is not None: |
|
input_data = ( |
|
self.resize_and_save(input_data[0], max_dim, square), |
|
self.resize_and_save(input_data[1], max_dim, square), |
|
) |
|
return ( |
|
self.move_resource_to_block_cache(input_data[0]), |
|
self.move_resource_to_block_cache(input_data[1]), |
|
) |
|
|
|
def process_example( |
|
self, input_data: tuple[str | Path | None] | None |
|
) -> image_tuple: |
|
return self.process_example_dims(input_data) |
|
|