mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-23 12:04:09 -03:00
fix: fall back to source image dimensions for missing width/height
When metadata extraction succeeds but no recognized latent source provides dimensions (e.g. img2img via VAEEncode), width/height now fall back to the source image size from the loaded pixels instead of the synthetic 1024x1024 starter preset. The starter preset for metadata-free images keeps its fixed size, and explicit overrides still win.
This commit is contained in:
@@ -75,7 +75,8 @@ prompt; UI-workflow-only subgraph definitions are not expanded or executed.
|
||||
|
||||
Extraction errors do not stop this node. If an API prompt uses unsupported
|
||||
samplers, the node first tries the image's saved generation parameters. Any
|
||||
remaining unavailable or invalid extracted fields use the SDXL starter defaults;
|
||||
remaining unavailable or invalid extracted fields use the SDXL starter defaults
|
||||
(width/height fall back to the source image dimensions instead);
|
||||
valid extracted fields are preserved. `readable_report` starts with **❌ ERROR**
|
||||
and explains each recovery or substitution. This also applies to existing nodes
|
||||
saved with `missing_settings=strict`; that legacy option no longer blocks
|
||||
@@ -147,6 +148,8 @@ when uniquely indexed; otherwise choose an SDXL checkpoint manually or supply
|
||||
original workflow for those cases.
|
||||
- Width/height come from a recognized latent source or fall back to source-image
|
||||
dimensions; resized/upscaled images can therefore need dimension overrides.
|
||||
Only the synthetic starter preset for metadata-free images uses a fixed
|
||||
1024×1024 regardless of the source image size.
|
||||
- VAE, text encoder choice, CLIP skip, ControlNet and architecture-specific
|
||||
conditioning still need the appropriate nodes. No embedded code is executed
|
||||
and no external metadata service is contacted.
|
||||
|
||||
@@ -253,8 +253,21 @@ class LoadImageMetadataLM:
|
||||
if "model" in extracted.issues and "model_name" not in overrides:
|
||||
values.pop("checkpoint_name", None)
|
||||
values.pop("unet_name", None)
|
||||
# Extraction without a recognized latent source (e.g. img2img) leaves
|
||||
# width/height unset; the source image dimensions are the best
|
||||
# estimate then. The synthetic starter preset keeps its fixed size.
|
||||
image_fallback = not no_metadata and "source" not in extracted.issues
|
||||
try:
|
||||
image_height, image_width = int(pixels.shape[1]), int(pixels.shape[2])
|
||||
except (AttributeError, IndexError, TypeError, ValueError):
|
||||
image_fallback = False
|
||||
for key, default in EMPTY_IMAGE_DEFAULTS.items():
|
||||
if key not in values:
|
||||
if key in values:
|
||||
continue
|
||||
if image_fallback and key in ("width", "height"):
|
||||
values[key] = image_width if key == "width" else image_height
|
||||
notes.append(f"WARNING Missing {key}; using source image dimension {values[key]}.")
|
||||
else:
|
||||
values[key] = default
|
||||
notes.append(f"ERROR: Missing {key}; using default {default!r}.")
|
||||
# Validate independently so one invalid value cannot erase the other
|
||||
|
||||
@@ -96,6 +96,44 @@ def test_no_metadata_can_be_inspected_with_defaults(runtime):
|
||||
assert "No model resolved" in result[15]
|
||||
|
||||
|
||||
def test_graph_without_recognized_latent_falls_back_to_image_size(runtime):
|
||||
info = PngImagePlugin.PngInfo()
|
||||
graph = {
|
||||
"1": {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": "base.safetensors"}},
|
||||
"2": {"class_type": "CLIPTextEncode", "inputs": {"text": "pos", "clip": ["1", 1]}},
|
||||
"3": {"class_type": "CLIPTextEncode", "inputs": {"text": "neg", "clip": ["1", 1]}},
|
||||
"5": {"class_type": "KSampler", "inputs": {
|
||||
"model": ["1", 0], "positive": ["2", 0], "negative": ["3", 0],
|
||||
"latent_image": ["9", 0], "seed": 1, "steps": 20, "cfg": 7,
|
||||
"sampler_name": "euler", "scheduler": "normal", "denoise": 1,
|
||||
}},
|
||||
"9": {"class_type": "VAEEncode", "inputs": {"pixels": ["10", 0], "vae": ["1", 2]}},
|
||||
}
|
||||
info.add_text("prompt", json.dumps(graph))
|
||||
Image.new("RGB", (16, 24)).save(runtime[0], pnginfo=info)
|
||||
# The mocked loader returns pixels with shape (1, 24, 16, 3): H=24, W=16.
|
||||
result = LoadImageMetadataLM().load_metadata("input.png")
|
||||
assert result[12:14] == (16, 24)
|
||||
assert "using source image dimension" in result[15]
|
||||
assert "❌ ERROR" not in result[16]
|
||||
|
||||
|
||||
def test_parameters_without_size_fall_back_to_image_size(runtime):
|
||||
info = PngImagePlugin.PngInfo()
|
||||
info.add_text("parameters", PARAMETERS.replace(", Size: 768x1024", ""))
|
||||
Image.new("RGB", (16, 24)).save(runtime[0], pnginfo=info)
|
||||
result = LoadImageMetadataLM().load_metadata("input.png")
|
||||
assert result[12:14] == (16, 24)
|
||||
|
||||
|
||||
def test_size_override_wins_over_image_size_fallback(runtime):
|
||||
info = PngImagePlugin.PngInfo()
|
||||
info.add_text("parameters", PARAMETERS.replace(", Size: 768x1024", ""))
|
||||
Image.new("RGB", (16, 24)).save(runtime[0], pnginfo=info)
|
||||
result = LoadImageMetadataLM().load_metadata("input.png", overrides_json='{"width": 512, "height": 640}')
|
||||
assert result[12:14] == (512, 640)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("override", [{"seed": -1}, {"steps": 2.5}, {"cfg": float("nan")}, {"sampler_name": "made_up"}, {"positive": ["1", 0]}, {"unknown": 1}])
|
||||
def test_invalid_override_rejected(runtime, override):
|
||||
with pytest.raises((MetadataError, ValueError)):
|
||||
|
||||
Reference in New Issue
Block a user