from modules.images import read_info_from_image from modules import script_callbacks, shared from PIL import Image import gradio as gr import re def parsePrompts(info: str) -> str: positive = negative = "" params = {} if "Negative prompt:" in info: positive, chunk = info.split("Negative prompt:") if "Steps" in chunk: negative, args = chunk.split("Steps") else: negative = chunk args = "" else: if "Steps" in info: positive, args = info.split("Steps") else: positive = info args = "" comma = ",(?=(?:[^\"]*[\"][^\"]*[\"])*[^\"]*$)" chunks = re.split(comma, ("Steps" + args)) for c in chunks: params[c.split(":", 1)[0].strip()] = c.split(":", 1)[1].strip() return ( positive.strip().replace("<", "<").replace(">", ">"), negative.strip().replace("<", "<").replace(">", ">"), params ) def toDiff(s: str) -> str: if len(s) == 0: return "" else: return f'{s}' def img2info(imgA, imgB) -> str: if imgA is None or imgB is None: return [gr.HTML.update(value=""), gr.HTML.update(value="")] infoA, _ = read_info_from_image(imgA) infoB, _ = read_info_from_image(imgB) if infoA is None or infoB is None: return [gr.HTML.update(value=""), gr.HTML.update(value="")] infoA = parsePrompts(infoA) infoB = parsePrompts(infoB) contentA = [] contentB = [] if infoA[0] == infoB[0]: contentA.append(infoA[0]) contentB.append(infoB[0]) else: contentA.append(toDiff(infoA[0])) contentB.append(toDiff(infoB[0])) if infoA[1] == infoB[1]: contentA.append(infoA[1]) contentB.append(infoB[1]) else: contentA.append(toDiff(infoA[1])) contentB.append(toDiff(infoB[1])) contentA[0] = f"Positive Prompt: {contentA[0]}" contentB[0] = f"Positive Prompt: {contentB[0]}" contentA[1] = f"Negative Prompt: {contentA[1]}" contentB[1] = f"Negative Prompt: {contentB[1]}" paramsA = [] paramsB = [] for K, V in infoA[2].items(): if K in infoB[2].keys(): if V == infoB[2][K]: paramsA.append(f"{K}: {V}") paramsB.append(f"{K}: {V}") else: paramsA.append(toDiff(f"{K}: {V}")) paramsB.append(toDiff(f"{K}: {infoB[2][K]}")) del infoB[2][K] else: paramsA.append(toDiff(f"{K}: {V}")) for K, V in infoB[2].items(): paramsB.append(toDiff(f"{K}: {V}")) contentA.append(f'Params: {", ".join(paramsA)}') contentB.append(f'Params: {", ".join(paramsB)}') return [ gr.HTML.update( value=f"""
Infotext

{'
'.join(contentA)}

""" ), gr.HTML.update( value=f"""
Infotext

{'
'.join(contentB)}

""" ), ] def img_ui(): dummy = Image.new('RGB', (1, 1), 'dimgrey') with gr.Blocks() as IMG_COMP: with gr.Row(elem_id='img_comp_row'): gr.Image( value=dummy, image_mode='RGB', type='pil', show_download_button=False, interactive=False, container=False, height=768, elem_id='img_comp_A' ) gr.Image( value=dummy, image_mode='RGB', type='pil', show_download_button=False, interactive=False, container=False, height=768, elem_id='img_comp_B' ) with gr.Row(): swap_btn = gr.Button('Swap', elem_id='img_comp_swap', scale=1) gr.Slider(label="Opacity", minimum=0.0, maximum=1.0, step=0.05, value=1.0, elem_id='img_comp_alpha', scale=3) dir_cb = gr.Checkbox(label='Horizontal Slider', value=True, elem_id='img_comp_horizontal', scale=1) with gr.Row(elem_id='img_comp_tools'): upload_A = gr.Image( image_mode='RGB', label='Image A', type='pil', show_download_button=False, interactive=True, height=256, elem_id='img_comp_input_A' ) with gr.Column(): comp_btn = gr.Button('Compare Upload', elem_id='img_comp_btn') i2i_btn = gr.Button('Compare img2img', elem_id='img_comp_i2i') inp_btn = gr.Button('Compare Inpaint', elem_id='img_comp_inpaint') ex_btn = gr.Button('Compare Extras', elem_id='img_comp_extras') upload_B = gr.Image( image_mode='RGB', label='Image B', type='pil', show_download_button=False, interactive=True, height=256, elem_id='img_comp_input_B' ) comp_btn.click(None, None, None, _js='() => { ImgCompLoader.loadImage("upload"); }') i2i_btn.click(None, None, None, _js='() => { ImgCompLoader.loadImage("i2i"); }') inp_btn.click(None, None, None, _js='() => { ImgCompLoader.loadImage("inpaint"); }') ex_btn.click(None, None, None, _js='() => { ImgCompLoader.loadImage("extras"); }') with gr.Row(elem_id='img_comp_info'): infotextA = gr.HTML() infotextB = gr.HTML() upload_A.change(img2info, [upload_A, upload_B], [infotextA, infotextB]) upload_B.change(img2info, [upload_A, upload_B], [infotextA, infotextB]) swap_btn.click(None, None, None, _js='() => { ImgCompLoader.swapImage(); }') dir_cb.change(None, None, None, _js='() => { ImageComparator.reset(); }') return [(IMG_COMP, 'Comparison', 'sd-webui-image-comparison')] def add_ui_settings(): shared.opts.add_option("comp_send_btn", shared.OptionInfo("Off", 'Add a "Send to Comparison" button under img2img generation result', gr.Radio, lambda: {"choices": ["Off", "Text", "Icon"]}, section=('ui', "User interface")).needs_reload_ui()) shared.opts.add_option("comp_send_btn_t2i", shared.OptionInfo("Off", 'Add a "Send to Comparison" button under txt2img generation result to compare against previous generation', gr.Radio, lambda: {"choices": ["Off", "Text", "Icon"]}, section=('ui', "User interface")).needs_reload_ui()) script_callbacks.on_ui_tabs(img_ui) script_callbacks.on_ui_settings(add_ui_settings)