From d609f6030ec464b371a899ced366c62bbd9a4a91 Mon Sep 17 00:00:00 2001 From: gk Date: Fri, 7 Apr 2023 21:04:46 +0900 Subject: Add [batch_number] and [generation_number] filename patterns --- modules/images.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index b3535070..5c0cf1d8 100644 --- a/modules/images.py +++ b/modules/images.py @@ -352,6 +352,8 @@ class FilenameGenerator: 'prompt_no_styles': lambda self: self.prompt_no_style(), 'prompt_spaces': lambda self: sanitize_filename_part(self.prompt, replace_spaces=False), 'prompt_words': lambda self: self.prompt_words(), + 'batch_number': lambda self: self.p.batch_index + 1, + 'generation_number': lambda self: self.p.iteration * self.p.batch_size + self.p.batch_index + 1, } default_time_format = '%Y%m%d%H%M%S' @@ -403,6 +405,10 @@ class FilenameGenerator: for m in re_pattern.finditer(x): text, pattern = m.groups() + + if pattern is not None and (pattern.lower() == 'batch_number' and self.p.batch_size == 1 or pattern.lower() == 'generation_number' and self.p.n_iter == 1 and self.p.batch_size == 1): + continue + res += text if pattern is None: -- cgit v1.2.1 From 02e351880796422eac3bbaf7aa86332b588651ce Mon Sep 17 00:00:00 2001 From: tqwuliao Date: Sat, 15 Apr 2023 23:20:08 +0800 Subject: Add new FilenameGenerator [hasprompt..] --- modules/images.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 2da988ee..cdbb77e1 100644 --- a/modules/images.py +++ b/modules/images.py @@ -349,6 +349,7 @@ class FilenameGenerator: 'prompt_no_styles': lambda self: self.prompt_no_style(), 'prompt_spaces': lambda self: sanitize_filename_part(self.prompt, replace_spaces=False), 'prompt_words': lambda self: self.prompt_words(), + 'hasprompt': lambda self, *args: self.hasprompt(*args), #accept formats:[hasprompt..] } default_time_format = '%Y%m%d%H%M%S' @@ -357,6 +358,22 @@ class FilenameGenerator: self.seed = seed self.prompt = prompt self.image = image + + def hasprompt(self, *args): + lower = self.prompt.lower() + if self.p is None or self.prompt is None: + return None + outres = "" + for arg in args: + if arg != "": + division = arg.split("|") + expected = division[0].lower() + default = division[1] if len(division) > 1 else "" + if lower.find(expected) >= 0: + outres = f'{outres}{expected}' + else: + outres = outres if default == "" else f'{outres}{default}' + return sanitize_filename_part(outres) def prompt_no_style(self): if self.p is None or self.prompt is None: -- cgit v1.2.1 From 596556162efd66cca225dffa3765d77cd51f69fe Mon Sep 17 00:00:00 2001 From: File_xor Date: Sun, 16 Apr 2023 16:49:21 +0900 Subject: Add filename pattern for CLIP_stop_at_last_layers. --- modules/images.py | 1 + 1 file changed, 1 insertion(+) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index b3535070..6391c34c 100644 --- a/modules/images.py +++ b/modules/images.py @@ -352,6 +352,7 @@ class FilenameGenerator: 'prompt_no_styles': lambda self: self.prompt_no_style(), 'prompt_spaces': lambda self: sanitize_filename_part(self.prompt, replace_spaces=False), 'prompt_words': lambda self: self.prompt_words(), + 'clip_skip': lambda: opts.data["CLIP_stop_at_last_layers"], } default_time_format = '%Y%m%d%H%M%S' -- cgit v1.2.1 From acbec225549987297383e3a31290b3f80ed064fd Mon Sep 17 00:00:00 2001 From: File_xor Date: Sun, 16 Apr 2023 17:14:11 +0900 Subject: Add self argument that is mandatory to [clip_skip] filename pattern. --- modules/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 6391c34c..1a118a69 100644 --- a/modules/images.py +++ b/modules/images.py @@ -352,7 +352,7 @@ class FilenameGenerator: 'prompt_no_styles': lambda self: self.prompt_no_style(), 'prompt_spaces': lambda self: sanitize_filename_part(self.prompt, replace_spaces=False), 'prompt_words': lambda self: self.prompt_words(), - 'clip_skip': lambda: opts.data["CLIP_stop_at_last_layers"], + 'clip_skip': lambda self: opts.data["CLIP_stop_at_last_layers"], } default_time_format = '%Y%m%d%H%M%S' -- cgit v1.2.1 From faff08f396f159a5ddd6328a6d2699b7e7d18ef9 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 29 Apr 2023 16:48:43 +0300 Subject: rework [batch_number]/[generation_number] filename patterns --- modules/images.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 9cd17ddd..fd173829 100644 --- a/modules/images.py +++ b/modules/images.py @@ -318,6 +318,7 @@ re_nonletters = re.compile(r'[\s' + string.punctuation + ']+') re_pattern = re.compile(r"(.*?)(?:\[([^\[\]]+)\]|$)") re_pattern_arg = re.compile(r"(.*)<([^>]*)>$") max_filename_part_length = 128 +NOTHING_AND_SKIP_PREVIOUS_TEXT = object() def sanitize_filename_part(text, replace_spaces=True): @@ -352,9 +353,9 @@ class FilenameGenerator: 'prompt_no_styles': lambda self: self.prompt_no_style(), 'prompt_spaces': lambda self: sanitize_filename_part(self.prompt, replace_spaces=False), 'prompt_words': lambda self: self.prompt_words(), - 'batch_number': lambda self: self.p.batch_index + 1, - 'generation_number': lambda self: self.p.iteration * self.p.batch_size + self.p.batch_index + 1, - 'hasprompt': lambda self, *args: self.hasprompt(*args), #accept formats:[hasprompt..] + 'batch_number': lambda self: NOTHING_AND_SKIP_PREVIOUS_TEXT if self.p.batch_size == 1 else self.p.batch_index + 1, + 'generation_number': lambda self: NOTHING_AND_SKIP_PREVIOUS_TEXT if self.p.n_iter == 1 and self.p.batch_size == 1 else self.p.iteration * self.p.batch_size + self.p.batch_index + 1, + 'hasprompt': lambda self, *args: self.hasprompt(*args), # accepts formats:[hasprompt..] 'clip_skip': lambda self: opts.data["CLIP_stop_at_last_layers"], } default_time_format = '%Y%m%d%H%M%S' @@ -424,12 +425,8 @@ class FilenameGenerator: for m in re_pattern.finditer(x): text, pattern = m.groups() - if pattern is not None and (pattern.lower() == 'batch_number' and self.p.batch_size == 1 or pattern.lower() == 'generation_number' and self.p.n_iter == 1 and self.p.batch_size == 1): - continue - - res += text - if pattern is None: + res += text continue pattern_args = [] @@ -450,11 +447,13 @@ class FilenameGenerator: print(f"Error adding [{pattern}] to filename", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) - if replacement is not None: - res += str(replacement) + if replacement == NOTHING_AND_SKIP_PREVIOUS_TEXT: + continue + elif replacement is not None: + res += text + str(replacement) continue - res += f'[{pattern}]' + res += f'{text}[{pattern}]' return res -- cgit v1.2.1 From cde0d642f34b2e008159eaeafb870d5efd1a3315 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Sat, 6 May 2023 02:20:33 +0900 Subject: add denoising strength filename pattern --- modules/images.py | 1 + 1 file changed, 1 insertion(+) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index fd173829..6ceb7c7c 100644 --- a/modules/images.py +++ b/modules/images.py @@ -357,6 +357,7 @@ class FilenameGenerator: 'generation_number': lambda self: NOTHING_AND_SKIP_PREVIOUS_TEXT if self.p.n_iter == 1 and self.p.batch_size == 1 else self.p.iteration * self.p.batch_size + self.p.batch_index + 1, 'hasprompt': lambda self, *args: self.hasprompt(*args), # accepts formats:[hasprompt..] 'clip_skip': lambda self: opts.data["CLIP_stop_at_last_layers"], + 'denoising': lambda self: self.p.denoising_strength if self.p and self.p.denoising_strength else NOTHING_AND_SKIP_PREVIOUS_TEXT, } default_time_format = '%Y%m%d%H%M%S' -- cgit v1.2.1 From 3ba6c3c83c0983a025c7bddc08bb7f49481b3cbb Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 9 May 2023 22:17:58 +0300 Subject: Fix up string formatting/concatenation to f-strings where feasible --- modules/images.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 6ceb7c7c..a41965ab 100644 --- a/modules/images.py +++ b/modules/images.py @@ -467,7 +467,7 @@ def get_next_sequence_number(path, basename): """ result = -1 if basename != '': - basename = basename + "-" + basename = f"{basename}-" prefix_length = len(basename) for p in os.listdir(path): @@ -536,7 +536,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i add_number = opts.save_images_add_number or file_decoration == '' if file_decoration != "" and add_number: - file_decoration = "-" + file_decoration + file_decoration = f"-{file_decoration}" file_decoration = namegen.apply(file_decoration) + suffix @@ -566,7 +566,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i def _atomically_save_image(image_to_save, filename_without_extension, extension): # save image with .tmp extension to avoid race condition when another process detects new image in the directory - temp_file_path = filename_without_extension + ".tmp" + temp_file_path = f"{filename_without_extension}.tmp" image_format = Image.registered_extensions()[extension] if extension.lower() == '.png': @@ -626,7 +626,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i if opts.save_txt and info is not None: txt_fullfn = f"{fullfn_without_extension}.txt" with open(txt_fullfn, "w", encoding="utf8") as file: - file.write(info + "\n") + file.write(f"{info}\n") else: txt_fullfn = None -- cgit v1.2.1 From 762265eab58cdb8f2d6398769bab43d8b8db0075 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 10 May 2023 07:52:45 +0300 Subject: autofixes from ruff --- modules/images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index a41965ab..3d5d76cc 100644 --- a/modules/images.py +++ b/modules/images.py @@ -409,13 +409,13 @@ class FilenameGenerator: time_format = args[0] if len(args) > 0 and args[0] != "" else self.default_time_format try: time_zone = pytz.timezone(args[1]) if len(args) > 1 else None - except pytz.exceptions.UnknownTimeZoneError as _: + except pytz.exceptions.UnknownTimeZoneError: time_zone = None time_zone_time = time_datetime.astimezone(time_zone) try: formatted_time = time_zone_time.strftime(time_format) - except (ValueError, TypeError) as _: + except (ValueError, TypeError): formatted_time = time_zone_time.strftime(self.default_time_format) return sanitize_filename_part(formatted_time, replace_spaces=False) -- cgit v1.2.1 From 96d6ca4199e7c5eee8d451618de5161cea317c40 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 10 May 2023 08:25:25 +0300 Subject: manual fixes for ruff --- modules/images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 3d5d76cc..5eb6d855 100644 --- a/modules/images.py +++ b/modules/images.py @@ -472,9 +472,9 @@ def get_next_sequence_number(path, basename): prefix_length = len(basename) for p in os.listdir(path): if p.startswith(basename): - l = os.path.splitext(p[prefix_length:])[0].split('-') # splits the filename (removing the basename first if one is defined, so the sequence number is always the first element) + parts = os.path.splitext(p[prefix_length:])[0].split('-') # splits the filename (removing the basename first if one is defined, so the sequence number is always the first element) try: - result = max(int(l[0]), result) + result = max(int(parts[0]), result) except ValueError: pass -- cgit v1.2.1 From f741a98baccae100fcfb40c017b5c35c5cba1b0c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 10 May 2023 08:43:42 +0300 Subject: imports cleanup for ruff --- modules/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 5eb6d855..7392cb8b 100644 --- a/modules/images.py +++ b/modules/images.py @@ -19,7 +19,7 @@ import json import hashlib from modules import sd_samplers, shared, script_callbacks, errors -from modules.shared import opts, cmd_opts +from modules.shared import opts LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) -- cgit v1.2.1 From a5121e7a0623db328a9462d340d389ed6737374a Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 10 May 2023 11:37:18 +0300 Subject: fixes for B007 --- modules/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 7392cb8b..c4e98c75 100644 --- a/modules/images.py +++ b/modules/images.py @@ -149,7 +149,7 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0): return ImageFont.truetype(Roboto, fontsize) def draw_texts(drawing, draw_x, draw_y, lines, initial_fnt, initial_fontsize): - for i, line in enumerate(lines): + for line in lines: fnt = initial_fnt fontsize = initial_fontsize while drawing.multiline_textsize(line.text, font=fnt)[0] > line.allowed_width and fontsize > 0: -- cgit v1.2.1 From df7070eca22278b25c921ef72d3f97a221d66242 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 11 May 2023 10:06:19 +0300 Subject: Deduplicate get_font code --- modules/images.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index c4e98c75..d8527179 100644 --- a/modules/images.py +++ b/modules/images.py @@ -24,6 +24,13 @@ from modules.shared import opts LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) +def get_font(fontsize: int): + try: + return ImageFont.truetype(opts.font or Roboto, fontsize) + except Exception: + return ImageFont.truetype(Roboto, fontsize) + + def image_grid(imgs, batch_size=1, rows=None): if rows is None: if opts.n_rows > 0: @@ -142,12 +149,6 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0): lines.append(word) return lines - def get_font(fontsize): - try: - return ImageFont.truetype(opts.font or Roboto, fontsize) - except Exception: - return ImageFont.truetype(Roboto, fontsize) - def draw_texts(drawing, draw_x, draw_y, lines, initial_fnt, initial_fontsize): for line in lines: fnt = initial_fnt -- cgit v1.2.1 From 1332c46b71b169b889d7df420f3285d9022da5cc Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 11 May 2023 10:07:01 +0300 Subject: Drop fonts + font-roboto deps since we only use the single regular cut of Roboto --- modules/images.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index d8527179..3b8b62d9 100644 --- a/modules/images.py +++ b/modules/images.py @@ -13,12 +13,12 @@ import numpy as np import piexif import piexif.helper from PIL import Image, ImageFont, ImageDraw, PngImagePlugin -from fonts.ttf import Roboto import string import json import hashlib from modules import sd_samplers, shared, script_callbacks, errors +from modules.paths_internal import roboto_ttf_file from modules.shared import opts LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) @@ -26,9 +26,9 @@ LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.L def get_font(fontsize: int): try: - return ImageFont.truetype(opts.font or Roboto, fontsize) + return ImageFont.truetype(opts.font or roboto_ttf_file, fontsize) except Exception: - return ImageFont.truetype(Roboto, fontsize) + return ImageFont.truetype(roboto_ttf_file, fontsize) def image_grid(imgs, batch_size=1, rows=None): -- cgit v1.2.1 From 49a55b410b66b7dd9be9335d8a2e3a71e4f8b15c Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 11 May 2023 18:28:15 +0300 Subject: Autofix Ruff W (not W605) (mostly whitespace) --- modules/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index 3b8b62d9..b2de3662 100644 --- a/modules/images.py +++ b/modules/images.py @@ -367,7 +367,7 @@ class FilenameGenerator: self.seed = seed self.prompt = prompt self.image = image - + def hasprompt(self, *args): lower = self.prompt.lower() if self.p is None or self.prompt is None: -- cgit v1.2.1 From a6b618d07248267de36f0e8f4a847d997285e272 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 17 May 2023 21:03:41 +0300 Subject: use a single function for saving images with metadata both in extra networks and main mode for #10395 --- modules/images.py | 70 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'modules/images.py') diff --git a/modules/images.py b/modules/images.py index b2de3662..4e8cd993 100644 --- a/modules/images.py +++ b/modules/images.py @@ -482,6 +482,43 @@ def get_next_sequence_number(path, basename): return result + 1 +def save_image_with_geninfo(image, geninfo, filename, extension=None, existing_pnginfo=None): + if extension is None: + extension = os.path.splitext(filename)[1] + + image_format = Image.registered_extensions()[extension] + + existing_pnginfo = existing_pnginfo or {} + if opts.enable_pnginfo: + existing_pnginfo['parameters'] = geninfo + + if extension.lower() == '.png': + pnginfo_data = PngImagePlugin.PngInfo() + for k, v in (existing_pnginfo or {}).items(): + pnginfo_data.add_text(k, str(v)) + + image.save(filename, format=image_format, quality=opts.jpeg_quality, pnginfo=pnginfo_data) + + elif extension.lower() in (".jpg", ".jpeg", ".webp"): + if image.mode == 'RGBA': + image = image.convert("RGB") + elif image.mode == 'I;16': + image = image.point(lambda p: p * 0.0038910505836576).convert("RGB" if extension.lower() == ".webp" else "L") + + image.save(filename, format=image_format, quality=opts.jpeg_quality, lossless=opts.webp_lossless) + + if opts.enable_pnginfo and geninfo is not None: + exif_bytes = piexif.dump({ + "Exif": { + piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(geninfo or "", encoding="unicode") + }, + }) + + piexif.insert(exif_bytes, filename) + else: + image.save(filename, format=image_format, quality=opts.jpeg_quality) + + def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None): """Save an image. @@ -566,38 +603,13 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i info = params.pnginfo.get(pnginfo_section_name, None) def _atomically_save_image(image_to_save, filename_without_extension, extension): - # save image with .tmp extension to avoid race condition when another process detects new image in the directory + """ + save image with .tmp extension to avoid race condition when another process detects new image in the directory + """ temp_file_path = f"{filename_without_extension}.tmp" - image_format = Image.registered_extensions()[extension] - - if extension.lower() == '.png': - pnginfo_data = PngImagePlugin.PngInfo() - if opts.enable_pnginfo: - for k, v in params.pnginfo.items(): - pnginfo_data.add_text(k, str(v)) - - image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality, pnginfo=pnginfo_data) - elif extension.lower() in (".jpg", ".jpeg", ".webp"): - if image_to_save.mode == 'RGBA': - image_to_save = image_to_save.convert("RGB") - elif image_to_save.mode == 'I;16': - image_to_save = image_to_save.point(lambda p: p * 0.0038910505836576).convert("RGB" if extension.lower() == ".webp" else "L") - - image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality, lossless=opts.webp_lossless) - - if opts.enable_pnginfo and info is not None: - exif_bytes = piexif.dump({ - "Exif": { - piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(info or "", encoding="unicode") - }, - }) - - piexif.insert(exif_bytes, temp_file_path) - else: - image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality) + save_image_with_geninfo(image_to_save, info, temp_file_path, extension, params.pnginfo) - # atomically rename the file with correct extension os.replace(temp_file_path, filename_without_extension + extension) fullfn_without_extension, extension = os.path.splitext(params.filename) -- cgit v1.2.1