From efa87a6abe1fd5098682d60b1670e18bd9c09c74 Mon Sep 17 00:00:00 2001 From: MarcusNyne <69087098+MarcusNyne@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:26:56 -0400 Subject: [PATCH] Display features for PNG Info tab Text on PNG Info tab is parsed and colorized in a way that makes it easier to read. Parameter values can be copied by clicking on them. - High performance regex used for parsing - Normal values are displayed in blue, but string content is displayed in orange to improve readability (i.e. adetailer prompts) - Clicking to copy uses a pointer cursor and a green color animation to show something is happening - Color choices configured differently for dark mode in order to optimize readability - Copying strings with \n automatically converts to newlines during copy operation - Settings that don't follow normal conventions are not parsed, but displayed in the old style (i.e. dynamic prompt templates) - If there are parsing issues (or exceptions), defaults to the old display mode --- modules/extras.py | 45 ++++++++++++++++++++++--- modules/png_parser.py | 48 +++++++++++++++++++++++++++ script.js | 14 ++++++++ style.css | 76 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 modules/png_parser.py diff --git a/modules/extras.py b/modules/extras.py index 2a310ae3f..a6fc9f497 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -2,27 +2,62 @@ import os import re import shutil import json - +import html import torch import tqdm -from modules import shared, images, sd_models, sd_vae, sd_models_config, errors +from modules import shared, images, sd_models, sd_vae, sd_models_config, errors, png_parser from modules.ui_common import plaintext_to_html import gradio as gr import safetensors.torch +def pnginfo_format_setting(name, value): + cls_name = 'geninfo-setting-string' if value.startswith('"') else 'geninfo-setting-value' + return f"{html.escape(name)}: {html.escape(value)}" + def run_pnginfo(image): if image is None: return '', '', '' geninfo, items = images.read_info_from_image(image) - items = {**{'parameters': geninfo}, **items} info = '' - for key, text in items.items(): - info += f""" + parser = png_parser.PngParser(geninfo) + if parser.valid: + info += f""" +
parameters
+{plaintext_to_html(str(parser.positive))} +
+Negative prompt:
{html.escape(str(parser.negative))}
+
" + first = True + for setting in parser.settings: + if first: + first = False + else: + info += ", " + info += pnginfo_format_setting(str(setting[0]), str(setting[1])+str(setting[2])) + info += f"
" + + if parser.extra is not None: + info += f"{plaintext_to_html(str(parser.extra))}" + + info += f""" +{plaintext_to_html(str(key))}
{plaintext_to_html(str(text))}
diff --git a/modules/png_parser.py b/modules/png_parser.py new file mode 100644 index 000000000..f06576fb5 --- /dev/null +++ b/modules/png_parser.py @@ -0,0 +1,48 @@ +import re + +class PngParser: + re_top_level = None + re_extra_newline = None + re_parameters = None + + def __init__(self, pnginfo_string): + PngParser.init_re() + + self.valid = self.parse_pnginfo(pnginfo_string) + + def parse_pnginfo(self, pnginfo_string): + try: + # separate positive, negative, and parameters + tlen = len(pnginfo_string) + m = PngParser.re_top_level.search(pnginfo_string) + if m is None: + return False + + self.positive = m.group(1) + self.negative = m.group(2) + self.parameters = m.group(3) + self.extra = None + self.settings = None + + # parse extra parameters (if they exist) by a newline outside of quotes + m = PngParser.re_extra_newline.search(self.parameters) + if m is not None: + s = m.span() + self.extra = self.parameters[s[1]:] + self.parameters = self.parameters[:s[0]] + + # parse standard parameters + self.settings = PngParser.re_parameters.findall(self.parameters) + if self.settings is None: + return False + except: + return False + + return True + + @classmethod + def init_re(cls): + if cls.re_top_level is None: + cls.re_top_level = re.compile(r'^(?P")?(?P(?(2)(?:.)*?(?:(? { + el.classList.add('animate'); + }, 0); +} diff --git a/style.css b/style.css index 64ef61bad..2e054614e 100644 --- a/style.css +++ b/style.css @@ -1665,3 +1665,79 @@ body.resizing .resize-handle { visibility: visible; width: auto; } + +/* PngInfo colors */ +:root { + --pnginfo-value-color:var(--secondary-600); + --pnginfo-string-color:var(--primary-600); + --pnginfo-value-hover:var(--secondary-100); + --pnginfo-string-hover:var(--primary-100); + --pnginfo-copy-color:#22c922; + --pnginfo-copy-background:#a9cfa9; +} + +.dark { + --pnginfo-value-color:var(--secondary-400); + --pnginfo-string-color:var(--primary-400); + --pnginfo-value-hover:var(--secondary-700); + --pnginfo-string-hover:var(--primary-700); + --pnginfo-copy-color:#a9cfa9; + --pnginfo-copy-background:#22c922; +} + +/* PngInfo styles */ +.pnginfo-page p span.geninfo-setting-name { + font-weight: var(--weight-semibold); +} + +.pnginfo-page p span.geninfo-setting-value { + color: var(--pnginfo-value-color); + cursor: pointer; +} + +.pnginfo-page p span.geninfo-setting-value:hover { + background-color: var(--pnginfo-value-hover); +} + +.pnginfo-page p span.geninfo-setting-string { + color: var(--pnginfo-string-color); + font-style: italic; + cursor: pointer; +} + +.pnginfo-page p span.geninfo-setting-string:hover { + background-color: var(--pnginfo-string-hover); +} + +/* PngInfo animations */ +@keyframes copyAnimationSettingValue { + 0% { + color: var(--pnginfo-copy-color); + background-color: var(--pnginfo-copy-background); + } + 100% { + color: var(--pnginfo-value-color); + background-color: unset; + } +} + +span.geninfo-setting-value.animate { + -webkit-animation: copyAnimationSettingValue 1s 1; + animation: copyAnimationSettingValue 1s 1; +} + +@keyframes copyAnimationSettingString { + 0% { + color: var(--pnginfo-copy-color); + background-color: var(--pnginfo-copy-background); + } + 100% { + color: var(--pnginfo-string-color); + background-color: unset; + } +} + +span.geninfo-setting-string.animate { + -webkit-animation: copyAnimationSettingString 1s 1; + animation: copyAnimationSettingString 1s 1; +} \ No newline at end of file