ehsanfal commited on
Commit
ab9739b
·
1 Parent(s): 69fe06d

upgrade gradio

Browse files
Files changed (4) hide show
  1. README.md +1 -1
  2. app.py +54 -20
  3. requirements.txt +17 -32
  4. runtime.txt +1 -1
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 📈
4
  colorFrom: pink
5
  colorTo: pink
6
  sdk: gradio
7
- sdk_version: 3.50.2
8
  app_file: app.py
9
  pinned: true
10
  short_description: tool for making inpainting masks
 
4
  colorFrom: pink
5
  colorTo: pink
6
  sdk: gradio
7
+ sdk_version: 5.49.1
8
  app_file: app.py
9
  pinned: true
10
  short_description: tool for making inpainting masks
app.py CHANGED
@@ -3,49 +3,83 @@ from PIL import Image
3
  import numpy as np
4
  import uuid
5
 
6
- def make_mask(data, invert=False):
7
- # data is a dict with keys "image" and "mask" when tool="sketch"
8
- if not data or data.get("mask") is None:
 
 
 
 
 
 
9
  return None, None
10
 
11
- mask_img = data["mask"].convert("L")
12
- arr = np.array(mask_img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- # binarize
15
- bin_mask = (arr > 0).astype(np.uint8) * 255
16
  if invert:
17
- bin_mask = 255 - bin_mask
18
 
19
- out = Image.fromarray(bin_mask, mode="L")
20
  fname = f"mask_{uuid.uuid4().hex}.png"
21
  out.save(fname)
22
  return out, fname
23
 
24
  with gr.Blocks(css="footer {visibility:hidden}") as demo:
25
- gr.Markdown("# 🖌️ Quick Mask Maker\nUpload an image, paint the mask, then export a white-on-black PNG.")
26
 
27
  with gr.Row():
28
  with gr.Column(scale=3):
29
- brush = gr.Slider(5, 120, value=40, step=1, label="Brush radius")
30
- img = gr.Image(
31
- label="Upload image, click the brush icon, paint. Use eraser to undo.",
32
- tool="sketch", # supported in Gradio 3.50.2
33
  type="pil",
34
- image_mode="RGB",
35
  height=520,
 
 
 
 
 
36
  )
37
- invert = gr.Checkbox(False, label="Invert mask (make background white)")
 
38
  gen = gr.Button("Generate Mask", variant="primary")
 
39
  with gr.Column(scale=2):
40
  out_mask = gr.Image(label="Mask Preview (PNG)", type="pil", image_mode="L")
41
  file_dl = gr.File(label="Download Mask")
42
 
43
- # Update brush radius on the fly
44
  def _set_brush(r):
45
- return gr.update(brush_radius=int(r))
46
- brush.change(_set_brush, inputs=brush, outputs=img)
47
 
48
- gen.click(fn=make_mask, inputs=[img, invert], outputs=[out_mask, file_dl])
49
 
50
  if __name__ == "__main__":
51
  demo.launch()
 
3
  import numpy as np
4
  import uuid
5
 
6
+ def editor_to_mask(value, invert=False):
7
+ """
8
+ Convert an ImageEditor EditorValue to a white-on-black mask.
9
+ value: dict with keys: 'background', 'layers', 'composite' (Gradio 4/5 ImageEditor)
10
+ Strategy:
11
+ - Create an empty (black) mask the size of the background (or composite if background is None)
12
+ - For each layer, use its alpha channel as painted region; OR it to the mask
13
+ """
14
+ if not value:
15
  return None, None
16
 
17
+ bg = value.get("background")
18
+ layers = value.get("layers") or []
19
+ comp = value.get("composite")
20
+
21
+ # Determine canvas size
22
+ ref_img = bg or comp
23
+ if ref_img is None:
24
+ return None, None
25
+ if not isinstance(ref_img, Image.Image):
26
+ ref_img = Image.fromarray(ref_img)
27
+
28
+ w, h = ref_img.size
29
+ mask_acc = np.zeros((h, w), dtype=np.uint8)
30
+
31
+ for layer in layers:
32
+ if layer is None:
33
+ continue
34
+ if not isinstance(layer, Image.Image):
35
+ layer = Image.fromarray(layer)
36
+ # Ensure RGBA to get alpha; if no alpha, treat non-black as painted
37
+ if layer.mode != "RGBA":
38
+ layer = layer.convert("RGBA")
39
+ la = np.array(layer)[:, :, 3] # alpha
40
+ # Any non-zero alpha counts as painted
41
+ mask_acc = np.maximum(mask_acc, (la > 0).astype(np.uint8) * 255)
42
 
 
 
43
  if invert:
44
+ mask_acc = 255 - mask_acc
45
 
46
+ out = Image.fromarray(mask_acc, mode="L")
47
  fname = f"mask_{uuid.uuid4().hex}.png"
48
  out.save(fname)
49
  return out, fname
50
 
51
  with gr.Blocks(css="footer {visibility:hidden}") as demo:
52
+ gr.Markdown("# 🖌️ Quick Mask Maker (Gradio 5)\nUpload an image, draw on the canvas (white brush), then export a white-on-black PNG mask.")
53
 
54
  with gr.Row():
55
  with gr.Column(scale=3):
56
+ brush_size = gr.Slider(5, 120, value=40, step=1, label="Brush radius")
57
+
58
+ editor = gr.ImageEditor(
59
+ label="Draw mask on its own layer (preselected).",
60
  type="pil",
61
+ image_mode="RGBA",
62
  height=520,
63
+ # Force a single "Mask" layer, disable adding extra layers
64
+ layers=gr.LayerOptions(allow_additional_layers=False, layers=["Mask"]),
65
+ # Force a white-only brush so painted area clearly becomes the mask
66
+ brush=gr.Brush(default_size=40, colors=["#FFFFFF"], default_color="#FFFFFF", color_mode="fixed"),
67
+ eraser=gr.Eraser(default_size=60),
68
  )
69
+
70
+ invert = gr.Checkbox(False, label="Invert mask (white background)")
71
  gen = gr.Button("Generate Mask", variant="primary")
72
+
73
  with gr.Column(scale=2):
74
  out_mask = gr.Image(label="Mask Preview (PNG)", type="pil", image_mode="L")
75
  file_dl = gr.File(label="Download Mask")
76
 
77
+ # Wire brush size slider to editor
78
  def _set_brush(r):
79
+ return gr.update(brush=gr.Brush(default_size=int(r), colors=["#FFFFFF"], default_color="#FFFFFF", color_mode="fixed"))
80
+ brush_size.change(_set_brush, inputs=brush_size, outputs=editor)
81
 
82
+ gen.click(fn=editor_to_mask, inputs=[editor, invert], outputs=[out_mask, file_dl])
83
 
84
  if __name__ == "__main__":
85
  demo.launch()
requirements.txt CHANGED
@@ -1,70 +1,55 @@
1
- aiofiles==23.2.1
2
- altair==5.5.0
3
  annotated-doc==0.0.3
4
  annotated-types==0.7.0
5
  anyio==4.11.0
6
- attrs==25.4.0
7
  certifi==2025.10.5
8
- charset-normalizer==3.4.4
9
- click==8.1.8
10
- contourpy==1.3.0
11
- cycler==0.12.1
12
  exceptiongroup==1.3.0
13
  fastapi==0.120.4
14
  ffmpy==0.6.4
15
- filelock==3.19.1
16
- fonttools==4.60.1
17
  fsspec==2025.10.0
18
- gradio==3.50.2
19
- gradio-client==0.6.1
 
20
  h11==0.16.0
21
  hf-xet==1.2.0
22
  httpcore==1.0.9
23
  httpx==0.28.1
24
- huggingface-hub==0.24.7
25
  idna==3.11
26
- importlib-resources==6.5.2
27
  jinja2==3.1.6
28
- jsonschema==4.25.1
29
- jsonschema-specifications==2025.9.1
30
- kiwisolver==1.4.7
31
- markdown-it-py==3.0.0
32
- markupsafe==2.1.5
33
- matplotlib==3.9.4
34
  mdurl==0.1.2
35
- narwhals==2.10.1
36
- numpy==1.26.4
37
  orjson==3.11.4
38
  packaging==25.0
39
  pandas==2.3.3
40
- pillow==10.4.0
41
- pydantic==2.12.3
42
- pydantic-core==2.41.4
43
  pydub==0.25.1
44
  pygments==2.19.2
45
- pyparsing==3.2.5
46
  python-dateutil==2.9.0.post0
47
  python-multipart==0.0.20
48
  pytz==2025.2
49
  pyyaml==6.0.3
50
- referencing==0.36.2
51
- requests==2.32.5
52
  rich==14.2.0
53
- rpds-py==0.27.1
54
  ruff==0.14.3
 
55
  semantic-version==2.10.0
56
  shellingham==1.5.4
57
  six==1.17.0
58
  sniffio==1.3.1
59
  starlette==0.49.1
60
- tomlkit==0.12.0
61
  tqdm==4.67.1
62
  typer==0.20.0
63
  typer-slim==0.20.0
64
  typing-extensions==4.15.0
65
  typing-inspection==0.4.2
66
  tzdata==2025.2
67
- urllib3==2.5.0
68
  uvicorn==0.38.0
69
- websockets==11.0.3
70
- zipp==3.23.0
 
1
+ aiofiles==24.1.0
 
2
  annotated-doc==0.0.3
3
  annotated-types==0.7.0
4
  anyio==4.11.0
5
+ brotli==1.1.0
6
  certifi==2025.10.5
7
+ click==8.3.0
 
 
 
8
  exceptiongroup==1.3.0
9
  fastapi==0.120.4
10
  ffmpy==0.6.4
11
+ filelock==3.20.0
 
12
  fsspec==2025.10.0
13
+ gradio==5.49.1
14
+ gradio-client==1.13.3
15
+ groovy==0.1.2
16
  h11==0.16.0
17
  hf-xet==1.2.0
18
  httpcore==1.0.9
19
  httpx==0.28.1
20
+ huggingface-hub==1.0.1
21
  idna==3.11
 
22
  jinja2==3.1.6
23
+ markdown-it-py==4.0.0
24
+ markupsafe==3.0.3
 
 
 
 
25
  mdurl==0.1.2
26
+ numpy==2.2.6
 
27
  orjson==3.11.4
28
  packaging==25.0
29
  pandas==2.3.3
30
+ pillow==11.3.0
31
+ pydantic==2.11.10
32
+ pydantic-core==2.33.2
33
  pydub==0.25.1
34
  pygments==2.19.2
 
35
  python-dateutil==2.9.0.post0
36
  python-multipart==0.0.20
37
  pytz==2025.2
38
  pyyaml==6.0.3
 
 
39
  rich==14.2.0
 
40
  ruff==0.14.3
41
+ safehttpx==0.1.7
42
  semantic-version==2.10.0
43
  shellingham==1.5.4
44
  six==1.17.0
45
  sniffio==1.3.1
46
  starlette==0.49.1
47
+ tomlkit==0.13.3
48
  tqdm==4.67.1
49
  typer==0.20.0
50
  typer-slim==0.20.0
51
  typing-extensions==4.15.0
52
  typing-inspection==0.4.2
53
  tzdata==2025.2
 
54
  uvicorn==0.38.0
55
+ websockets==15.0.1
 
runtime.txt CHANGED
@@ -1 +1 @@
1
- python-3.9
 
1
+ python-3.10