Merge upstream

upstream
This commit is contained in:
lllyasviel 2024-02-21 23:56:45 -08:00 committed by GitHub
commit 95ddac3117
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 68 additions and 32 deletions

View File

@ -74,16 +74,18 @@ def uncrop(image, dest_size, paste_loc):
def apply_overlay(image, paste_loc, overlay): def apply_overlay(image, paste_loc, overlay):
if overlay is None: if overlay is None:
return image return image, image.copy()
if paste_loc is not None: if paste_loc is not None:
image = uncrop(image, (overlay.width, overlay.height), paste_loc) image = uncrop(image, (overlay.width, overlay.height), paste_loc)
original_denoised_image = image.copy()
image = image.convert('RGBA') image = image.convert('RGBA')
image.alpha_composite(overlay) image.alpha_composite(overlay)
image = image.convert('RGB') image = image.convert('RGB')
return image return image, original_denoised_image
def create_binary_mask(image, round=True): def create_binary_mask(image, round=True):
if image.mode == 'RGBA' and image.getextrema()[-1] != (255, 255): if image.mode == 'RGBA' and image.getextrema()[-1] != (255, 255):
@ -997,7 +999,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
if p.color_corrections is not None and i < len(p.color_corrections): if p.color_corrections is not None and i < len(p.color_corrections):
if save_samples and opts.save_images_before_color_correction: if save_samples and opts.save_images_before_color_correction:
image_without_cc = apply_overlay(image, p.paste_to, overlay_image) image_without_cc, _ = apply_overlay(image, p.paste_to, overlay_image)
images.save_image(image_without_cc, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p, suffix="-before-color-correction") images.save_image(image_without_cc, p.outpath_samples, "", p.seeds[i], p.prompts[i], opts.samples_format, info=infotext(i), p=p, suffix="-before-color-correction")
image = apply_color_correction(p.color_corrections[i], image) image = apply_color_correction(p.color_corrections[i], image)
@ -1005,12 +1007,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
# that is being composited over the original image, # that is being composited over the original image,
# we need to keep the original image around # we need to keep the original image around
# and use it in the composite step. # and use it in the composite step.
original_denoised_image = image.copy() image, original_denoised_image = apply_overlay(image, p.paste_to, overlay_image)
if p.paste_to is not None:
original_denoised_image = uncrop(original_denoised_image, (overlay_image.width, overlay_image.height), p.paste_to)
image = apply_overlay(image, p.paste_to, overlay_image)
if p.scripts is not None: if p.scripts is not None:
pp = scripts.PostprocessImageArgs(image) pp = scripts.PostprocessImageArgs(image)

View File

