fix: update version to 1.1.3 and add make_civitai_safe_text function for punctuation normalization

This commit is contained in:
LuqP2
2026-06-16 19:29:46 -03:00
parent a0b6b9cf7d
commit 00ace2ae4e
4 changed files with 70 additions and 10 deletions
+2 -2
View File
@@ -3,7 +3,7 @@ Compatibility shim for MetaHub Save Node metadata helpers.
The implementation is kept in metadata_utils_impl.py; this module exposes the
same public API expected by the save nodes while pinning the published node
version to 1.1.2.
version to 1.1.3.
"""
try:
@@ -11,7 +11,7 @@ try:
except ImportError:
import metadata_utils_impl as _impl
METAHUB_SAVE_NODE_VERSION = "1.1.2"
METAHUB_SAVE_NODE_VERSION = "1.1.3"
_impl.METAHUB_SAVE_NODE_VERSION = METAHUB_SAVE_NODE_VERSION
for _name in dir(_impl):
+29 -6
View File
@@ -14,7 +14,7 @@ from xml.sax.saxutils import escape as xml_escape
import numpy as np
from PIL import Image, PngImagePlugin
METAHUB_SAVE_NODE_VERSION = "1.0.9"
METAHUB_SAVE_NODE_VERSION = "1.1.3"
try:
import piexif
@@ -315,6 +315,28 @@ def collect_version_info() -> Dict[str, Optional[str]]:
# METADATA FORMATTING
# ============================================================================
def make_civitai_safe_text(value: str) -> str:
"""
Normalizes common smart punctuation for legacy A1111/Civitai text readers.
"""
if value is None:
return ""
replacements = {
"\u2018": "'",
"\u2019": "'",
"\u201c": '"',
"\u201d": '"',
"\u2013": "-",
"\u2014": "-",
"\u2026": "...",
"\u00a0": " ",
}
text = str(value)
for source, replacement in replacements.items():
text = text.replace(source, replacement)
return text
def build_a1111_metadata(params: dict) -> str:
"""
Builds A1111/Civitai compatible metadata string for tEXt chunk.
@@ -836,7 +858,7 @@ def save_png_with_metadata(image: Image.Image, image_path: str, a1111_metadata:
"""
try:
png_info = PngImagePlugin.PngInfo()
png_info.add_text("parameters", a1111_metadata or "")
png_info.add_text("parameters", make_civitai_safe_text(a1111_metadata))
imh_json = json.dumps(imh_metadata or {}, ensure_ascii=False)
png_info.add_itxt("imagemetahub_data", imh_json)
workflow_text = _serialize_metadata_json_ascii(imh_metadata.get("workflow"))
@@ -861,9 +883,10 @@ def _build_exif_bytes(a1111_metadata: str, imh_metadata: dict) -> Optional[bytes
imh_json = json.dumps(imh_metadata or {}, ensure_ascii=False)
if imh_json:
exif_dict["0th"][piexif.ImageIFD.ImageDescription] = imh_json.encode("utf-8", errors="replace")
if a1111_metadata:
civitai_metadata = make_civitai_safe_text(a1111_metadata)
if civitai_metadata:
exif_dict["Exif"][piexif.ExifIFD.UserComment] = piexif_helper.UserComment.dump(
a1111_metadata, encoding="unicode"
civitai_metadata, encoding="unicode"
)
return piexif.dump(exif_dict)
except Exception:
@@ -889,7 +912,7 @@ def save_jpeg_with_metadata(
if exif_bytes:
save_kwargs["exif"] = exif_bytes
elif a1111_metadata:
save_kwargs["comment"] = a1111_metadata.encode("utf-8", errors="replace")
save_kwargs["comment"] = make_civitai_safe_text(a1111_metadata).encode("utf-8", errors="replace")
if xmp_bytes:
save_kwargs["xmp"] = xmp_bytes
try:
@@ -922,7 +945,7 @@ def save_webp_with_metadata(
if exif_bytes:
save_kwargs["exif"] = exif_bytes
elif a1111_metadata:
save_kwargs["comment"] = a1111_metadata
save_kwargs["comment"] = make_civitai_safe_text(a1111_metadata)
if xmp_bytes:
save_kwargs["xmp"] = xmp_bytes
try:
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "imagemetahub-comfyui-save"
description = "Official companion node for Image MetaHub. Saves A1111/Civitai-compatible parameters plus extended Image MetaHub metadata (workflow JSON, SHA256 model hashes, VRAM peak/total, GPU device, generation time, and steps/sec) for reproducibility and benchmarking."
version = "1.1.2"
version = "1.1.3"
license = {file = "LICENSE"}
# classifiers = [
# # For OS-independent nodes (works on all operating systems)
+38 -1
View File
@@ -16,6 +16,7 @@ from metadata_utils import (
get_next_filename,
get_output_directory,
get_workflow_json,
make_civitai_safe_text,
resolve_filename_pattern_path,
save_png_with_metadata,
)
@@ -316,7 +317,7 @@ def test_extract_workflow_attribution_from_node_properties():
assert attribution["token"] == "imhcrt_br_creator_workflow_v1_random"
assert attribution["source"] == "metahub_save_node"
assert attribution["node_version"] == "1.0.9"
assert attribution["node_version"] == "1.1.3"
def test_build_imh_metadata_includes_attribution_without_a1111_parameters():
@@ -401,6 +402,42 @@ def test_build_a1111_metadata_formats_text():
assert "Model hash: abcdef1234" in text
def test_make_civitai_safe_text_normalizes_smart_punctuation():
text = "McDonald\u2019s \u201cquote\u201d \u2013 dash \u2014 dash\u2026space\u00a0here"
assert make_civitai_safe_text(text) == "McDonald's \"quote\" - dash - dash...space here"
def test_save_png_with_metadata_sanitizes_only_parameters_chunk(tmp_path):
imh_metadata = {
"prompt": "McDonald\u2019s \u201cquote\u201d",
"workflow": {"nodes": [{"title": "McDonald\u2019s \u201cquote\u201d"}]},
"prompt_api": {
"1": {
"class_type": "CLIPTextEncode",
"inputs": {"text": "McDonald\u2019s \u201cquote\u201d"},
}
},
}
image = Image.new("RGB", (2, 2), color=(0, 0, 0))
file_path = tmp_path / "civitai-safe.png"
save_png_with_metadata(
image,
str(file_path),
"McDonald\u2019s \u201cquote\u201d \u2013 dash\u2026",
imh_metadata,
)
loaded = Image.open(file_path)
text = getattr(loaded, "text", {})
assert text["parameters"] == "McDonald's \"quote\" - dash..."
assert json.loads(text["imagemetahub_data"])["prompt"] == "McDonald\u2019s \u201cquote\u201d"
assert json.loads(text["workflow"])["nodes"][0]["title"] == "McDonald\u2019s \u201cquote\u201d"
assert json.loads(text["prompt"])["1"]["inputs"]["text"] == "McDonald\u2019s \u201cquote\u201d"
def test_save_png_with_metadata_writes_workflow_prompt(tmp_path):
imh_metadata = {
"workflow": {"nodes": []},