simplify impaint/sketch canvas handling

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2024-11-28 13:28:46 -05:00
parent 964b4c9e5a
commit 425f51bb25
8 changed files with 60 additions and 95 deletions
+4 -1
View File
@@ -48,7 +48,8 @@
- control: hide preview column by default
- control: optionn to hide input column
- control: add stats
- browser->server logging framework
- browser -> server logging framework
- add addtional themes: `black-reimagined`
- **Sampler** improvements
- Euler FlowMatch: add sigma methods (*karras/exponential/betas*)
- DPM FlowMatch: update all and add sigma methods
@@ -65,6 +66,8 @@
- allow xyz-grid with multi-axis s&r
- fix xyz-grid with lora
- fix api script callbacks
- fix gpu memory monitoring
- simplify img2img/inpaint/sketch canvas handling
## Update for 2024-11-21
-1
View File
@@ -108,7 +108,6 @@ fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; }
.eta-bar { display: none !important }
.gradio-slider { max-width: 200px; }
.gradio-slider input[type="number"] { background: var(--neutral-950); margin-top: 2px; }
.gradio-image { height: unset !important; }
svg.feather.feather-image, .feather .feather-image { display: none }
.gap-2 { padding-top: 8px; }
.gr-box > div > div > input.gr-text-input { right: 0; width: 4em; padding: 0; top: -12px; border: none; max-height: 20px; }
-38
View File
@@ -1,38 +0,0 @@
/**
* temporary fix for https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/668
* @see https://github.com/gradio-app/gradio/issues/1721
*/
function imageMaskResize() {
const canvases = gradioApp().querySelectorAll('#img2maskimg .touch-none canvas');
if (!canvases.length) {
window.removeEventListener('resize', imageMaskResize);
return;
}
const wrapper = canvases[0].closest('.touch-none');
const previewImage = wrapper.previousElementSibling;
if (!previewImage.complete) {
previewImage.addEventListener('load', imageMaskResize);
return;
}
const w = previewImage.width;
const h = previewImage.height;
const nw = previewImage.naturalWidth;
const nh = previewImage.naturalHeight;
const portrait = nh > nw;
const wW = Math.min(w, portrait ? h / nh * nw : w / nw * nw);
const wH = Math.min(h, portrait ? h / nh * nh : w / nw * nh);
wrapper.style.width = `${wW}px`;
wrapper.style.height = `${wH}px`;
wrapper.style.left = '0px';
wrapper.style.top = '0px';
canvases.forEach((c) => {
c.style.width = '';
c.style.height = '';
c.style.maxWidth = '100%';
c.style.maxHeight = '100%';
c.style.objectFit = 'contain';
});
}
onAfterUiUpdate(imageMaskResize);
window.addEventListener('resize', imageMaskResize);
+13 -7
View File
@@ -30,6 +30,19 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { margin-left
.hidden { display: none; }
.tabitem { padding: 0 !important; }
/* gradio image/canvas elements */
.image-container { overflow: auto; }
/*
.gradio-image { min-height: fit-content; }
.gradio-image img { object-fit: contain; }
*/
/*
.gradio-image { min-height: 200px !important; }
.image-container { height: unset !important; }
.control-image { height: unset !important; }
#img2img_sketch, #img2maskimg, #inpaint_sketch { overflow: overlay !important; resize: auto; background: var(--panel-background-fill); z-index: 5; }
*/
/* color elements */
.gradio-dropdown, .block.gradio-slider, .block.gradio-checkbox, .block.gradio-textbox, .block.gradio-radio, .block.gradio-checkboxgroup, .block.gradio-number, .block.gradio-colorpicker { border-width: 0 !important; box-shadow: none !important;}
.gradio-accordion { padding-top: var(--spacing-md) !important; padding-right: 0 !important; padding-bottom: 0 !important; color: var(--body-text-color); }
@@ -87,8 +100,6 @@ button.custom-button { border-radius: var(--button-large-radius); padding: var(-
.performance .time { margin-right: 0; }
.thumbnails { background: var(--body-background-fill); }
.prompt textarea { resize: vertical; }
.image-container { height: unset !important; }
.control-image { height: unset !important; }
.grid-wrap { overflow-y: auto !important; }
#control_results { margin: 0; padding: 0; }
#txt2img_gallery, #img2img_gallery { height: 50vh; }
@@ -106,7 +117,6 @@ button.custom-button { border-radius: var(--button-large-radius); padding: var(-
#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt, #control_prompt, #control_neg_prompt { display: contents; }
#txt2img_actions_column, #img2img_actions_column, #control_actions { flex-flow: wrap; justify-content: space-between; }
.interrogate-clip { position: absolute; right: 6em; top: 8px; max-width: fit-content; background: none !important; z-index: 50; }
.interrogate-blip { position: absolute; right: 4em; top: 8px; max-width: fit-content; background: none !important; z-index: 50; }
.interrogate-col { min-width: 0 !important; max-width: fit-content; margin-right: var(--spacing-xxl); }
@@ -119,8 +129,6 @@ div#extras_scale_to_tab div.form { flex-direction: row; }
#img2img_unused_scale_by_slider { visibility: hidden; width: 0.5em; max-width: 0.5em; min-width: 0.5em; }
.inactive{ opacity: 0.5; }
div#extras_scale_to_tab div.form { flex-direction: row; }
#mode_img2img .gradio-image>div.fixed-height, #mode_img2img .gradio-image>div.fixed-height img{ height: 480px !important; max-height: 480px !important; min-height: 480px !important; }
#img2img_sketch, #img2maskimg, #inpaint_sketch { overflow: overlay !important; resize: auto; background: var(--panel-background-fill); z-index: 5; }
.image-buttons button { min-width: auto; }
.infotext { overflow-wrap: break-word; line-height: 1.5em; font-size: 0.95em !important; }
.infotext > p { white-space: pre-wrap; color: var(--block-info-text-color) !important; }
@@ -380,8 +388,6 @@ div:has(>#tab-gallery-folders) { flex-grow: 0 !important; background-color: var(
#img2img_actions_column { display: flex; min-width: fit-content !important; flex-direction: row;justify-content: space-evenly; align-items: center;}
#txt2img_generate_box, #img2img_generate_box, #txt2img_enqueue_wrapper,#img2img_enqueue_wrapper {display: flex;flex-direction: column;height: 4em !important;align-items: stretch;justify-content: space-evenly;}
#img2img_interface, #img2img_results, #img2img_footer p { text-wrap: wrap; min-width: 100% !important; max-width: 100% !important;} /* maintain single column for from image operations on larger mobile devices */
#img2img_sketch, #img2maskimg, #inpaint_sketch {display: flex; overflow: auto !important; resize: none !important; } /* fix inpaint image display being too large for mobile displays */
#img2maskimg canvas { width: auto !important; max-height: 100% !important; height: auto !important; }
#txt2img_sampler, #txt2img_batch, #txt2img_seed_group, #txt2img_advanced, #txt2img_second_pass, #img2img_sampling_group, #img2img_resize_group, #img2img_batch_group, #img2img_seed_group, #img2img_denoise_group, #img2img_advanced_group { width: 100% !important; } /* fix from text/image UI elements to prevent them from moving around within the UI */
#img2img_resize_group .gradio-radio>div { display: flex; flex-direction: column; width: unset !important; }
#inpaint_controls div { display:flex;flex-direction: row;}
+1 -1
View File
@@ -139,7 +139,7 @@ function switch_to_inpaint(...args) {
return Array.from(arguments);
}
function switch_to_inpaint_sketch(...args) {
function switch_to_composite(...args) {
switchToTab('Image');
switch_to_img2img_tab(3);
return Array.from(arguments);
+7 -7
View File
@@ -164,12 +164,7 @@ def img2img(id_task: str, state: str, mode: int,
return [], '', '', 'Error: init image not provided'
image = init_img.convert("RGB")
mask = None
elif mode == 1: # img2img sketch
if sketch is None:
return [], '', '', 'Error: sketch image not provided'
image = sketch.convert("RGB")
mask = None
elif mode == 2: # inpaint
elif mode == 1: # inpaint
if init_img_with_mask is None:
return [], '', '', 'Error: init image with mask not provided'
image = init_img_with_mask["image"]
@@ -177,7 +172,12 @@ def img2img(id_task: str, state: str, mode: int,
alpha_mask = ImageOps.invert(image.split()[-1]).convert('L').point(lambda x: 255 if x > 0 else 0, mode='1')
mask = ImageChops.lighter(alpha_mask, mask.convert('L')).convert('L')
image = image.convert("RGB")
elif mode == 3: # inpaint sketch
elif mode == 2: # sketch
if sketch is None:
return [], '', '', 'Error: sketch image not provided'
image = sketch.convert("RGB")
mask = None
elif mode == 3: # composite
if inpaint_color_sketch is None:
return [], '', '', 'Error: color sketch image not provided'
image = inpaint_color_sketch
+2 -2
View File
@@ -13,7 +13,7 @@ from modules import errors, shared, progress, ui_components, ui_symbols, ui_comm
from modules import ui_control_helpers as helpers
gr_height = None
gr_height = 512
max_units = shared.opts.control_max_units
units: list[unit.Unit] = [] # main state variable
controls: list[gr.component] = [] # list of gr controls
@@ -135,7 +135,7 @@ def create_ui(_blocks: gr.Blocks=None):
with gr.Row():
input_type = gr.Radio(label="Input type", choices=['Control only', 'Init image same as control', 'Separate init image'], value='Control only', type='index', elem_id='control_input_type')
with gr.Row():
denoising_strength = gr.Slider(minimum=0.01, maximum=1.0, step=0.01, label='Denoising strength', value=0.50, elem_id="control_input_denoising_strength")
denoising_strength = gr.Slider(minimum=0.01, maximum=1.0, step=0.01, label='Denoising strength', value=0.30, elem_id="control_input_denoising_strength")
with gr.Accordion(open=False, label="Size", elem_id="control_size", elem_classes=["small-accordion"]):
with gr.Tabs():
+33 -38
View File
@@ -1,7 +1,6 @@
import os
from PIL import Image
import gradio as gr
import numpy as np
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call
from modules import timer, shared, ui_common, ui_sections, generation_parameters_copypaste, processing_vae
@@ -56,7 +55,7 @@ def create_ui():
def add_copy_image_controls(tab_name, elem):
with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
for title, name in zip(['➠ Image', 'Sketch', 'Inpaint', '➠ Composite'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
for title, name in zip(['➠ Image', 'Inpaint', 'Sketch', '➠ Composite'], ['img2img', 'sketch', 'inpaint', 'composite']):
if name == tab_name:
gr.Button(title, elem_id=f'copy_to_{name}', interactive=False)
copy_image_destinations[name] = elem
@@ -67,33 +66,36 @@ def create_ui():
with gr.Tabs(elem_id="mode_img2img"):
img2img_selected_tab = gr.State(0) # pylint: disable=abstract-class-instantiated
state = gr.Textbox(value='', visible=False)
with gr.TabItem('Image', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img:
init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA")
with gr.TabItem('Image', id='img2img_image', elem_id="img2img_image_tab") as tab_img2img:
img_init = gr.Image(label="", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA", height=512)
interrogate_clip, interrogate_booru = ui_sections.create_interrogate_buttons('img2img')
add_copy_image_controls('img2img', init_img)
add_copy_image_controls('img2img', img_init)
with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_img2img_sketch_tab") as tab_sketch:
sketch = gr.Image(label="Image for img2img", elem_id="img2img_sketch", show_label=False, source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA")
add_copy_image_controls('sketch', sketch)
with gr.TabItem('Inpaint', id='img2img_inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint:
img_inpaint = gr.Image(label="", elem_id="img2img_inpaint", show_label=False, source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA", height=512)
add_copy_image_controls('inpaint', img_inpaint)
with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint:
init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA")
add_copy_image_controls('inpaint', init_img_with_mask)
with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_sketch_tab") as tab_sketch:
img_sketch = gr.Image(label="", elem_id="img2img_sketch", show_label=False, source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA", height=512)
add_copy_image_controls('sketch', img_sketch)
with gr.TabItem('Composite', id='inpaint_sketch', elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color:
inpaint_color_sketch = gr.Image(label="Color sketch inpainting", show_label=False, elem_id="inpaint_sketch", source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA")
inpaint_color_sketch_orig = gr.State(None) # pylint: disable=abstract-class-instantiated
add_copy_image_controls('inpaint_sketch', inpaint_color_sketch)
with gr.TabItem('Composite', id='img2img_composite', elem_id="img2img_composite_tab") as tab_inpaint_color:
img_composite = gr.Image(label="", show_label=False, elem_id="img2img_composite", source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA", height=512)
img_composite_orig = gr.State(None) # pylint: disable=abstract-class-instantiated
img_composite_orig_update = False
def update_orig(image, state):
if image is not None:
same_size = state is not None and state.size == image.size
has_exact_match = np.any(np.all(np.array(image) == np.array(state), axis=-1))
edited = same_size and has_exact_match
return image if not edited or state is None else state
return state
def fn_img_composite_upload():
nonlocal img_composite_orig_update
img_composite_orig_update = True
def fn_img_composite_change(img, img_composite):
nonlocal img_composite_orig_update
res = img if img_composite_orig_update else img_composite
img_composite_orig_update = False
return res
inpaint_color_sketch.change(update_orig, [inpaint_color_sketch, inpaint_color_sketch_orig], inpaint_color_sketch_orig)
img_composite.upload(fn=fn_img_composite_upload, inputs=[], outputs=[])
img_composite.change(fn=fn_img_composite_change, inputs=[img_composite, img_composite_orig], outputs=[img_composite_orig])
add_copy_image_controls('composite', img_composite)
with gr.TabItem('Upload', id='inpaint_upload', elem_id="img2img_inpaint_upload_tab") as tab_inpaint_upload:
init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", elem_id="img_inpaint_base")
@@ -120,13 +122,13 @@ def create_ui():
with gr.Accordion(open=False, label="Sampler", elem_classes=["small-accordion"], elem_id="img2img_sampler_group"):
steps, sampler_index = ui_sections.create_sampler_and_steps_selection(None, "img2img")
ui_sections.create_sampler_options('img2img')
resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab = ui_sections.create_resize_inputs('img2img', [init_img, sketch], latent=True, non_zero=False)
resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab = ui_sections.create_resize_inputs('img2img', [img_init, img_sketch], latent=True, non_zero=False)
batch_count, batch_size = ui_sections.create_batch_inputs('img2img', accordion=True)
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('img2img')
with gr.Accordion(open=False, label="Denoise", elem_classes=["small-accordion"], elem_id="img2img_denoise_group"):
with gr.Row():
denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Denoising strength', value=0.50, elem_id="img2img_denoising_strength")
denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Denoising strength', value=0.30, elem_id="img2img_denoising_strength")
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="img2img_refiner_start")
full_quality, tiling, hidiffusion, cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, cfg_end = ui_sections.create_advanced_inputs('img2img')
@@ -167,13 +169,8 @@ def create_ui():
img2img_args = [
dummy_component1, state, dummy_component2,
img2img_prompt, img2img_negative_prompt, img2img_prompt_styles,
init_img,
sketch,
init_img_with_mask,
inpaint_color_sketch,
inpaint_color_sketch_orig,
init_img_inpaint,
init_mask_inpaint,
img_init, img_sketch, img_inpaint, img_composite, img_composite_orig,
init_img_inpaint, init_mask_inpaint,
steps,
sampler_index,
mask_blur, mask_alpha,
@@ -225,10 +222,7 @@ def create_ui():
img2img_batch_files,
img2img_batch_input_dir,
img2img_batch_output_dir,
init_img,
sketch,
init_img_with_mask,
inpaint_color_sketch,
img_init, img_sketch, img_inpaint, img_composite,
init_img_inpaint,
],
outputs=[img2img_prompt, dummy_component],
@@ -285,7 +279,8 @@ def create_ui():
(seed_resize_from_h, "Seed resize from-2"),
*modules.scripts.scripts_img2img.infotext_fields
]
generation_parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields, override_settings)
generation_parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask, img2img_paste_fields, override_settings)
generation_parameters_copypaste.add_paste_fields("img2img", img_init, img2img_paste_fields, override_settings)
generation_parameters_copypaste.add_paste_fields("sketch", img_sketch, img2img_paste_fields, override_settings)
generation_parameters_copypaste.add_paste_fields("inpaint", img_inpaint, img2img_paste_fields, override_settings)
img2img_bindings = generation_parameters_copypaste.ParamBinding(paste_button=img2img_paste, tabname="img2img", source_text_component=img2img_prompt, source_image_component=None)
generation_parameters_copypaste.register_paste_params_button(img2img_bindings)