ehsanfal's picture
upgrade gradio
ab9739b
import gradio as gr
from PIL import Image
import numpy as np
import uuid
def editor_to_mask(value, invert=False):
"""
Convert an ImageEditor EditorValue to a white-on-black mask.
value: dict with keys: 'background', 'layers', 'composite' (Gradio 4/5 ImageEditor)
Strategy:
- Create an empty (black) mask the size of the background (or composite if background is None)
- For each layer, use its alpha channel as painted region; OR it to the mask
"""
if not value:
return None, None
bg = value.get("background")
layers = value.get("layers") or []
comp = value.get("composite")
# Determine canvas size
ref_img = bg or comp
if ref_img is None:
return None, None
if not isinstance(ref_img, Image.Image):
ref_img = Image.fromarray(ref_img)
w, h = ref_img.size
mask_acc = np.zeros((h, w), dtype=np.uint8)
for layer in layers:
if layer is None:
continue
if not isinstance(layer, Image.Image):
layer = Image.fromarray(layer)
# Ensure RGBA to get alpha; if no alpha, treat non-black as painted
if layer.mode != "RGBA":
layer = layer.convert("RGBA")
la = np.array(layer)[:, :, 3] # alpha
# Any non-zero alpha counts as painted
mask_acc = np.maximum(mask_acc, (la > 0).astype(np.uint8) * 255)
if invert:
mask_acc = 255 - mask_acc
out = Image.fromarray(mask_acc, mode="L")
fname = f"mask_{uuid.uuid4().hex}.png"
out.save(fname)
return out, fname
with gr.Blocks(css="footer {visibility:hidden}") as demo:
gr.Markdown("# 🖌️ Quick Mask Maker (Gradio 5)\nUpload an image, draw on the canvas (white brush), then export a white-on-black PNG mask.")
with gr.Row():
with gr.Column(scale=3):
brush_size = gr.Slider(5, 120, value=40, step=1, label="Brush radius")
editor = gr.ImageEditor(
label="Draw mask on its own layer (preselected).",
type="pil",
image_mode="RGBA",
height=520,
# Force a single "Mask" layer, disable adding extra layers
layers=gr.LayerOptions(allow_additional_layers=False, layers=["Mask"]),
# Force a white-only brush so painted area clearly becomes the mask
brush=gr.Brush(default_size=40, colors=["#FFFFFF"], default_color="#FFFFFF", color_mode="fixed"),
eraser=gr.Eraser(default_size=60),
)
invert = gr.Checkbox(False, label="Invert mask (white background)")
gen = gr.Button("Generate Mask", variant="primary")
with gr.Column(scale=2):
out_mask = gr.Image(label="Mask Preview (PNG)", type="pil", image_mode="L")
file_dl = gr.File(label="Download Mask")
# Wire brush size slider to editor
def _set_brush(r):
return gr.update(brush=gr.Brush(default_size=int(r), colors=["#FFFFFF"], default_color="#FFFFFF", color_mode="fixed"))
brush_size.change(_set_brush, inputs=brush_size, outputs=editor)
gen.click(fn=editor_to_mask, inputs=[editor, invert], outputs=[out_mask, file_dl])
if __name__ == "__main__":
demo.launch()