diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e6188de..5564f2291 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,7 +91,8 @@ Plus tons of minor items and fixes - see [changelog](https://github.com/vladmand ui result is always 8bit/channel hdr-effect image plus grid of original images used to create hdr grid image can be disabled via settings -> user interface -> show grid actual full-hdr image is not displayed in ui, only optionally saved to disk -- **hires** workflow now allows for full resize options, not just limited width/height/scale +- **hires** workflow now allows for full resize options + not just limited width/height/scale - **taesd** configurable number of layers can be used to speed-up taesd decoding by reducing number of ops e.g. if generating 1024px image, reducing layers by 1 will result in preview being 512px @@ -114,6 +115,7 @@ Plus tons of minor items and fixes - see [changelog](https://github.com/vladmand - fix handling of model configs if offline config is not available - fix vae decode in backend original - fix model path typos +- fix guidance end handler ## Update for 2024-08-31 diff --git a/extensions-builtin/sdnext-modernui b/extensions-builtin/sdnext-modernui index 6119f62df..62a01fd49 160000 --- a/extensions-builtin/sdnext-modernui +++ b/extensions-builtin/sdnext-modernui @@ -1 +1 @@ -Subproject commit 6119f62dffc2d7caea6eade6333cf9021985f3f8 +Subproject commit 62a01fd490082a1c444dedb080f706d64b448da3 diff --git a/modules/images.py b/modules/images.py index 4f42f276e..c777a07d9 100644 --- a/modules/images.py +++ b/modules/images.py @@ -320,7 +320,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type t0 = time.time() if resize_mode is None: resize_mode = 0 - if resize_mode == 0 or (im.width == width and im.height == height): # none + if resize_mode == 0 or (im.width == width and im.height == height) or (width == 0 and height == 0): # none res = im.copy() elif resize_mode == 1: # fixed res = resize(im, width, height) @@ -338,7 +338,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type res = im.copy() shared.log.error(f'Invalid resize mode: {resize_mode}') t1 = time.time() - shared.log.debug(f'Image resize: input={im} width={width} height={height} mode="{shared.resize_modes[resize_mode]}" upscaler="{upscaler_name}" context="{context}" type={output_type} result={res} time={t1-t0:.2f} fn={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access + shared.log.debug(f'Image resize: input={im} width={width} height={height} mode="{shared.resize_modes[resize_mode]}" upscaler="{upscaler_name}" context="{context}" type={output_type} result={res} time={t1-t0:.2f} fn={sys._getframe(1).f_code.co_filename}:{sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access return np.array(res) if output_type == 'np' else res diff --git a/modules/img2img.py b/modules/img2img.py index e2ec2837e..4bf057d4a 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -235,6 +235,7 @@ def img2img(id_task: str, mode: int, resize_mode=resize_mode, resize_name=resize_name, resize_context=resize_context, + scale_by=scale_by, denoising_strength=denoising_strength, image_cfg_scale=image_cfg_scale, diffusers_guidance_rescale=diffusers_guidance_rescale, @@ -248,8 +249,6 @@ def img2img(id_task: str, mode: int, hdr_boundary=hdr_boundary, hdr_threshold=hdr_threshold, hdr_maximize=hdr_maximize, hdr_max_center=hdr_max_center, hdr_max_boundry=hdr_max_boundry, hdr_color_picker=hdr_color_picker, hdr_tint_ratio=hdr_tint_ratio, override_settings=override_settings, ) - if selected_scale_tab == 1 and resize_mode != 0: - p.scale_by = scale_by p.scripts = modules.scripts.scripts_img2img p.script_args = args if mask: diff --git a/modules/processing_callbacks.py b/modules/processing_callbacks.py index 8446c5c68..7f2d86242 100644 --- a/modules/processing_callbacks.py +++ b/modules/processing_callbacks.py @@ -81,7 +81,8 @@ def diffusers_callback(pipe, step: int, timestep: int, kwargs: dict): else: pipe._guidance_scale = 0.0 # pylint: disable=protected-access for key in {"prompt_embeds", "negative_prompt_embeds", "add_text_embeds", "add_time_ids"} & set(kwargs): - kwargs[key] = kwargs[key].chunk(2)[-1] + if kwargs[key] is not None: + kwargs[key] = kwargs[key].chunk(2)[-1] try: if hasattr(pipe, "_unpack_latents") and hasattr(pipe, "vae_scale_factor"): # FLUX if p.hr_resize_mode > 0 and (p.hr_upscaler != 'None' or p.hr_resize_mode == 5): diff --git a/modules/processing_class.py b/modules/processing_class.py index fb3b5d73f..7e4858d16 100644 --- a/modules/processing_class.py +++ b/modules/processing_class.py @@ -268,7 +268,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): self.is_hr_pass = True hypertile_set(self, hr=True) shared.state.job_count = 2 * self.n_iter - shared.log.debug(f'Init hires: upscaler="{self.hr_upscaler}" sampler="{self.hr_sampler_name}" resize={self.hr_resize_x}x{self.hr_resize_y} upscale={self.hr_upscale_to_x}x{self.hr_upscale_to_y}') + shared.log.debug(f'Init hires: upscaler="{self.hr_upscaler}" sampler="{self.hr_sampler_name}" resize={self.hr_resize_x}x{self.hr_resize_y} upscale={self.hr_upscale_to_x}x{self.hr_upscale_to_y}') def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts): from modules import processing_original @@ -313,6 +313,11 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.script_args = [] def init(self, all_prompts=None, all_seeds=None, all_subseeds=None): + if self.init_images is not None and len(self.init_images) > 0: + if self.width is None or self.width == 0: + self.width = int(8 * (self.init_images[0].width * self.scale_by // 8)) + if self.height is None or self.height == 0: + self.height = int(8 * (self.init_images[0].height * self.scale_by // 8)) if shared.native and getattr(self, 'image_mask', None) is not None: shared.sd_model = sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.INPAINTING) elif shared.native and getattr(self, 'init_images', None) is not None: @@ -392,8 +397,6 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): if shared.opts.save_init_img: images.save_image(img, path=shared.opts.outdir_init_images, basename=None, forced_filename=self.init_img_hash, suffix="-init-image") image = images.flatten(img, shared.opts.img2img_background_color) - if self.width is None or self.height is None: - self.width, self.height = image.width, image.height if crop_region is None and self.resize_mode > 0: image = images.resize_image(self.resize_mode, image, self.width, self.height, upscaler_name=self.resize_name, context=self.resize_context) self.width = image.width @@ -511,7 +514,6 @@ class StableDiffusionProcessingControl(StableDiffusionProcessingImg2Img): self.is_hr_pass = True self.hr_force = force self.hr_upscaler = upscaler - use_scale = self.hr_resize_x == 0 or self.hr_resize_y == 0 if use_scale: self.hr_upscale_to_x, self.hr_upscale_to_y = 8 * int(self.width * scale / 8), 8 * int(self.height * scale / 8) else: diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index e0a6a65ca..46a2da06e 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -119,7 +119,7 @@ def create_ui(): with gr.Accordion(open=False, label="Sampler", elem_classes=["small-accordion"], elem_id="img2img_sampler_group"): steps, sampler_index = ui_sections.create_sampler_and_steps_selection(None, "img2img") ui_sections.create_sampler_options('img2img') - resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab = ui_sections.create_resize_inputs('img2img', [init_img, sketch], latent=True) + resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab = ui_sections.create_resize_inputs('img2img', [init_img, sketch], latent=True, non_zero=False) batch_count, batch_size = ui_sections.create_batch_inputs('img2img', accordion=True) seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('img2img') diff --git a/modules/ui_sections.py b/modules/ui_sections.py index 245925785..4bd8c0b40 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -330,15 +330,15 @@ def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=Tru with gr.Row(): with gr.Column(elem_id=f"{tab}_column_size_fixed"): with gr.Row(): - width = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label="Width" if non_zero else "Resize width", value=1024 if non_zero else 0, elem_id=f"{tab}_width") - height = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label="Height" if non_zero else "Resize height", value=1024 if non_zero else 0, elem_id=f"{tab}_height") + width = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label="Width" if non_zero else "Resize width", value=1024 if non_zero else 0, elem_id=f"{tab}_resize_width") + height = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label="Height" if non_zero else "Resize height", value=1024 if non_zero else 0, elem_id=f"{tab}_resize_height") ar_list = ['AR'] + [x.strip() for x in shared.opts.aspect_ratios.split(',') if x.strip() != ''] - ar_dropdown = gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_ar", elem_classes=["ar-dropdown"]) + ar_dropdown = gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_resize_ar", elem_classes=["ar-dropdown"]) for c in [ar_dropdown, width, height]: c.change(fn=ar_change, inputs=[ar_dropdown, width, height], outputs=[width, height], show_progress=False) - res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_res_switch_btn") + res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_resize_switch_size_btn") res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False) - detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_detect_image_size_btn") + detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_resize_detect_size_btn") el = tab.split('_')[0] detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js=f'currentImageResolution{el}', inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress=False) with gr.Tab(label="Scale", id=1, elem_id=f"{tab}_scale_tab_scale") as tab_scale_by: diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index fd92407ce..2800a3722 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -18,18 +18,21 @@ import modules.ui_symbols as symbols def apply_field(field): def fun(p, x, xs): + shared.log.debug(f'XYZ grid apply field: {field}={x}') setattr(p, field, x) return fun def apply_task_args(field): def fun(p, x, xs): + shared.log.debug(f'XYZ grid apply task-arg: {field}={x}') p.task_args[field] = x return fun def apply_setting(field): def fun(p, x, xs): + shared.log.debug(f'XYZ grid apply setting: {field}={x}') shared.opts.data[field] = x return fun @@ -40,6 +43,7 @@ def apply_prompt(p, x, xs): else: p.prompt = p.prompt.replace(xs[0], x) p.negative_prompt = p.negative_prompt.replace(xs[0], x) + shared.log.debug(f'XYZ grid apply prompt: "{xs[0]}"="{x}"') def apply_order(p, x, xs): @@ -65,6 +69,7 @@ def apply_sampler(p, x, xs): shared.log.warning(f"XYZ grid: unknown sampler: {x}") else: p.sampler_name = sampler_name + shared.log.debug(f'XYZ grid apply sampler: "{x}"') def apply_hr_sampler_name(p, x, xs): @@ -73,6 +78,7 @@ def apply_hr_sampler_name(p, x, xs): shared.log.warning(f"XYZ grid: unknown sampler: {x}") else: p.hr_sampler_name = hr_sampler_name + shared.log.debug(f'XYZ grid apply HR sampler: "{x}"') def confirm_samplers(p, xs): @@ -90,6 +96,7 @@ def apply_checkpoint(p, x, xs): else: sd_models.reload_model_weights(shared.sd_model, info) p.override_settings['sd_model_checkpoint'] = info.name + shared.log.debug(f'XYZ grid apply checkpoint: "{x}"') def apply_refiner(p, x, xs): @@ -103,6 +110,7 @@ def apply_refiner(p, x, xs): else: sd_models.reload_model_weights(shared.sd_refiner, info) p.override_settings['sd_model_refiner'] = info.name + shared.log.debug(f'XYZ grid apply refiner: "{x}"') def apply_dict(p, x, xs): @@ -116,11 +124,13 @@ def apply_dict(p, x, xs): shared.opts.sd_model_dict = info_dict.name # this will trigger reload_model_weights via onchange handler p.override_settings['sd_model_checkpoint'] = info_ckpt.name p.override_settings['sd_model_dict'] = info_dict.name + shared.log.debug(f'XYZ grid apply model dict: "{x}"') def apply_clip_skip(p, x, xs): p.clip_skip = x shared.opts.data["clip_skip"] = x + shared.log.debug(f'XYZ grid apply clip-skip: "{x}"') def find_vae(name: str): @@ -139,6 +149,7 @@ def find_vae(name: str): def apply_vae(p, x, xs): sd_vae.reload_vae_weights(shared.sd_model, vae_file=find_vae(x)) + shared.log.debug(f'XYZ grid apply VAE: "{x}"') def list_lora(): @@ -153,15 +164,18 @@ def apply_lora(p, x, xs): return x = os.path.basename(x) p.prompt = p.prompt + f" " + shared.log.debug(f'XYZ grid apply LoRA: "{x}"') def apply_te(p, x, xs): shared.opts.data["sd_text_encoder"] = x sd_models.reload_text_encoder() + shared.log.debug(f'XYZ grid apply text-encoder: "{x}"') def apply_styles(p: processing.StableDiffusionProcessingTxt2Img, x: str, _): p.styles.extend(x.split(',')) + shared.log.debug(f'XYZ grid apply style: "{x}"') def apply_upscaler(p: processing.StableDiffusionProcessingTxt2Img, opt, x): @@ -169,11 +183,14 @@ def apply_upscaler(p: processing.StableDiffusionProcessingTxt2Img, opt, x): p.hr_force = True p.denoising_strength = 0.0 p.hr_upscaler = opt + shared.log.debug(f'XYZ grid apply upscaler: "{x}"') def apply_context(p: processing.StableDiffusionProcessingTxt2Img, opt, x): p.resize_mode = 5 p.resize_context = opt + shared.log.debug(f'XYZ grid apply resize-context: "{x}"') + def apply_face_restore(p, opt, x): opt = opt.lower() @@ -186,11 +203,13 @@ def apply_face_restore(p, opt, x): else: is_active = opt in ('true', 'yes', 'y', '1') p.restore_faces = is_active + shared.log.debug(f'XYZ grid apply face-restore: "{x}"') def apply_override(field): def fun(p, x, xs): p.override_settings[field] = x + shared.log.debug(f'XYZ grid apply override: "{field}"="{x}"') return fun