import modules.scripts as scripts
import gradio as gr
import os
import cv2
import numpy as np
from PIL import Image

from modules import images
from modules.processing import process_images, Processed
from modules.processing import Processed
from modules.shared import opts, cmd_opts, state
from scipy.ndimage import binary_erosion


class Script(scripts.Script):  

# The title of the script. This is what will be displayed in the dropdown menu.
    def title(self):
        return "MaskPadding"


# Determines when the script should be shown in the dropdown menu via the 
# returned value. As an example:
# is_img2img is True if the current tab is img2img, and False if it is txt2img.
# Thus, return is_img2img to only show the script on the img2img tab.

    def show(self, is_img2img):
        return scripts.AlwaysVisible

# How the script's is displayed in the UI. See https://gradio.app/docs/#components
# for the different UI components you can use and how to create them.
# Most UI components can return a value, such as a boolean for a checkbox.
# The returned values are passed to the run method as parameters.

    def ui(self, is_img2img):
        maskPadding = gr.Number(0 , label="Mask Padding")
        return [maskPadding]

    def before_process(self, p, *args):
        pass

    def process(self, p, *args):
        """
        Author: jack
        This function is called before processing begins for AlwaysVisible scripts.
        You can modify the processing object (p) here, inject hooks, etc.
        args contains all values returned by components from ui()
        """
        maskPadding = args[0]

        # 缩进mask
        if maskPadding > 0 and p.image_mask is not None:
            image_mask = np.array(p.image_mask)
            mask = image_mask[:, :]/255 if len(image_mask.shape) == 2 else image_mask[:, :, 0]/255
            pil_mask, np_mask = self.erode_mask(mask, maskPadding)
            p.image_mask = Image.fromarray(np_mask.astype(np.uint8)) #.convert("RGB")
            print(f'process mask padding[{maskPadding}] success\n')

  
    #Author: jack
    def erode_mask(self , mask, dilation_amt):
        x, y = np.meshgrid(np.arange(dilation_amt), np.arange(dilation_amt))
        center = dilation_amt // 2
        dilation_kernel = ((x - center)**2 + (y - center)**2 <= center**2).astype(np.uint8)
        dilated_binary_img = binary_erosion(mask, dilation_kernel)
        dilated_mask = Image.fromarray(dilated_binary_img.astype(np.uint8) * 255)
        return dilated_mask, dilated_binary_img.astype(np.uint8)*255


    def postprocess(self, p, processed, *args):
        pass

# This is where the additional processing is implemented. The parameters include
# self, the model object "p" (a StableDiffusionProcessing class, see
# processing.py), and the parameters returned by the ui method.
# Custom functions can be defined here, and additional libraries can be imported 
# to be used in processing. The return value should be a Processed object, which is
# what is returned by the process_images method.

    # def run(self, p, angle, hflip, vflip, overwrite):
    #     pass