From de5bfdf9177d7035c76a890c241f8a5a32455cad Mon Sep 17 00:00:00 2001 From: JJ Date: Sat, 17 Sep 2022 06:48:22 +1000 Subject: [PATCH 01/10] image info tab * handles exceptions if jpeg jfif data not present * removes further non-comment related exif data. --- modules/extras.py | 7 ++++--- modules/ui.py | 4 ++-- webui.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 38d6ec484..64b4f2b6c 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -97,7 +97,7 @@ def run_extras(image, image_folder, gfpgan_visibility, codeformer_visibility, co return outputs, plaintext_to_html(info), '' -def run_pnginfo(image): +def run_image_info(image): items = image.info if "exif" in image.info: @@ -111,8 +111,9 @@ def run_pnginfo(image): items['exif comment'] = exif_comment - for field in ['jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif']: - del items[field] + for field in ['jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif', + 'loop', 'background', 'timestamp', 'duration']: + items.pop(field, None) info = '' diff --git a/modules/ui.py b/modules/ui.py index 738ac945b..0899490f2 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -295,7 +295,7 @@ def create_toprow(is_img2img): return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, check_progress -def create_ui(txt2img, img2img, run_extras, run_pnginfo): +def create_ui(txt2img, img2img, run_extras, run_image_info): with gr.Blocks(analytics_enabled=False) as txt2img_interface: txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, check_progress = create_toprow(is_img2img=False) @@ -697,7 +697,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo): submit.click(**extras_args) pnginfo_interface = gr.Interface( - wrap_gradio_call(run_pnginfo), + wrap_gradio_call(run_image_info), inputs=[ gr.Image(label="Source", source="upload", interactive=True, type="pil"), ], diff --git a/webui.py b/webui.py index add721233..cbfb62f04 100644 --- a/webui.py +++ b/webui.py @@ -121,7 +121,7 @@ def webui(): txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), img2img=wrap_gradio_gpu_call(modules.img2img.img2img), run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), - run_pnginfo=modules.extras.run_pnginfo + run_image_info=modules.extras.run_image_info ) demo.launch( From 047a623f7a5c585d308d25268763f76ea225f9a0 Mon Sep 17 00:00:00 2001 From: jjisnow Date: Sat, 17 Sep 2022 16:07:07 +1000 Subject: [PATCH 02/10] Restore run_pnginfo --- modules/extras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/extras.py b/modules/extras.py index 64b4f2b6c..3d9d9f7a8 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -97,7 +97,7 @@ def run_extras(image, image_folder, gfpgan_visibility, codeformer_visibility, co return outputs, plaintext_to_html(info), '' -def run_image_info(image): +def run_pnginfo(image): items = image.info if "exif" in image.info: From 588d6de4a870a80862377d14c4f316ff13e5e818 Mon Sep 17 00:00:00 2001 From: jjisnow Date: Sat, 17 Sep 2022 16:08:56 +1000 Subject: [PATCH 03/10] Update ui.py Reverse run_pnginfo for compatibility reasons --- modules/ui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 0899490f2..738ac945b 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -295,7 +295,7 @@ def create_toprow(is_img2img): return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, check_progress -def create_ui(txt2img, img2img, run_extras, run_image_info): +def create_ui(txt2img, img2img, run_extras, run_pnginfo): with gr.Blocks(analytics_enabled=False) as txt2img_interface: txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, check_progress = create_toprow(is_img2img=False) @@ -697,7 +697,7 @@ def create_ui(txt2img, img2img, run_extras, run_image_info): submit.click(**extras_args) pnginfo_interface = gr.Interface( - wrap_gradio_call(run_image_info), + wrap_gradio_call(run_pnginfo), inputs=[ gr.Image(label="Source", source="upload", interactive=True, type="pil"), ], From b172cd56e820c2ee107a2a0bc4cfb45de34ede4b Mon Sep 17 00:00:00 2001 From: jjisnow Date: Sat, 17 Sep 2022 16:09:53 +1000 Subject: [PATCH 04/10] Update webui.py --- webui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webui.py b/webui.py index cbfb62f04..576b4a3d0 100644 --- a/webui.py +++ b/webui.py @@ -9,7 +9,7 @@ from omegaconf import OmegaConf import signal from ldm.util import instantiate_from_config - +run_ from modules.shared import opts, cmd_opts, state import modules.shared as shared import modules.ui @@ -121,7 +121,7 @@ def webui(): txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), img2img=wrap_gradio_gpu_call(modules.img2img.img2img), run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), - run_image_info=modules.extras.run_image_info + run_pnginfo=modules.extras.run_pnginfo ) demo.launch( From ac61e4663c21ea0f51a4319162d3877e00554a2a Mon Sep 17 00:00:00 2001 From: jjisnow Date: Sat, 17 Sep 2022 16:10:46 +1000 Subject: [PATCH 05/10] Update webui.py --- webui.py | 1 - 1 file changed, 1 deletion(-) diff --git a/webui.py b/webui.py index 576b4a3d0..1a6208b75 100644 --- a/webui.py +++ b/webui.py @@ -9,7 +9,6 @@ from omegaconf import OmegaConf import signal from ldm.util import instantiate_from_config -run_ from modules.shared import opts, cmd_opts, state import modules.shared as shared import modules.ui From ba295b32688629cf575d67f1750a7838b008858b Mon Sep 17 00:00:00 2001 From: Tony Beeman Date: Sat, 17 Sep 2022 01:34:33 -0700 Subject: [PATCH 06/10] * Fix process_images where the number of images is not a multiple of (batch_size * n_iter), which would cause us to throw an exception. * Add a textbox option to Prompts from file (ease of use and it makes it much easier to use on a mobile device) * Fix the fact that Prompts from file was sometimes passing an empty batch. --- modules/processing.py | 9 ++++++++- scripts/prompts_from_file.py | 34 ++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 3a4ff224b..6a99d3837 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -188,7 +188,11 @@ def fix_seed(p): def process_images(p: StableDiffusionProcessing) -> Processed: """this is the main loop that both txt2img and img2img use; it calls func_init once inside all the scopes and func_sample once per batch""" - assert p.prompt is not None + if type(p.prompt) == list: + assert(len(p.prompt) > 0) + else: + assert p.prompt is not None + devices.torch_gc() fix_seed(p) @@ -265,6 +269,9 @@ def process_images(p: StableDiffusionProcessing) -> Processed: seeds = all_seeds[n * p.batch_size:(n + 1) * p.batch_size] subseeds = all_subseeds[n * p.batch_size:(n + 1) * p.batch_size] + if (len(prompts) == 0): + break + #uc = p.sd_model.get_learned_conditioning(len(prompts) * [p.negative_prompt]) #c = p.sd_model.get_learned_conditioning(prompts) uc = prompt_parser.get_learned_conditioning(len(prompts) * [p.negative_prompt], p.steps) diff --git a/scripts/prompts_from_file.py b/scripts/prompts_from_file.py index d9b01c81b..513d9a1c5 100644 --- a/scripts/prompts_from_file.py +++ b/scripts/prompts_from_file.py @@ -13,28 +13,42 @@ from modules.shared import opts, cmd_opts, state class Script(scripts.Script): def title(self): - return "Prompts from file" + return "Prompts from file or textbox" def ui(self, is_img2img): + # This checkbox would look nicer as two tabs, but there are two problems: + # 1) There is a bug in Gradio 3.3 that prevents visibility from working on Tabs + # 2) Even with Gradio 3.3.1, returning a control (like Tabs) that can't be used as input + # causes a AttributeError: 'Tabs' object has no attribute 'preprocess' assert, + # due to the way Script assumes all controls returned can be used as inputs. + # Therefore, there's no good way to use grouping components right now, + # so we will use a checkbox! :) + checkbox_txt = gr.Checkbox(label="Show Textbox", value=False) file = gr.File(label="File with inputs", type='bytes') + prompt_txt = gr.TextArea(label="Prompts") + checkbox_txt.change(fn=lambda x: [gr.File.update(visible = not x), gr.TextArea.update(visible = x)], inputs=[checkbox_txt], outputs=[file, prompt_txt]) + return [checkbox_txt, file, prompt_txt] - return [file] - - def run(self, p, data: bytes): - lines = [x.strip() for x in data.decode('utf8', errors='ignore').split("\n")] + def run(self, p, checkbox_txt, data: bytes, prompt_txt: str): + if (checkbox_txt): + lines = [x.strip() for x in prompt_txt.splitlines()] + else: + lines = [x.strip() for x in data.decode('utf8', errors='ignore').split("\n")] lines = [x for x in lines if len(x) > 0] - batch_count = math.ceil(len(lines) / p.batch_size) - print(f"Will process {len(lines) * p.n_iter} images in {batch_count * p.n_iter} batches.") + img_count = len(lines) * p.n_iter + batch_count = math.ceil(img_count / p.batch_size) + loop_count = math.ceil(batch_count / p.n_iter) + print(f"Will process {img_count} images in {batch_count} batches.") p.do_not_save_grid = True state.job_count = batch_count images = [] - for batch_no in range(batch_count): - state.job = f"{batch_no + 1} out of {batch_count * p.n_iter}" - p.prompt = lines[batch_no*p.batch_size:(batch_no+1)*p.batch_size] * p.n_iter + for loop_no in range(loop_count): + state.job = f"{loop_no + 1} out of {loop_count}" + p.prompt = lines[loop_no*p.batch_size:(loop_no+1)*p.batch_size] * p.n_iter proc = process_images(p) images += proc.images From 65be5312dc2b73e659299ea052d5484e6ae6c0ea Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 17 Sep 2022 01:00:45 +0100 Subject: [PATCH 07/10] Add modal css classes --- style.css | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/style.css b/style.css index 752d2cf42..2de83a946 100644 --- a/style.css +++ b/style.css @@ -196,3 +196,40 @@ input[type="range"]{ border-radius: 8px; } +#lightboxModal{ + display: none; + position: fixed; + z-index: 900; + padding-top: 100px; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: black; +} + +.modalClose { + color: white; + position: absolute; + top: 10px; + right: 25px; + font-size: 35px; + font-weight: bold; +} + +.modalClose:hover, +.modalClose:focus { + color: #999; + text-decoration: none; + cursor: pointer; +} + +#modalImage { + display: block; + margin-left: auto; + margin-right: auto; + margin-top: auto; + width: auto; +} + From 1a513370774ccb4cd9562f1b40048adc2ab7c896 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 17 Sep 2022 01:03:03 +0100 Subject: [PATCH 08/10] Add modal creation and functions --- script.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/script.js b/script.js index e63e06956..7c27da74b 100644 --- a/script.js +++ b/script.js @@ -76,6 +76,35 @@ function gradioApp(){ global_progressbar = null +function closeModal() { + gradioApp().getElementById("lightboxModal").style.display = "none"; +} + +function showModal(elem) { + gradioApp().getElementById("modalImage").src = elem.src + gradioApp().getElementById("lightboxModal").style.display = "block"; +} + +function showGalleryImage(){ + setTimeout(function() { + fullImg_preview = gradioApp().querySelectorAll('img.w-full.object-contain') + + if(fullImg_preview != null){ + fullImg_preview.forEach(function function_name(e) { + if(e && e.parentElement.tagName == 'DIV'){ + e.style.cursor='pointer' + + elemfunc = function(elem){ + elem.onclick = function(){showModal(elem)}; + } + elemfunc(e) + } + }); + } + + }, 100); +} + function addTitles(root){ root.querySelectorAll('span, button, select').forEach(function(span){ tooltip = titles[span.textContent]; @@ -117,8 +146,18 @@ function addTitles(root){ img2img_preview.style.width = img2img_gallery.clientWidth + "px" img2img_preview.style.height = img2img_gallery.clientHeight + "px" } + + fullImg_preview = gradioApp().querySelectorAll('img.w-full') + if(fullImg_preview != null){ + fullImg_preview.forEach(function function_name(e) { + if(e && e.parentElement.tagName == 'BUTTON'){ + e.onclick = showGalleryImage; + } + }); + } + window.setTimeout(requestProgress, 500) }); mutationObserver.observe( progressbar, { childList:true, subtree:true }) @@ -131,6 +170,27 @@ document.addEventListener("DOMContentLoaded", function() { addTitles(gradioApp()); }); mutationObserver.observe( gradioApp(), { childList:true, subtree:true }) + + const modalFragment = document.createDocumentFragment(); + const modal = document.createElement('div') + modal.onclick = closeModal; + + const modalClose = document.createElement('span') + modalClose.className = 'modalClose cursor'; + modalClose.innerHTML = '×' + modalClose.onclick = closeModal; + modal.id = "lightboxModal"; + modal.appendChild(modalClose) + + const modalImage = document.createElement('img') + modalImage.id = 'modalImage'; + modalImage.onclick = closeModal; + modal.appendChild(modalImage) + + gradioApp().getRootNode().appendChild(modal) + + document.body.appendChild(modalFragment); + }); function selected_gallery_index(){ From a66d857345c090674430c21fba1256c76d769635 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 17 Sep 2022 01:13:28 +0100 Subject: [PATCH 09/10] make background semi-transparent not black; --- style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/style.css b/style.css index 2de83a946..2bdd1e0e3 100644 --- a/style.css +++ b/style.css @@ -206,7 +206,7 @@ input[type="range"]{ width: 100%; height: 100%; overflow: auto; - background-color: black; + background-color: rgba(20, 20, 20, 0.95); } .modalClose { From 1ef79f926e6314b3ef9308b12ff7ad482afd790a Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 17 Sep 2022 03:26:47 +0100 Subject: [PATCH 10/10] generalise to work on all non-masked images on all tabs --- script.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/script.js b/script.js index 7c27da74b..a016eb4ec 100644 --- a/script.js +++ b/script.js @@ -105,6 +105,12 @@ function showGalleryImage(){ }, 100); } +function galleryImageHandler(e){ + if(e && e.parentElement.tagName == 'BUTTON'){ + e.onclick = showGalleryImage; + } +} + function addTitles(root){ root.querySelectorAll('span, button, select').forEach(function(span){ tooltip = titles[span.textContent]; @@ -147,22 +153,17 @@ function addTitles(root){ img2img_preview.style.height = img2img_gallery.clientHeight + "px" } - fullImg_preview = gradioApp().querySelectorAll('img.w-full') - - if(fullImg_preview != null){ - - fullImg_preview.forEach(function function_name(e) { - if(e && e.parentElement.tagName == 'BUTTON'){ - e.onclick = showGalleryImage; - } - }); - } - window.setTimeout(requestProgress, 500) }); mutationObserver.observe( progressbar, { childList:true, subtree:true }) } + + fullImg_preview = gradioApp().querySelectorAll('img.w-full') + if(fullImg_preview != null){ + fullImg_preview.forEach(galleryImageHandler); + } + } document.addEventListener("DOMContentLoaded", function() {