@ -284,6 +284,7 @@ options_templates.update(options_section(('ui_gallery', "Gallery", "ui"), {
"sd_webui_modal_lightbox_icon_opacity": OptionInfo(1, "Full page image viewer: control icon unfocused opacity", gr.Slider, {"minimum": 0.0, "maximum": 1, "step": 0.01}, onchange=shared.reload_gradio_theme).info('for mouse only').needs_reload_ui(), "sd_webui_modal_lightbox_icon_opacity": OptionInfo(1, "Full page image viewer: control icon unfocused opacity", gr.Slider, {"minimum": 0.0, "maximum": 1, "step": 0.01}, onchange=shared.reload_gradio_theme).info('for mouse only').needs_reload_ui(),
"sd_webui_modal_lightbox_toolbar_opacity": OptionInfo(0.9, "Full page image viewer: tool bar opacity", gr.Slider, {"minimum": 0.0, "maximum": 1, "step": 0.01}, onchange=shared.reload_gradio_theme).info('for mouse only').needs_reload_ui(), "sd_webui_modal_lightbox_toolbar_opacity": OptionInfo(0.9, "Full page image viewer: tool bar opacity", gr.Slider, {"minimum": 0.0, "maximum": 1, "step": 0.01}, onchange=shared.reload_gradio_theme).info('for mouse only').needs_reload_ui(),
"gallery_height": OptionInfo("", "Gallery height", gr.Textbox).info("can be any valid CSS value, for example 768px or 20em").needs_reload_ui(), "gallery_height": OptionInfo("", "Gallery height", gr.Textbox).info("can be any valid CSS value, for example 768px or 20em").needs_reload_ui(),
"open_dir_button_choice": OptionInfo("Subdirectory", "What directory the [📂] button opens", gr.Radio, {"choices": ["Output Root", "Subdirectory", "Subdirectory (even temp dir)"]}),
})) }))
options_templates.update(options_section(('ui_alternatives', "UI alternatives", "ui"), { options_templates.update(options_section(('ui_alternatives', "UI alternatives", "ui"), {

View File

@ -9,7 +9,7 @@ import sys
import gradio as gr import gradio as gr
import subprocess as sp import subprocess as sp
from modules import call_queue, shared from modules import call_queue, shared, ui_tempdir
from modules.infotext_utils import image_from_url_text from modules.infotext_utils import image_from_url_text
import modules.images import modules.images
from modules.ui_components import ToolButton from modules.ui_components import ToolButton
@ -164,29 +164,43 @@ class OutputPanel:
def create_output_panel(tabname, outdir, toprow=None): def create_output_panel(tabname, outdir, toprow=None):
res = OutputPanel() res = OutputPanel()
def open_folder(f): def open_folder(f, images=None, index=None):
if shared.cmd_opts.hide_ui_dir_config:
return
try:
if 'Sub' in shared.opts.open_dir_button_choice:
image_dir = os.path.split(images[index]["name"].rsplit('?', 1)[0])[0]
if 'temp' in shared.opts.open_dir_button_choice or not ui_tempdir.is_gradio_temp_path(image_dir):
f = image_dir
except Exception:
pass
if not os.path.exists(f): if not os.path.exists(f):
print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.') msg = f'Folder "{f}" does not exist. After you create an image, the folder will be created.'
print(msg)
gr.Info(msg)
return return
elif not os.path.isdir(f): elif not os.path.isdir(f):
print(f""" msg = f"""
WARNING WARNING
An open_folder request was made with an argument that is not a folder. An open_folder request was made with an argument that is not a folder.
This could be an error or a malicious attempt to run code on your computer. This could be an error or a malicious attempt to run code on your computer.
Requested path was: {f} Requested path was: {f}
""", file=sys.stderr) """
print(msg, file=sys.stderr)
gr.Warning(msg)
return return
if not shared.cmd_opts.hide_ui_dir_config: path = os.path.normpath(f)
path = os.path.normpath(f) if platform.system() == "Windows":
if platform.system() == "Windows": os.startfile(path)
os.startfile(path) elif platform.system() == "Darwin":
elif platform.system() == "Darwin": sp.Popen(["open", path])
sp.Popen(["open", path]) elif "microsoft-standard-WSL2" in platform.uname().release:
elif "microsoft-standard-WSL2" in platform.uname().release: sp.Popen(["wsl-open", path])
sp.Popen(["wsl-open", path]) else:
else: sp.Popen(["xdg-open", path])
sp.Popen(["xdg-open", path])
with gr.Column(elem_id=f"{tabname}_results"): with gr.Column(elem_id=f"{tabname}_results"):
if toprow: if toprow:
@ -214,8 +228,12 @@ Requested path was: {f}
res.button_upscale = ToolButton('', elem_id=f'{tabname}_upscale', tooltip="Create an upscaled version of the current image using hires fix settings.") res.button_upscale = ToolButton('', elem_id=f'{tabname}_upscale', tooltip="Create an upscaled version of the current image using hires fix settings.")
open_folder_button.click( open_folder_button.click(
fn=lambda: open_folder(shared.opts.outdir_samples or outdir), fn=lambda images, index: open_folder(shared.opts.outdir_samples or outdir, images, index),
inputs=[], _js="(y, w) => [y, selected_gallery_index()]",
inputs=[
res.gallery,
open_folder_button, # placeholder for index
],
outputs=[], outputs=[],
) )

View File

@ -472,7 +472,7 @@ class ExtraNetworksPage:
return f"<ul class='tree-list tree-list--tree'>{res}</ul>" return f"<ul class='tree-list tree-list--tree'>{res}</ul>"
def create_card_view_html(self, tabname: str) -> str: def create_card_view_html(self, tabname: str, *, none_message) -> str:
"""Generates HTML for the network Card View section for a tab. """Generates HTML for the network Card View section for a tab.
This HTML goes into the `extra-networks-pane.html` <div> with This HTML goes into the `extra-networks-pane.html` <div> with
@ -480,6 +480,7 @@ class ExtraNetworksPage:
Args: Args:
tabname: The name of the active tab. tabname: The name of the active tab.
none_message: HTML text to show when there are no cards.
Returns: Returns:
HTML formatted string. HTML formatted string.
@ -490,24 +491,28 @@ class ExtraNetworksPage:
if res == "": if res == "":
dirs = "".join([f"<li>{x}</li>" for x in self.allowed_directories_for_previews()]) dirs = "".join([f"<li>{x}</li>" for x in self.allowed_directories_for_previews()])
res = shared.html("extra-networks-no-cards.html").format(dirs=dirs) res = none_message or shared.html("extra-networks-no-cards.html").format(dirs=dirs)
return res return res
def create_html(self, tabname): def create_html(self, tabname, *, empty=False):
"""Generates an HTML string for the current pane. """Generates an HTML string for the current pane.
The generated HTML uses `extra-networks-pane.html` as a template. The generated HTML uses `extra-networks-pane.html` as a template.
Args: Args:
tabname: The name of the active tab. tabname: The name of the active tab.
empty: create an empty HTML page with no items
Returns: Returns:
HTML formatted string. HTML formatted string.
""" """
self.lister.reset() self.lister.reset()
self.metadata = {} self.metadata = {}
self.items = {x["name"]: x for x in self.list_items()}
items_list = [] if empty else self.list_items()
self.items = {x["name"]: x for x in items_list}
# Populate the instance metadata for each item. # Populate the instance metadata for each item.
for item in self.items.values(): for item in self.items.values():
metadata = item.get("metadata") metadata = item.get("metadata")
@ -536,7 +541,7 @@ class ExtraNetworksPage:
"tree_view_btn_extra_class": tree_view_btn_extra_class, "tree_view_btn_extra_class": tree_view_btn_extra_class,
"tree_view_div_extra_class": tree_view_div_extra_class, "tree_view_div_extra_class": tree_view_div_extra_class,
"tree_html": self.create_tree_view_html(tabname), "tree_html": self.create_tree_view_html(tabname),
"items_html": self.create_card_view_html(tabname), "items_html": self.create_card_view_html(tabname, none_message="Loading..." if empty else None),
} }
) )
@ -655,7 +660,7 @@ def create_ui(interface: gr.Blocks, unrelated_tabs, tabname):
pass pass
elem_id = f"{tabname}_{page.extra_networks_tabname}_cards_html" elem_id = f"{tabname}_{page.extra_networks_tabname}_cards_html"
page_elem = gr.HTML('Loading...', elem_id=elem_id) page_elem = gr.HTML(page.create_html(tabname, empty=True), elem_id=elem_id)
ui.pages.append(page_elem) ui.pages.append(page_elem)
editor = page.create_user_metadata_editor(ui, tabname) editor = page.create_user_metadata_editor(ui, tabname)
editor.create_ui() editor.create_ui()

View File

@ -81,3 +81,18 @@ def cleanup_tmpdr():
filename = os.path.join(root, name) filename = os.path.join(root, name)
os.remove(filename) os.remove(filename)
def is_gradio_temp_path(path):
"""
Check if the path is a temp dir used by gradio
"""
path = Path(path)
if shared.opts.temp_dir and path.is_relative_to(shared.opts.temp_dir):
return True
if gradio_temp_dir := os.environ.get("GRADIO_TEMP_DIR"):
if path.is_relative_to(gradio_temp_dir):
return True
if path.is_relative_to(Path(tempfile.gettempdir()) / "gradio"):
return True
return False