Add AVIF to Save Image Advanced#14975
Conversation
📝 WalkthroughWalkthroughAdds AVIF image output to 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@comfy_extras/nodes_images.py`:
- Around line 1131-1135: Update the AVIF capability check’s RuntimeError message
in the image-saving path to state only that saving AVIF images requires a Pillow
build with AVIF support. Remove the claim about official Pillow wheel versions
while preserving the existing check and exception behavior.
In `@tests-unit/comfy_extras_test/nodes_images_save_test.py`:
- Around line 18-32: Update the import setup around comfy_extras.nodes_images to
snapshot and restore both sys.modules["comfy_extras.nodes_images"] and the
corresponding comfy_extras package attribute, in addition to the mocked nodes
and server entries. Remove the target module before importing so the mocks are
applied consistently, then restore or remove all cached entries in the finally
block.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 836ffb06-f70b-440c-8dbb-9e5926d58ddd
📒 Files selected for processing (3)
comfy_extras/nodes_images.pyrequirements.txttests-unit/comfy_extras_test/nodes_images_save_test.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*
📄 CodeRabbit inference engine (AGENTS.md)
**/*: Keep changes small, direct, and limited to the narrowest code path and fewest files necessary; prefer practical fixes over broad architectural work.
Prefer fewer dependencies and do not add a ComfyUI dependency unless absolutely necessary.
Remove obsolete code, dead branches, unused options, debug prints, and unnecessary compatibility paths.
Preserve existing APIs, node names, model-loading behavior, file layout, and workflow compatibility unless replacement is explicit.
Keep architectural layers focused; do not leak UI, API, workflow, queue, persistence, telemetry, model-loading, node, or execution concerns into unrelated layers.
Shared core modules should depend only on lower-level primitives and their own domain concepts; higher-level concepts belong at callers, adapters, services, or boundaries.
Pass only the narrowest data needed across boundaries and keep identity mapping, persistence, history, telemetry, response shaping, and UI state in their owning layers.
Before touching many files, identify the smallest owner layer; use caller-side mappings, adapters, events, or narrow interfaces instead of exposing private concepts across layers.
Core ComfyUI code must not make unsolicited internet requests or add uploads, telemetry, analytics, tracking, reporting, update checks, remote configuration, licensing checks, or similar outbound paths.
Model downloading is allowed only when explicitly authorized by the user, limited to the requested artifact, and free of telemetry, tracking, unrelated metadata, or background activity.
Warning and info messages should be short and actionable; documentation and README changes should be concise, factual, and tied to changed behavior.
Use short direct commit subjects such asFix ...,Add ...,Support ...,Remove ..., orUpdate ...; keep PR descriptions short and state the problem, behavior change, and tests.
Prefer one coherent behavioral change per commit and prioritize crashes, incorrect dtype/device behavior, m...
Files:
requirements.txtcomfy_extras/nodes_images.pytests-unit/comfy_extras_test/nodes_images_save_test.py
**
⚙️ CodeRabbit configuration file
**: IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing awith:block),
treat it as unchanged. Contributors should not feel obligated to address
pre-existing issues outside the scope of their contribution.
Files:
requirements.txtcomfy_extras/nodes_images.pytests-unit/comfy_extras_test/nodes_images_save_test.py
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Keep state and capability flags on the object that owns the behavior; use explicit parent-owned fields rather than probing children withgetattrfor parent control flow.
Keep public methods aligned with caller contracts; preserve arguments, parameter order, return types, side effects, and error behavior unless all affected interfaces are intentionally updated.
Do not add unused compatibility parameters, flags, attributes, constructor options, or model-specific options to shared helpers.
Normalize third-party and upstream return conventions at integration boundaries so core code receives the expected type and shape.
Avoid caller-side unwrapping such asout = out[0]unless the called interface documents that return structure.
Do not addtorch.no_grad,torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients.
Do not add freeze, unfreeze, or trainability toggles to ComfyUI model classes.
Remove training-only behavior such as dropout from inference models while preserving checkpoint and state-dict compatibility, usingnn.Identitywhen necessary to retain slots.
Keep imports at module scope; use inline imports only for established optional-backend probes or import-cycle avoidance.
Usetry/exceptonly for optional dependency, platform, or backend detection with a useful fallback, and prefer specific exception types.
Do not add code for unsupported pinned library versions or obsolete PyTorch workarounds; unsupported formats, quantization metadata, and bad states should fail clearly.
Match local file style and keep comments sparse, useful, and non-obvious; remove comments that merely restate code.
Files:
comfy_extras/nodes_images.pytests-unit/comfy_extras_test/nodes_images_save_test.py
comfy_extras/**
⚙️ CodeRabbit configuration file
comfy_extras/**: Community-contributed extra nodes. Focus on:
- Consistency with node patterns (INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY)
- No breaking changes to existing node interfaces
Files:
comfy_extras/nodes_images.py
🧠 Learnings (7)
📚 Learning: 2026-02-24T06:20:53.084Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI PR: 12604
File: requirements.txt:0-0
Timestamp: 2026-02-24T06:20:53.084Z
Learning: When reviewing Python dependency files, do not flag or comment on whether a package version exists on PyPI. Treat versions in requirements.txt as valid and focus reviews on correctness of syntax, formatting, and usage rather than PyPI availability.
Applied to files:
requirements.txt
📚 Learning: 2026-02-21T14:01:41.482Z
Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI PR: 12555
File: comfy_extras/nodes_glsl.py:719-724
Timestamp: 2026-02-21T14:01:41.482Z
Learning: In PyOpenGL, bare Python scalars can be accepted for 1-element array parameters by NumberHandler. This means you can pass an int/float directly to OpenGL texture deletion (e.g., glDeleteTextures(tex)) without wrapping in a list. Verify function-specific expectations and ensure types match what the OpenGL call expects; use explicit lists only when the API requires an array.
Applied to files:
comfy_extras/nodes_images.pytests-unit/comfy_extras_test/nodes_images_save_test.py
📚 Learning: 2026-03-04T14:05:31.426Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI PR: 12757
File: comfy_extras/nodes_custom_sampler.py:1069-1089
Timestamp: 2026-03-04T14:05:31.426Z
Learning: In the ComfyUI sampling pipeline, treat percent_to_sigma(0.0) as a sentinel value (999999999.9) that means starting from pure noise. This is consistent with BasicScheduler via calculate_sigmas. The SamplingPercentToSigma node’s return_actual_sigma flag differentiates this sentinel from sigma_max. Reviewers should not flag CurveToSigmas or similar nodes that rely on percent_to_sigma as bugs; downstream samplers are expected to handle the sentinel correctly. When reviewing related sampling-related code, assume this sentinel semantics unless there is explicit handling for a real sigma_max.
Applied to files:
comfy_extras/nodes_images.py
📚 Learning: 2026-04-04T13:29:15.653Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13258
File: comfy_extras/nodes_frame_interpolation.py:151-189
Timestamp: 2026-04-04T13:29:15.653Z
Learning: In this ComfyUI codebase, node `execute()` inference is already run under a global `torch.inference_mode()` context established in the execution engine (e.g., `execution.py` around line ~732). During review, avoid recommending changes that wrap node inference loops in `torch.inference_mode()`—it is already applied, so such suggestions are likely redundant.
Applied to files:
comfy_extras/nodes_images.py
📚 Learning: 2026-05-09T18:40:40.199Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13813
File: comfy_extras/nodes_wandancer.py:868-872
Timestamp: 2026-05-09T18:40:40.199Z
Learning: When building video/temporal decoding nodes that call ComfyUI’s VAE.decode (comfy/sd.py), leverage VAE.decode’s existing VRAM-aware chunking along dim 0. Reshape or transpose the latent so the temporal dimension T is folded into dim 0 (e.g., transform a latent of shape [B, T, C, H, W] into [B*T, C, H, W] before calling vae.decode). This lets VAE.decode do chunked decoding without needing an explicit per-frame loop inside the node itself.
Applied to files:
comfy_extras/nodes_images.py
📚 Learning: 2026-05-20T00:10:14.673Z
Learnt from: Pauan
Repo: Comfy-Org/ComfyUI PR: 13997
File: comfy_extras/nodes_string.py:12-25
Timestamp: 2026-05-20T00:10:14.673Z
Learning: In the ComfyUI `comfy_extras/` codebase, some nodes intentionally ship with a default input string that references parameters that may not yet be connected. If the default would raise a `KeyError` (e.g., examples like `MathExpression` default `a + b`, or `StringFormat` default `{a}` with `min=0` and autogrow inputs), treat it as an intentional “hint default” UX pattern, not a bug. During review, do not flag this behavior or recommend changing `min` to `1` or altering the default to an empty string solely to avoid the `KeyError`.
Applied to files:
comfy_extras/nodes_images.py
📚 Learning: 2026-07-13T17:26:10.852Z
Learnt from: silveroxides
Repo: Comfy-Org/ComfyUI PR: 14922
File: tests-unit/comfy_extras_test/test_qwen_visual_fusion.py:3-7
Timestamp: 2026-07-13T17:26:10.852Z
Learning: In Comfy unit tests that import CUDA-dependent modules (e.g., tests that need `comfy_extras/nodes_qwen.py`), set the global `cli_args.cpu = True` at module load time *before* importing `comfy_extras/nodes_qwen.py` when CUDA is unavailable. Do not rely on `pytest` fixtures or `monkeypatch` for this kind of import-time behavior, because fixtures run after the test module is imported/collected and the CUDA code would already execute. The goal is to prevent import-time CUDA initialization and keep the tests runnable in CPU-only environments.
Applied to files:
tests-unit/comfy_extras_test/nodes_images_save_test.py
🪛 ast-grep (0.44.1)
comfy_extras/nodes_images.py
[info] 956-956: use jsonify instead of json.dumps for JSON output
Context: json.dumps(prompt)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[info] 960-960: use jsonify instead of json.dumps for JSON output
Context: json.dumps(workflow)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
tests-unit/comfy_extras_test/nodes_images_save_test.py
[warning] 35-35: Do not make http calls without encryption
Context: "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.
(requests-http)
[info] 74-76: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
prompt
)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[info] 77-77: use jsonify instead of json.dumps for JSON output
Context: json.dumps(workflow)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[warning] 69-69: XPath query is request-/variable-derived; use parameterized XPath to prevent injection.
Context: root.find(f".//{{{RDF_NAMESPACE}}}Description")
Note: [CWE-643] Improper Neutralization of Data within XPath Expressions ('XPath Injection').
(xpath-injection-python)
[warning] 70-70: XPath query is request-/variable-derived; use parameterized XPath to prevent injection.
Context: root.find(f".//{{{COMFYUI_XMP_NAMESPACE}}}workflow")
Note: [CWE-643] Improper Neutralization of Data within XPath Expressions ('XPath Injection').
(xpath-injection-python)
🪛 OSV Scanner (2.4.0)
requirements.txt
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-165)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2249)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2250)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2251)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2252)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2253)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2254)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2255)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2256)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-2257)
[HIGH] 17-17: pillow 11.3.0: Pillow has a PDF Parsing Trailer Infinite Loop (DoS)
(PYSEC-2026-2874)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-3451)
[HIGH] 17-17: pillow 11.3.0: undefined
(PYSEC-2026-3453)
[HIGH] 17-17: pillow 11.3.0: Pillow has a heap buffer overflow with nested list coordinates
[HIGH] 17-17: pillow 11.3.0: Pillow affected by out-of-bounds write when loading PSD images
[HIGH] 17-17: pillow 11.3.0: Pillow has an OOB Write with Invalid PSD Tile Extents (Integer Overflow)
[HIGH] 17-17: pillow 11.3.0: Pillow has a PDF Parsing Trailer Infinite Loop (DoS)
[HIGH] 17-17: pillow 11.3.0: FITS GZIP decompression bomb in Pillow
[HIGH] 17-17: pillow 11.3.0: Pillow has an integer overflow when processing fonts
🔇 Additional comments (3)
comfy_extras/nodes_images.py (1)
17-20: LGTM!Also applies to: 914-914, 949-977, 1124-1130, 1136-1161, 1269-1277, 1290-1290, 1303-1310
requirements.txt (1)
17-17: LGTM!tests-unit/comfy_extras_test/nodes_images_save_test.py (1)
1-17: LGTM!Also applies to: 35-180
Use the canonical ComfyUI XMP namespace emitted by the Save Image (Advanced) AVIF writer in Comfy-Org/ComfyUI#14975. The reader matches by local name, so parsing behavior is unchanged.
|
The only dependency change here bumps the Pillow requirement to
Existing behavior is untouched: PNG and EXR save exactly as before, with AVIF as an added option alongside them. Nothing needs installing at the system level either, since the codecs ship inside the wheels. On the few wheels that don't include AVIF (Windows ARM64, iOS), selecting AVIF raises a clear "needs a Pillow build with AVIF support" and every other format keeps working. Python support is unaffected, since 11.3.0 sits inside ComfyUI's Pillow is also the only encoder in the stack that preserves the workflow metadata. PyAV is already bundled, but it drops the XMP packet entirely, so there's no metadata-safe AVIF path without Pillow's AVIF wheels. Any CVEs a scanner shows against 11.3.0 are later issues already fixed upstream. Because this is a |
59e72d9 to
f2aa3b7
Compare
Adds 8-bit AVIF output to Save Image (Advanced) using Pillow's existing libavif-backed encoder. The legacy Save Image node remains unchanged.
Related to .avif image format support. Complements the frontend AVIF XMP importer.
Prompt and workflow metadata are stored in a standard
application/rdf+xmlXMP item. The Pillow floor is raised to 11.3.0, which adds AVIF support to official wheels on supported platforms.Validation:
ruff check .python -m pytest -q tests-unit/comfy_extras_test/nodes_images_save_test.py tests-unit/comfy_extras_test/image_stitch_test.py tests-unit/comfy_api_test/multicombo_serialization_test.py tests-unit/execution_test/test_enrich_output.py(49 passed)