prithivMLmods commited on
Commit
ce44242
·
verified ·
1 Parent(s): 327921b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -70
app.py CHANGED
@@ -3,7 +3,7 @@ import spaces
3
  import torch
4
  from diffusers import AutoencoderKL, TCDScheduler
5
  from diffusers.models.model_loading_utils import load_state_dict
6
- from gradio_imageslider import ImageSlider
7
  from huggingface_hub import hf_hub_download
8
 
9
  from controlnet_union import ControlNetModel_Union
@@ -12,6 +12,7 @@ from pipeline_fill_sd_xl import StableDiffusionXLFillPipeline
12
  from PIL import Image, ImageDraw
13
  import numpy as np
14
 
 
15
  config_file = hf_hub_download(
16
  "xinsir/controlnet-union-sdxl-1.0",
17
  filename="config_promax.json",
@@ -45,6 +46,8 @@ pipe = StableDiffusionXLFillPipeline.from_pretrained(
45
 
46
  pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
47
 
 
 
48
  def can_expand(source_width, source_height, target_width, target_height, alignment):
49
  """Checks if the image can be expanded based on the alignment."""
50
  if alignment in ("Left", "Right") and source_width >= target_width:
@@ -60,7 +63,7 @@ def prepare_image_and_mask(image, width, height, overlap_percentage, resize_opti
60
  scale_factor = min(target_size[0] / image.width, target_size[1] / image.height)
61
  new_width = int(image.width * scale_factor)
62
  new_height = int(image.height * scale_factor)
63
-
64
  # Resize the source image to fit within target size
65
  source = image.resize((new_width, new_height), Image.LANCZOS)
66
 
@@ -132,7 +135,7 @@ def prepare_image_and_mask(image, width, height, overlap_percentage, resize_opti
132
  right_overlap = margin_x + new_width - overlap_x if overlap_right else margin_x + new_width - white_gaps_patch
133
  top_overlap = margin_y + overlap_y if overlap_top else margin_y + white_gaps_patch
134
  bottom_overlap = margin_y + new_height - overlap_y if overlap_bottom else margin_y + new_height - white_gaps_patch
135
-
136
  if alignment == "Left":
137
  left_overlap = margin_x + overlap_x if overlap_left else margin_x
138
  elif alignment == "Right":
@@ -153,31 +156,40 @@ def prepare_image_and_mask(image, width, height, overlap_percentage, resize_opti
153
 
154
  def preview_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
155
  background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
156
-
157
  # Create a preview image showing the mask
158
  preview = background.copy().convert('RGBA')
159
-
160
  # Create a semi-transparent red overlay
161
  red_overlay = Image.new('RGBA', background.size, (255, 0, 0, 64)) # Reduced alpha to 64 (25% opacity)
162
-
163
  # Convert black pixels in the mask to semi-transparent red
164
  red_mask = Image.new('RGBA', background.size, (0, 0, 0, 0))
165
  red_mask.paste(red_overlay, (0, 0), mask)
166
-
167
  # Overlay the red mask on the background
168
  preview = Image.alpha_composite(preview, red_mask)
169
-
170
  return preview
171
 
172
  @spaces.GPU(duration=24)
173
  def infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
174
  background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
175
-
176
  if not can_expand(background.width, background.height, width, height, alignment):
177
- alignment = "Middle"
178
 
179
  cnet_image = background.copy()
180
- cnet_image.paste(0, (0, 0), mask)
 
 
 
 
 
 
 
 
 
181
 
182
  final_prompt = f"{prompt_input} , high quality, 4k"
183
 
@@ -188,23 +200,41 @@ def infer(image, width, height, overlap_percentage, num_inference_steps, resize_
188
  negative_pooled_prompt_embeds,
189
  ) = pipe.encode_prompt(final_prompt, "cuda", True)
190
 
191
- for image in pipe(
 
 
 
 
192
  prompt_embeds=prompt_embeds,
193
  negative_prompt_embeds=negative_prompt_embeds,
194
  pooled_prompt_embeds=pooled_prompt_embeds,
195
  negative_pooled_prompt_embeds=negative_pooled_prompt_embeds,
196
- image=cnet_image,
 
197
  num_inference_steps=num_inference_steps
198
  ):
199
- yield cnet_image, image
200
 
201
- image = image.convert("RGBA")
202
- cnet_image.paste(image, (0, 0), mask)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
- yield background, cnet_image
205
 
206
  def clear_result():
207
- """Clears the result ImageSlider."""
208
  return gr.update(value=None)
209
 
210
  def preload_presets(target_ratio, ui_width, ui_height):
@@ -222,6 +252,7 @@ def preload_presets(target_ratio, ui_width, ui_height):
222
  changed_height = 1024
223
  return changed_width, changed_height, gr.update()
224
  elif target_ratio == "Custom":
 
225
  return ui_width, ui_height, gr.update(open=True)
226
 
227
  def select_the_right_preset(user_width, user_height):
@@ -241,9 +272,16 @@ def update_history(new_image, history):
241
  """Updates the history gallery with the new image."""
242
  if history is None:
243
  history = []
244
- history.insert(0, new_image)
 
 
 
 
 
245
  return history
246
 
 
 
247
  css = """
248
  .gradio-container {
249
  width: 1200px !important;
@@ -279,7 +317,7 @@ with gr.Blocks(css=css) as demo:
279
  value="9:16",
280
  scale=2
281
  )
282
-
283
  alignment_dropdown = gr.Dropdown(
284
  choices=["Middle", "Left", "Right", "Top", "Bottom"],
285
  value="Middle",
@@ -294,16 +332,16 @@ with gr.Blocks(css=css) as demo:
294
  minimum=720,
295
  maximum=1536,
296
  step=8,
297
- value=720, # Set a default value
298
  )
299
  height_slider = gr.Slider(
300
  label="Target Height",
301
  minimum=720,
302
  maximum=1536,
303
  step=8,
304
- value=1280, # Set a default value
305
  )
306
-
307
  num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
308
  with gr.Group():
309
  overlap_percentage = gr.Slider(
@@ -316,7 +354,7 @@ with gr.Blocks(css=css) as demo:
316
  with gr.Row():
317
  overlap_top = gr.Checkbox(label="Overlap Top", value=True)
318
  overlap_right = gr.Checkbox(label="Overlap Right", value=True)
319
- with gr.Row():
320
  overlap_left = gr.Checkbox(label="Overlap Left", value=True)
321
  overlap_bottom = gr.Checkbox(label="Overlap Bottom", value=True)
322
  with gr.Row():
@@ -333,11 +371,11 @@ with gr.Blocks(css=css) as demo:
333
  value=50,
334
  visible=False
335
  )
336
-
337
- with gr.Column():
338
  preview_button = gr.Button("Preview alignment and mask")
339
-
340
-
341
  gr.Examples(
342
  examples=[
343
  ["./examples/example_1.webp", 1280, 720, "Middle"],
@@ -346,29 +384,33 @@ with gr.Blocks(css=css) as demo:
346
  ["./examples/example_3.jpg", 1024, 1024, "Bottom"],
347
  ],
348
  inputs=[input_image, width_slider, height_slider, alignment_dropdown],
 
 
 
349
  )
350
 
351
-
352
 
353
  with gr.Column():
354
- result = ImageSlider(label="Generated Image", interactive=False, type="pil", slider_color="pink")
 
355
  use_as_input_button = gr.Button("Use as Input Image", visible=False)
356
 
357
- history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", interactive=False)
358
- preview_image = gr.Image(label="Preview")
359
 
360
-
361
 
362
  def use_output_as_input(output_image):
363
  """Sets the generated output as the new input image."""
364
- return gr.update(value=output_image[1])
 
365
 
366
  use_as_input_button.click(
367
  fn=use_output_as_input,
368
- inputs=[result],
369
  outputs=[input_image]
370
  )
371
-
372
  target_ratio.change(
373
  fn=preload_presets,
374
  inputs=[target_ratio, width_slider, height_slider],
@@ -376,73 +418,90 @@ with gr.Blocks(css=css) as demo:
376
  queue=False
377
  )
378
 
 
379
  width_slider.change(
380
  fn=select_the_right_preset,
381
  inputs=[width_slider, height_slider],
382
  outputs=[target_ratio],
383
  queue=False
 
 
 
 
 
384
  )
385
 
 
386
  height_slider.change(
387
  fn=select_the_right_preset,
388
  inputs=[width_slider, height_slider],
389
  outputs=[target_ratio],
390
  queue=False
 
 
 
 
 
391
  )
392
 
 
393
  resize_option.change(
394
  fn=toggle_custom_resize_slider,
395
  inputs=[resize_option],
396
  outputs=[custom_resize_percentage],
397
  queue=False
398
  )
399
-
400
- run_button.click( # Clear the result
401
- fn=clear_result,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  inputs=None,
403
  outputs=result,
404
- ).then( # Generate the new image
405
- fn=infer,
406
- inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
407
- resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
408
- overlap_left, overlap_right, overlap_top, overlap_bottom],
409
- outputs=result,
410
- ).then( # Update the history gallery
411
- fn=lambda x, history: update_history(x[1], history),
412
- inputs=[result, history_gallery],
413
- outputs=history_gallery,
414
- ).then( # Show the "Use as Input Image" button
415
- fn=lambda: gr.update(visible=True),
416
- inputs=None,
417
- outputs=use_as_input_button,
418
  )
419
 
420
- prompt_input.submit( # Clear the result
421
- fn=clear_result,
422
  inputs=None,
423
  outputs=result,
424
- ).then( # Generate the new image
425
- fn=infer,
426
- inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
427
- resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
428
- overlap_left, overlap_right, overlap_top, overlap_bottom],
429
- outputs=result,
430
- ).then( # Update the history gallery
431
- fn=lambda x, history: update_history(x[1], history),
432
- inputs=[result, history_gallery],
433
- outputs=history_gallery,
434
- ).then( # Show the "Use as Input Image" button
435
- fn=lambda: gr.update(visible=True),
436
- inputs=None,
437
- outputs=use_as_input_button,
438
  )
439
 
 
440
  preview_button.click(
441
  fn=preview_image_and_mask,
442
  inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
443
  overlap_left, overlap_right, overlap_top, overlap_bottom],
444
  outputs=preview_image,
445
- queue=False
446
  )
447
 
 
448
  demo.queue(max_size=20).launch(share=False, ssr_mode=False, show_error=True)
 
3
  import torch
4
  from diffusers import AutoencoderKL, TCDScheduler
5
  from diffusers.models.model_loading_utils import load_state_dict
6
+ # Removed: from gradio_imageslider import ImageSlider
7
  from huggingface_hub import hf_hub_download
8
 
9
  from controlnet_union import ControlNetModel_Union
 
12
  from PIL import Image, ImageDraw
13
  import numpy as np
14
 
15
+ # --- Model Loading (unchanged) ---
16
  config_file = hf_hub_download(
17
  "xinsir/controlnet-union-sdxl-1.0",
18
  filename="config_promax.json",
 
46
 
47
  pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
48
 
49
+ # --- Helper Functions (unchanged, except infer) ---
50
+
51
  def can_expand(source_width, source_height, target_width, target_height, alignment):
52
  """Checks if the image can be expanded based on the alignment."""
53
  if alignment in ("Left", "Right") and source_width >= target_width:
 
63
  scale_factor = min(target_size[0] / image.width, target_size[1] / image.height)
64
  new_width = int(image.width * scale_factor)
65
  new_height = int(image.height * scale_factor)
66
+
67
  # Resize the source image to fit within target size
68
  source = image.resize((new_width, new_height), Image.LANCZOS)
69
 
 
135
  right_overlap = margin_x + new_width - overlap_x if overlap_right else margin_x + new_width - white_gaps_patch
136
  top_overlap = margin_y + overlap_y if overlap_top else margin_y + white_gaps_patch
137
  bottom_overlap = margin_y + new_height - overlap_y if overlap_bottom else margin_y + new_height - white_gaps_patch
138
+
139
  if alignment == "Left":
140
  left_overlap = margin_x + overlap_x if overlap_left else margin_x
141
  elif alignment == "Right":
 
156
 
157
  def preview_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
158
  background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
159
+
160
  # Create a preview image showing the mask
161
  preview = background.copy().convert('RGBA')
162
+
163
  # Create a semi-transparent red overlay
164
  red_overlay = Image.new('RGBA', background.size, (255, 0, 0, 64)) # Reduced alpha to 64 (25% opacity)
165
+
166
  # Convert black pixels in the mask to semi-transparent red
167
  red_mask = Image.new('RGBA', background.size, (0, 0, 0, 0))
168
  red_mask.paste(red_overlay, (0, 0), mask)
169
+
170
  # Overlay the red mask on the background
171
  preview = Image.alpha_composite(preview, red_mask)
172
+
173
  return preview
174
 
175
  @spaces.GPU(duration=24)
176
  def infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
177
  background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
178
+
179
  if not can_expand(background.width, background.height, width, height, alignment):
180
+ alignment = "Middle" # Default to middle if expansion not possible with current alignment
181
 
182
  cnet_image = background.copy()
183
+ # Prepare the controlnet input image (original image with blacked-out mask area)
184
+ # Note: The pipeline expects the original image content where the mask is 0 (black)
185
+ # and the area to be filled where the mask is 255 (white).
186
+ # However, the current pipeline_fill_sd_xl seems to use the mask differently internally.
187
+ # Let's prepare the input image as per the original logic, which pastes black over the masked area.
188
+ black_fill = Image.new('RGB', cnet_image.size, (0, 0, 0))
189
+ # Invert the mask: white (255) becomes the area to keep, black (0) the area to fill
190
+ inverted_mask = Image.eval(mask, lambda x: 255 - x)
191
+ cnet_image.paste(black_fill, (0, 0), inverted_mask) # Paste black where the inverted mask is white (original mask was 0)
192
+
193
 
194
  final_prompt = f"{prompt_input} , high quality, 4k"
195
 
 
200
  negative_pooled_prompt_embeds,
201
  ) = pipe.encode_prompt(final_prompt, "cuda", True)
202
 
203
+ # Generate the image content for the masked area
204
+ # The pipeline yields the generated content for the masked area
205
+ # We only need the final result from the generator
206
+ generated_content = None
207
+ for res in pipe(
208
  prompt_embeds=prompt_embeds,
209
  negative_prompt_embeds=negative_prompt_embeds,
210
  pooled_prompt_embeds=pooled_prompt_embeds,
211
  negative_pooled_prompt_embeds=negative_pooled_prompt_embeds,
212
+ image=cnet_image, # Pass the image with blacked-out area
213
+ mask_image=mask, # Pass the mask (white = area to fill)
214
  num_inference_steps=num_inference_steps
215
  ):
216
+ generated_content = res # Keep updating until the last step
217
 
218
+ # The pipeline directly returns the final composite image in recent versions
219
+ # If it returns only the filled part, we need to composite it
220
+ # Let's assume the pipeline returns the final composited image based on its name "FillPipeline"
221
+ final_image = generated_content
222
+
223
+ # --- OLD compositing logic (keep commented in case pipeline behavior differs) ---
224
+ # # Convert generated content to RGBA to handle potential transparency
225
+ # generated_content = generated_content.convert("RGBA")
226
+ # # Create the final composite image by pasting the generated content onto the background
227
+ # final_image = background.copy().convert("RGBA")
228
+ # # Paste the generated content using the original mask (white area = where to paste)
229
+ # final_image.paste(generated_content, (0, 0), mask)
230
+ # final_image = final_image.convert("RGB") # Convert back to RGB if needed
231
+
232
+ # Yield only the final composited image
233
+ yield final_image
234
 
 
235
 
236
  def clear_result():
237
+ """Clears the result Image."""
238
  return gr.update(value=None)
239
 
240
  def preload_presets(target_ratio, ui_width, ui_height):
 
252
  changed_height = 1024
253
  return changed_width, changed_height, gr.update()
254
  elif target_ratio == "Custom":
255
+ # When switching to custom, keep current slider values but open the accordion
256
  return ui_width, ui_height, gr.update(open=True)
257
 
258
  def select_the_right_preset(user_width, user_height):
 
272
  """Updates the history gallery with the new image."""
273
  if history is None:
274
  history = []
275
+ # Ensure new_image is a PIL Image before inserting
276
+ if isinstance(new_image, Image.Image):
277
+ history.insert(0, new_image)
278
+ # Handle cases where the input might be None or not an image (e.g., during clearing)
279
+ elif new_image is not None:
280
+ print(f"Warning: Attempted to add non-image type to history: {type(new_image)}")
281
  return history
282
 
283
+
284
+ # --- Gradio UI ---
285
  css = """
286
  .gradio-container {
287
  width: 1200px !important;
 
317
  value="9:16",
318
  scale=2
319
  )
320
+
321
  alignment_dropdown = gr.Dropdown(
322
  choices=["Middle", "Left", "Right", "Top", "Bottom"],
323
  value="Middle",
 
332
  minimum=720,
333
  maximum=1536,
334
  step=8,
335
+ value=720, # Default for 9:16
336
  )
337
  height_slider = gr.Slider(
338
  label="Target Height",
339
  minimum=720,
340
  maximum=1536,
341
  step=8,
342
+ value=1280, # Default for 9:16
343
  )
344
+
345
  num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
346
  with gr.Group():
347
  overlap_percentage = gr.Slider(
 
354
  with gr.Row():
355
  overlap_top = gr.Checkbox(label="Overlap Top", value=True)
356
  overlap_right = gr.Checkbox(label="Overlap Right", value=True)
357
+ with gr.Row(): # Changed nesting for better layout
358
  overlap_left = gr.Checkbox(label="Overlap Left", value=True)
359
  overlap_bottom = gr.Checkbox(label="Overlap Bottom", value=True)
360
  with gr.Row():
 
371
  value=50,
372
  visible=False
373
  )
374
+
375
+ with gr.Column(): # Keep preview button separate
376
  preview_button = gr.Button("Preview alignment and mask")
377
+
378
+
379
  gr.Examples(
380
  examples=[
381
  ["./examples/example_1.webp", 1280, 720, "Middle"],
 
384
  ["./examples/example_3.jpg", 1024, 1024, "Bottom"],
385
  ],
386
  inputs=[input_image, width_slider, height_slider, alignment_dropdown],
387
+ # Ensure examples don't try to set output components directly
388
+ # outputs=[result], # Remove output mapping from examples
389
+ # fn=infer, # Don't run infer on example click, just load inputs
390
  )
391
 
 
392
 
393
  with gr.Column():
394
+ # *** MODIFICATION: Changed ImageSlider to Image ***
395
+ result = gr.Image(label="Generated Image", interactive=False, type="pil")
396
  use_as_input_button = gr.Button("Use as Input Image", visible=False)
397
 
398
+ history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", interactive=False, type="pil")
399
+ preview_image = gr.Image(label="Preview", type="pil") # Ensure preview is also PIL
400
 
401
+ # --- Event Handlers ---
402
 
403
  def use_output_as_input(output_image):
404
  """Sets the generated output as the new input image."""
405
+ # *** MODIFICATION: Access the image directly, not output_image[1] ***
406
+ return gr.update(value=output_image)
407
 
408
  use_as_input_button.click(
409
  fn=use_output_as_input,
410
+ inputs=[result], # Input is the single result image
411
  outputs=[input_image]
412
  )
413
+
414
  target_ratio.change(
415
  fn=preload_presets,
416
  inputs=[target_ratio, width_slider, height_slider],
 
418
  queue=False
419
  )
420
 
421
+ # Link sliders change to update the ratio selection to "Custom"
422
  width_slider.change(
423
  fn=select_the_right_preset,
424
  inputs=[width_slider, height_slider],
425
  outputs=[target_ratio],
426
  queue=False
427
+ ).then(
428
+ fn=lambda: gr.update(open=True), # Also open accordion on slider change
429
+ inputs=None,
430
+ outputs=settings_panel,
431
+ queue=False
432
  )
433
 
434
+
435
  height_slider.change(
436
  fn=select_the_right_preset,
437
  inputs=[width_slider, height_slider],
438
  outputs=[target_ratio],
439
  queue=False
440
+ ).then(
441
+ fn=lambda: gr.update(open=True), # Also open accordion on slider change
442
+ inputs=None,
443
+ outputs=settings_panel,
444
+ queue=False
445
  )
446
 
447
+
448
  resize_option.change(
449
  fn=toggle_custom_resize_slider,
450
  inputs=[resize_option],
451
  outputs=[custom_resize_percentage],
452
  queue=False
453
  )
454
+
455
+ # Combine run logic for Button and Textbox submission
456
+ run_inputs = [
457
+ input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
458
+ resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
459
+ overlap_left, overlap_right, overlap_top, overlap_bottom
460
+ ]
461
+
462
+ def run_generation(img, w, h, ov_perc, steps, res_opt, cust_res_perc, prompt, align, ov_l, ov_r, ov_t, ov_b, history):
463
+ # The infer function is a generator, we need to iterate to get the final value
464
+ final_image = None
465
+ for res_img in infer(img, w, h, ov_perc, steps, res_opt, cust_res_perc, prompt, align, ov_l, ov_r, ov_t, ov_b):
466
+ final_image = res_img
467
+
468
+ # Update history with the final image
469
+ updated_history = update_history(final_image, history)
470
+
471
+ # Return the final image for the result component and the updated history
472
+ return final_image, updated_history, gr.update(visible=True) # Also make button visible
473
+
474
+
475
+ run_button.click(
476
+ fn=clear_result, # First clear the previous result
477
  inputs=None,
478
  outputs=result,
479
+ queue=False # Clearing should be fast
480
+ ).then(
481
+ fn=run_generation, # Then run the generation and history update
482
+ inputs=run_inputs + [history_gallery], # Pass current history
483
+ outputs=[result, history_gallery, use_as_input_button], # Update result, history, and button visibility
 
 
 
 
 
 
 
 
 
484
  )
485
 
486
+ prompt_input.submit(
487
+ fn=clear_result, # First clear the previous result
488
  inputs=None,
489
  outputs=result,
490
+ queue=False # Clearing should be fast
491
+ ).then(
492
+ fn=run_generation, # Then run the generation and history update
493
+ inputs=run_inputs + [history_gallery], # Pass current history
494
+ outputs=[result, history_gallery, use_as_input_button], # Update result, history, and button visibility
 
 
 
 
 
 
 
 
 
495
  )
496
 
497
+
498
  preview_button.click(
499
  fn=preview_image_and_mask,
500
  inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
501
  overlap_left, overlap_right, overlap_top, overlap_bottom],
502
  outputs=preview_image,
503
+ queue=False # Preview should be fast
504
  )
505
 
506
+ # Launch the demo
507
  demo.queue(max_size=20).launch(share=False, ssr_mode=False, show_error=True)