From 3d38f6ea73a3e8b4fa217a7d88a274c31358b3d3 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 25 Sep 2024 19:32:57 -0400 Subject: [PATCH] update xyz grid --- cli/image-exif.py | 3 +++ modules/images.py | 6 +++++- modules/images_namegen.py | 14 +++++++------- scripts/xyz_grid.py | 5 ++++- scripts/xyz_grid_classes.py | 4 ++-- scripts/xyz_grid_draw.py | 3 +-- scripts/xyz_grid_on.py | 10 ++++++++-- scripts/xyz_grid_shared.py | 6 ++++++ 8 files changed, 36 insertions(+), 15 deletions(-) diff --git a/cli/image-exif.py b/cli/image-exif.py index c3954204a..10fb4010f 100755 --- a/cli/image-exif.py +++ b/cli/image-exif.py @@ -100,6 +100,7 @@ def read_exif(filename: str): from pi_heif import register_heif_opener register_heif_opener() try: + print('HERE', filename) image = Image.open(filename) exif = Exif(image) print('image:', filename, 'format:', image) @@ -120,3 +121,5 @@ if __name__ == '__main__': for root, _dirs, files in os.walk(fn): for file in files: read_exif(os.path.join(root, file)) + else: + print('file not found: ', fn) diff --git a/modules/images.py b/modules/images.py index e85dd3fc6..6808bb176 100644 --- a/modules/images.py +++ b/modules/images.py @@ -128,7 +128,7 @@ def save_image(image, path = shared.opts.outdir_save namegen = FilenameGenerator(p, seed, prompt, image, grid=grid) suffix = suffix if suffix is not None else '' - basename = basename if basename is not None else '' + basename = '' if basename is None else basename if shared.opts.save_to_dirs: dirname = namegen.apply(shared.opts.directories_filename_pattern or "[prompt_words]") path = os.path.join(path, dirname) @@ -139,9 +139,13 @@ def save_image(image, file_decoration = "[seq]-[prompt_words]" file_decoration = namegen.apply(file_decoration) file_decoration += suffix if suffix is not None else '' + if file_decoration.startswith(basename): + basename = '' filename = os.path.join(path, f"{file_decoration}.{extension}") if basename == '' else os.path.join(path, f"{basename}-{file_decoration}.{extension}") else: forced_filename += suffix if suffix is not None else '' + if forced_filename.startswith(basename): + basename = '' filename = os.path.join(path, f"{forced_filename}.{extension}") if basename == '' else os.path.join(path, f"{basename}-{forced_filename}.{extension}") pnginfo = existing_info or {} if info is None: diff --git a/modules/images_namegen.py b/modules/images_namegen.py index 4aa245c56..ea6914102 100644 --- a/modules/images_namegen.py +++ b/modules/images_namegen.py @@ -176,16 +176,16 @@ class FilenameGenerator: debug(f'Filename sanitize: input="{filename}" parts={parts} output="{fn}" ext={ext} max={max_length} len={len(fn)}') return fn - def sequence(self, x, dirname, basename): - if shared.opts.save_images_add_number or '[seq]' in x: - if '[seq]' not in x: - x = os.path.join(os.path.dirname(x), f"[seq]-{os.path.basename(x)}") + def sequence(self, fn, dirname, basename): + if shared.opts.save_images_add_number or '[seq]' in fn: + if '[seq]' not in fn: + fn = os.path.join(os.path.dirname(fn), f"[seq]-{os.path.basename(fn)}") basecount = get_next_sequence_number(dirname, basename) for i in range(9999): - seq = f"{basecount + i:05}" if basename == '' else f"{basename}-{basecount + i:04}" - filename = x.replace('[seq]', seq) + seq = f"{basecount + i:05}" + filename = fn.replace('[seq]', seq) if not os.path.exists(filename): - debug(f'Prompt sequence: input="{x}" seq={seq} output="{filename}"') + debug(f'Prompt sequence: input="{fn}" seq={seq} output="{filename}"') x = filename break return x diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index aa99c21cf..18906916d 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -328,7 +328,10 @@ class Script(scripts.Script): grid_count = z_count + ( 1 if not no_grid and z_count > 1 else 0 ) for g in range(grid_count): adj_g = g-1 if g > 0 else g - images.save_image(processed.images[g], p.outpath_grids, "xyz_grid", info=processed.infotexts[g], extension=shared.opts.grid_format, prompt=processed.all_prompts[adj_g], seed=processed.all_seeds[adj_g], grid=True, p=processed) + info = processed.infotexts[g] + prompt = processed.all_prompts[adj_g] + seed = processed.all_seeds[adj_g] + images.save_image(processed.images[g], p.outpath_grids, "grid", info=info, extension=shared.opts.grid_format, prompt=prompt, seed=seed, grid=True, p=processed) if not include_sub_grids: # Done with sub-grids, drop all related information: for _sg in range(z_count): del processed.images[1] diff --git a/scripts/xyz_grid_classes.py b/scripts/xyz_grid_classes.py index af79f58a5..8b06b73fa 100644 --- a/scripts/xyz_grid_classes.py +++ b/scripts/xyz_grid_classes.py @@ -1,4 +1,4 @@ -from scripts.xyz_grid_shared import apply_field, apply_task_args, apply_setting, apply_prompt, apply_order, apply_sampler, apply_hr_sampler_name, confirm_samplers, apply_checkpoint, apply_refiner, apply_unet, apply_dict, apply_clip_skip, apply_vae, list_lora, apply_lora, apply_te, apply_styles, apply_upscaler, apply_context, apply_face_restore, apply_override, apply_processing, format_value_add_label, format_value, format_value_join_list, do_nothing, format_nothing, str_permutations # pylint: disable=no-name-in-module +from scripts.xyz_grid_shared import apply_field, apply_task_args, apply_setting, apply_prompt, apply_order, apply_sampler, apply_hr_sampler_name, confirm_samplers, apply_checkpoint, apply_refiner, apply_unet, apply_dict, apply_clip_skip, apply_vae, list_lora, apply_lora, apply_te, apply_styles, apply_upscaler, apply_context, apply_face_restore, apply_override, apply_processing, apply_seed, format_value_add_label, format_value, format_value_join_list, do_nothing, format_nothing, str_permutations # pylint: disable=no-name-in-module from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet @@ -93,7 +93,7 @@ axis_options = [ AxisOption("[Network] Styles", str, apply_styles, choices=lambda: [s.name for s in shared.prompt_styles.styles.values()]), AxisOption("[Param] Width", int, apply_field("width")), AxisOption("[Param] Height", int, apply_field("height")), - AxisOption("[Param] Seed", int, apply_field("seed")), + AxisOption("[Param] Seed", int, apply_seed), AxisOption("[Param] Steps", int, apply_field("steps")), AxisOption("[Param] CFG scale", float, apply_field("cfg_scale")), AxisOption("[Param] Guidance end", float, apply_field("cfg_end")), diff --git a/scripts/xyz_grid_draw.py b/scripts/xyz_grid_draw.py index 264c68c97..c56c50b4a 100644 --- a/scripts/xyz_grid_draw.py +++ b/scripts/xyz_grid_draw.py @@ -84,9 +84,8 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend return processing.Processed(p, []) t1 = time.time() - z_count = len(zs) grid = None - for i in range(z_count): + for i in range(len(zs)): start_index = (i * len(xs) * len(ys)) + i end_index = start_index + len(xs) * len(ys) to_process = processed_result.images[start_index:end_index] diff --git a/scripts/xyz_grid_on.py b/scripts/xyz_grid_on.py index d20dff945..e58c1e15f 100644 --- a/scripts/xyz_grid_on.py +++ b/scripts/xyz_grid_on.py @@ -335,15 +335,20 @@ class Script(scripts.Script): z_count = len(zs) processed.infotexts[:1+z_count] = grid_infotext[:1+z_count] # Set the grid infotexts to the real ones with extra_generation_params (1 main grid + z_count sub-grids) if not include_lone_images: + # TODO broken logic to delete sub-images if no_grid and include_sub_grids: processed.images = processed.images[:z_count] # we don't have the main grid image, and need zero additional sub-images else: processed.images = processed.images[:z_count+1] # we either have the main grid image, or need one sub-images if shared.opts.grid_save: # Auto-save main and sub-grids: - grid_count = z_count + ( 1 if not no_grid and z_count > 1 else 0 ) + grid_count = z_count + (1 if not no_grid and z_count > 1 else 0) for g in range(grid_count): adj_g = g-1 if g > 0 else g - images.save_image(processed.images[g], p.outpath_grids, "xyz_grid", info=processed.infotexts[g], extension=shared.opts.grid_format, prompt=processed.all_prompts[adj_g], seed=processed.all_seeds[adj_g], grid=True, p=processed) + info = processed.infotexts[g] + prompt = processed.all_prompts[adj_g] + seed = processed.all_seeds[adj_g] + _fn, _txt, _exif = images.save_image(processed.images[g], p.outpath_grids, "grid", info=info, extension=shared.opts.grid_format, prompt=prompt, seed=seed, grid=True, p=processed) + # TODO broken logic to delete sub-grids if not include_sub_grids: # Done with sub-grids, drop all related information: for _sg in range(z_count): del processed.images[1] @@ -354,6 +359,7 @@ class Script(scripts.Script): del processed.infotexts[0] active = False cache = processed + # TODO main processing loop auto-creates grid out of all returned images so we end up with grid of grids + images which we don't need, need to skip that return processed def process_images(self, p, enabled, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, no_grid, include_lone_images, include_sub_grids, margin_size): # pylint: disable=W0221, W0613 diff --git a/scripts/xyz_grid_shared.py b/scripts/xyz_grid_shared.py index 8f3019f73..972e1d2a4 100644 --- a/scripts/xyz_grid_shared.py +++ b/scripts/xyz_grid_shared.py @@ -45,6 +45,12 @@ def apply_setting(field): return fun +def apply_seed(p, x, xs): + p.seed = x + p.all_seeds = None + shared.log.debug(f'XYZ grid apply seed: {x}') + + def apply_prompt(p, x, xs): if xs[0] not in p.prompt and xs[0] not in p.negative_prompt: shared.log.warning(f"XYZ grid: prompt S/R did not find {xs[0]} in prompt or negative prompt.")