mcpField
C
comfyui-node-datatypes

comfyui-node-datatypes

github.com/jtydhr88开发308115 次安装2 周前更新
代码仓库

关于 comfyui-node-datatypes

ComfyUI 节点数据类型参考,面向开发自定义节点的开发者,说明张量、模型、3D 文件及界面控件的数据结构。

主要功能

  1. 01图像、遮罩与潜空间格式
  2. 02音频、视频及条件数据结构
  3. 03模型与 3D 类型参考
  4. 04节点界面控件类型
  5. 05特殊与动态类型说明

适用场景

  1. 01检查节点输入输出的数据格式
  2. 02处理 ComfyUI 图像或视频数据
  3. 03构建自定义节点的类型定义

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jtydhr88/comfyui-custom-node-skills --skill comfyui-node-datatypes

安装后在 Claude Code 中输入/comfyui-node-datatypes确认已加载。

详细介绍

ComfyUI 数据类型

ComfyUI 为节点输入和输出使用特定的数据类型。理解张量形状和数据格式至关重要。

完整类型参考

张量/数据类型
类型V3 类格式描述
IMAGEio.Imagetorch.Tensor [B,H,W,C] float32 0-1RGB 图像批次
MASKio.Masktorch.Tensor [H,W] 或 [B,H,W] float32 0-1灰度蒙版
LATENTio.Latent{"samples": Tensor[B,C,H,W] or [B,C,T,H,W], "noise_mask"?: Tensor, "batch_index"?: list[int], "type"?: str}潜空间(4D 图像 / 5D 视频)
CONDITIONINGio.Conditioninglist[tuple[Tensor, PooledDict]]包含池化输出的文本条件
AUDIOio.Audio{"waveform": Tensor[B,C,T], "sample_rate": int}音频数据
VIDEOio.VideoVideoInput ABC视频数据(抽象基类)
SIGMASio.Sigmastorch.Tensor 1D,长度为 steps+1噪声调度
NOISEio.Noise具有 generate_noise() 的对象噪声生成器
LORA_MODELio.LoraModeldict[str, torch.Tensor]LoRA 权重增量
LOSS_MAPio.LossMap{"loss": list[torch.Tensor]}损失映射
TRACKSio.Tracks{"track_path": Tensor, "track_visibility": Tensor}运动跟踪数据
WAN_CAMERA_EMBEDDINGio.WanCameraEmbeddingtorch.TensorWAN 摄像头嵌入
LATENT_OPERATIONio.LatentOperationCallable[[Tensor], Tensor]潜变量变换函数
TIMESTEPS_RANGEio.TimestepsRangetuple[int, int]0.0-1.0 范围
DICTio.Dictdict通用字典
ARRAYio.Arraylist通用列表/数组
LAYERSio.Layers{"version": int, "canvas"?: (w, h), "layers": list[LayerItem]}图层堆栈(v0.31+);LayerItem:image 张量、type: "raster"、z_index,以及可选的 x、y、mask、name、opacity、blend_mode(io.Layers.BlendMode)、visible、flip_h/v、rotation、w、h
模型类型(不透明,通常直接传递)
类型V3 类Python 类型
MODELio.ModelModelPatcher
CLIPio.ClipCLIP
VAEio.VaeVAE
CONTROL_NETio.ControlNetControlNet
CLIP_VISIONio.ClipVisionClipVisionModel
CLIP_VISION_OUTPUTio.ClipVisionOutputClipVisionOutput
STYLE_MODELio.StyleModelStyleModel
GLIGENio.GligenModelPatcher(封装 Gligen)
UPSCALE_MODELio.UpscaleModelImageModelDescriptor
BACKGROUND_REMOVALio.BackgroundRemovalBackgroundRemovalModel(例如 BiRefNet)
LATENT_UPSCALE_MODELio.LatentUpscaleModelAny
SAMPLERio.SamplerSampler
GUIDERio.GuiderCFGGuider
HOOKSio.HooksHookGroup
HOOK_KEYFRAMESio.HookKeyframesHookKeyframeGroup
MODEL_PATCHio.ModelPatchAny
AUDIO_ENCODERio.AudioEncoderAny
AUDIO_ENCODER_OUTPUTio.AudioEncoderOutputAny
PHOTOMAKERio.PhotomakerAny
POINTio.PointAny
FACE_ANALYSISio.FaceAnalysisAny
BBOXio.BBOXAny
SEGSio.SEGSAny
3D 类型
类型V3 类Python 类型描述
MESHio.MeshMESH(vertices, faces)包含顶点和面张量的 3D 网格
VOXELio.VoxelVOXEL(data)体素数据张量
SPLATio.SplatSPLAT高斯泼溅数据
FILE_3Dio.File3DAnyFile3D任意受支持的 3D 格式
FILE_3D_GLBio.File3DGLBFile3D二进制 glTF
FILE_3D_GLTFio.File3DGLTFFile3D基于 JSON 的 glTF
FILE_3D_FBXio.File3DFBXFile3DFBX 格式
FILE_3D_OBJio.File3DOBJFile3DOBJ 格式
FILE_3D_STLio.File3DSTLFile3DSTL 格式(用于 3D 打印)
FILE_3D_USDZio.File3DUSDZFile3DApple AR 格式
FILE_3D_PLYio.File3DPLYFile3DPLY(点云/泼溅)
FILE_3D_SPLATio.File3DSPLATFile3D.splat 高斯泼溅文件
FILE_3D_SPZio.File3DSPZFile3D压缩泼溅(.spz)
FILE_3D_KSPLATio.File3DKSPLATFile3D.ksplat 格式
FILE_3D_SPLAT_ANYio.File3DSplatAnyFile3D任意泼溅格式
FILE_3D_POINT_CLOUD_ANYio.File3DPointCloudAnyFile3D任意点云格式
SVGio.SVGSVG可缩放矢量图形
LOAD_3Dio.Load3DModel3DDict(见下文)带渲染结果的 3D 模型
LOAD_3D_ANIMATIONio.Load3DAnimation与 Load3D 相同动画 3D 模型
LOAD3D_CAMERAio.Load3DCameraCameraInfo(见下文)3D 相机信息
LOAD3D_MODEL_INFOio.Load3DModelInfolist[Model3DTransform]每个模型的变换(位置/四元数/缩放)

Load3D.Model3DDict:{"image": str, "mask": str, "normal": str, "camera_info": CameraInfo, "recording"?: str, "model_3d_info"?: list[Model3DTransform]}

Load3DCamera.CameraInfo(右手坐标系,Y 轴向上,相机朝 -Z 方向看):必需键为 position、target、zoom、cameraType('perspective' | 'orthographic');可选键为 quaternion(相机世界旋转)、useCustomUp(bool,v0.40+:使用四元数的上方向,而不是世界 +Y 方向)、fov(垂直视野角,单位为度,仅透视模式)、aspect、near、far、frustum(仅正交模式:{left, right, top, bottom})。

Load3DModelInfo.Model3DTransform:世界空间中的 {"position": dict, "quaternion": dict, "scale": dict}。

组件类型(创建 UI 控件)
类型V3 类Python 类型描述
INTio.Intint带最小值/最大值/步长的整数
FLOATio.Floatfloat带最小值/最大值/步长/舍入设置的浮点数
STRINGio.Stringstr文本(单行/多行)
BOOLEANio.Booleanbool带标签的切换开关
COMBOio.Combostr下拉选择
COMBO (multi)io.MultiCombolist[str]多选下拉菜单
COLORio.Colorstr (hex)颜色选择器,默认值为 #ffffff
COLORSio.Colorslist[str] (hex)调色板(颜色列表)
BOUNDING_BOXio.BoundingBox{"x": int, "y": int, "width": int, "height": int}矩形区域
BOUNDING_BOXESio.BoundingBoxeslist[{"x", "y", "width", "height", "metadata": dict}]多个带标签的区域
CURVEio.Curvelist[tuple[float, float]]样条曲线点
RANGEio.RangeRangeInput(最小值/最大值 + 可选中点)带渐变显示的色阶/范围编辑器
IMAGECOMPAREio.ImageComparedict图像比较控件
WEBCAMio.Webcamstr网络摄像头捕获控件
HISTOGRAMio.Histogramlist[int]直方图分箱计数
VIDEO_EDITio.VideoEdit{"trim"?: {start_time, duration}, "crop"?: {x, y, width, height}}视频修剪/裁剪编辑器(features=["trim","crop"])
RESOLUTION_PREVIEWio.ResolutionPreviewdict与其他控件按名称绑定的实时分辨率预览
COMPOSITORio.Compositordict (LayerState)图层编辑器状态,默认值为 {}
CAMERA_INFO_STATEio.CameraInfoStatedict相机编辑器状态(仅输入)
特殊类型
类型V3 类描述
* (ANY)io.AnyType匹配任意类型
COMFY_MULTITYPED_V3io.MultiType在一个输入上接受多个指定类型
COMFY_MATCHTYPE_V3io.MatchType在输入/输出之间进行通用类型匹配
COMFY_AUTOGROW_V3io.Autogrow动态增长的输入
COMFY_DYNAMICCOMBO_V3io.DynamicCombo可根据选项显示子输入的组合框
COMFY_DYNAMICSLOT_V3io.DynamicSlot连接后可显示子输入的连接槽(核心节点尚未使用)
COMFY_DYNAMICGROUP_V3(内部 _DynamicGroup)重复的控件行;未导出且不稳定 — 请勿使用(前端自 v1.57.0 起支持)
FLOW_CONTROLio.FlowControl仅用于内部测试
ACCUMULATIONio.Accumulation仅用于内部测试

IMAGE 类型

图像是形状为 [B, H, W, C] 的 torch.Tensor:

  • B = 批次大小(单张图像为 1)
  • H = 像素高度
  • W = 像素宽度
  • C = 通道数(RGB 为 3,取值范围为 0.0-1.0)
import torch
import numpy as np
from PIL import Image as PILImage

class ImageProcessor(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="ImageProcessor",
            display_name="Image Processor",
            category="image",
            inputs=[io.Image.Input("image")],
            outputs=[io.Image.Output("IMAGE")],
        )

    @classmethod
    def execute(cls, image):
        b, h, w, c = image.shape
        result = torch.clamp(image * 1.5, 0.0, 1.0)
        return io.NodeOutput(result)
加载/保存图像
from PIL import ImageOps

# Load from file → tensor
def load_image(path):
    img = PILImage.open(path)
    img = ImageOps.exif_transpose(img)   # fix rotation from camera EXIF
    if img.mode == "I":                  # handle 16-bit images
        img = img.point(lambda i: i * (1 / 255))
    img = img.convert("RGB")
    return torch.from_numpy(np.array(img).astype(np.float32) / 255.0).unsqueeze(0)

# Tensor → save to file
def save_image(tensor, path):
    if tensor.dim() == 4:
        tensor = tensor[0]
    PILImage.fromarray(np.clip(255.0 * tensor.cpu().numpy(), 0, 255).astype(np.uint8)).save(path)

# Batch operations
batch = torch.cat([img1, img2], dim=0)    # stack into batch
single = image[i]                          # extract from batch [H,W,C]
single_batch = image.unsqueeze(0)          # add batch dim [1,H,W,C]

MASK 类型

形状为 [H, W] 或 [B, H, W]、取值范围为 0.0-1.0 的 torch.Tensor。

# Invert mask
inverted = 1.0 - mask

# Mask ↔ Image conversion
alpha = mask.unsqueeze(0).unsqueeze(-1)                   # [1,H,W,1]
gray_mask = 0.299*img[:,:,:,0] + 0.587*img[:,:,:,1] + 0.114*img[:,:,:,2]
image_from_mask = mask.unsqueeze(-1).repeat(1, 1, 1, 3)  # [B,H,W,3]

# Ensure batch dim
if mask.dim() == 2:
    mask = mask.unsqueeze(0)  # [1, H, W]

LATENT 类型

含有类型化键的字典:

class LatentDict(TypedDict):
    samples: torch.Tensor       # [B, C, H, W] (image) or [B, C, T, H, W] (video) - required
    noise_mask: NotRequired[torch.Tensor]
    batch_index: NotRequired[list[int]]
    type: NotRequired[str]      # only for "audio", "hunyuan3dv2"

图像模型(SD1.5、SDXL、SD3、Flux):4D [B, C, H, W] — SD1.5/SDXL 为 4 个通道,SD3/Flux 为 16 个通道。潜空间尺寸为像素尺寸的 1/8。

视频模型(Hunyuan Video、Wan、Cosmos、LTX Video、Mochi):5D [B, C, T, H, W] — T 为时间(帧)维度。

samples = latent["samples"]
# Check dimensionality:
if samples.ndim == 5:
    B, C, T, H, W = samples.shape   # video latent
else:
    B, C, H, W = samples.shape      # image latent

# Always preserve extra keys when modifying:
result = latent.copy()
result["samples"] = modified_samples

CONDITIONING 类型

list[tuple[Tensor, PooledDict]] — 由 (cond_tensor, metadata_dict) 对组成的列表。

PooledDict 包含许多适用于不同模型的可选键:

class PooledDict(TypedDict):
    pooled_output: torch.Tensor
    control: NotRequired[ControlNet]
    area: NotRequired[tuple[int, ...]]
    strength: NotRequired[float]           # default 1.0
    mask: NotRequired[torch.Tensor]
    start_percent: NotRequired[float]      # 0.0-1.0
    end_percent: NotRequired[float]        # 0.0-1.0
    guidance: NotRequired[float]           # Flux-like models
    hooks: NotRequired[HookGroup]
    # ... many more model-specific keys (SDXL, SVD, WAN, etc.)

合并 conditioning:result = cond_a + cond_b(列表拼接)。

VIDEO 类型

VideoInput 是抽象基类,包含以下方法:

class VideoInput(ABC):
    def get_components(self) -> VideoComponents    # images tensor + audio + frame_rate
    def save_to(self, path, format=VideoContainer.AUTO, codec=VideoCodec.AUTO, metadata=None,
                bit_depth=None,     # None keeps native depth
                crf=None,           # H.264/AV1 CRF; None -> 18 (H.264) / 24 (AV1)
                color_space=None,   # "sRGB" | "HDR" (BT.2020 HLG) | "HDR PQ"
                preset=None)        # H.264 encoder preset, e.g. "ultrafast"
    def as_trimmed(self, start_time=None, duration=None, strict_duration=False) -> VideoInput | None
    def as_cropped(self, x=0, y=0, width=0, height=0) -> VideoInput  # clamped, even-aligned; empty/full rect = self
    def get_stream_source(self) -> str | BytesIO
    def get_dimensions(self) -> tuple[int, int]     # (width, height)
    def get_duration(self) -> float                  # seconds
    def get_frame_count(self) -> int
    def get_frame_rate(self) -> Fraction
    def get_container_format(self) -> str
    def get_bit_depth(self) -> int                   # max component bits of the stream, e.g. 8/10/12 (default 8)
    def get_color_space(self) -> str                 # "sRGB" | "HDR" | "HDR PQ" | "auto" (unknown)

端到端支持高位深和 HDR(v0.34+):加载器提供 get_bit_depth() / get_color_space(),保存节点会保留这些属性。编解码器:Types.VideoCodec.AUTO/H264/AV1;容器:Types.VideoContainer.AUTO/MP4/MKV/WEBM。

具体实现(通过 from comfy_api.latest import InputImpl 导入):

  • VideoFromFile(file, *, start_time=0, duration=0, crop=None) — 路径或 BytesIO;crop=(x, y, w, h)
  • VideoFromComponents(components, bit_depth=8, color_space="sRGB") — 从张量创建
  • VideoFromList(videos, complete_audio=None, codec=AUTO) — 拼接(v0.36+)

3D 类型

File3D
from comfy_api.latest import Types

# File3D wraps a 3D file (disk path or BytesIO stream)
file_3d = Types.File3D(source="/path/to/model.glb", file_format="glb")
file_3d.format              # "glb"
file_3d.is_disk_backed      # True
file_3d.get_data()          # BytesIO
file_3d.get_bytes()         # raw bytes
file_3d.save_to("/output/model.glb")
MESH、VOXEL 和 SPLAT
from comfy_api.latest import Types

mesh = Types.MESH(vertices=torch.tensor(...), faces=torch.tensor(...))  # (B,N,3), (B,M,3)
voxel = Types.VOXEL(data=torch.tensor(...), voxel_colors=None, resolution=None)
splat = Types.SPLAT(...)   # gaussian splat data

MESH 可选字段(请通过关键字传递 — metallic_roughness 在 v0.34 中插入到 vertex_counts 前,导致位置参数调用失效):uvs (B,N,2)、vertex_colors (B,N,3|4)、texture (B,H,W,3 baseColor)、metallic_roughness (B,H,W,3;G=roughness,B=metallic)、vertex_counts/face_counts (B,) 用于填充批次的实际长度(两者必须同时提供或都不提供)、unlit、normals (B,N,3)、tangents (B,N,4)、normal_map、occlusion_in_mr、material (dict)、emissive。

具有特殊功能的控件类型

Color
io.Color.Input("color", default="#ff0000", socketless=True)
# Value is a hex string like "#ff0000"
Colors(调色板)
io.Colors.Input("palette", default=["#ff0000", "#00ff00"], socketless=True)
# Value is list[str] of hex colors
BoundingBox
io.BoundingBox.Input("bbox",
    default={"x": 0, "y": 0, "width": 512, "height": 512},
    socketless=True,
    component="my_component",  # optional custom UI component
)
# Value is {"x": int, "y": int, "width": int, "height": int}
BoundingBoxes(多个区域)
io.BoundingBoxes.Input("regions", default=[], socketless=True)
# Value is list of {"x": int, "y": int, "width": int, "height": int, "metadata": dict}
Curve
from comfy_api.input import CurveInput

io.Curve.Input("curve",
    default=[(0.0, 0.0), (1.0, 1.0)],  # linear
    socketless=True,
)
# In execute(), normalize the raw value first:
curve = CurveInput.from_raw(curve)
Range(色阶编辑器)
from comfy_api.input import RangeInput

io.Range.Input("levels",
    default={"min": 0.0, "max": 1.0},
    display=None,                # widget visualization mode
    gradient_stops=None,         # gradient background for the slider
    show_midpoint=True,          # show gamma midpoint handle
    midpoint_scale=None,
    value_min=0.0, value_max=1.0,  # UI bounds
)
# In execute(), normalize with RangeInput.from_raw(value):
# .min_val, .max_val, .midpoint (gamma = -log2(midpoint), 0.5 = linear)
# .to_lut(size) generates a GIMP-style levels lookup table
MultiCombo
io.MultiCombo.Input("tags",
    options=["tag1", "tag2", "tag3"],
    default=["tag1"],
    placeholder="Select tags...",
    chip=True,  # show as chips
)
# Value is list[str]
Webcam
io.Webcam.Input("webcam_capture")
# Value is str (captured image data)
ImageCompare
io.ImageCompare.Input("comparison", socketless=True)
# Value is dict

自定义类型

# Simple: create inline custom type
MyData = io.Custom("MY_DATA_TYPE")

# Use in inputs/outputs
io.Schema(
    inputs=[MyData.Input("data")],
    outputs=[MyData.Output("MY_DATA")],
)
进阶:@comfytype 装饰器

适用于带有类型提示或自定义 Input/Output 类的自定义类型:

from comfy_api.latest._io import comfytype, ComfyTypeIO

@comfytype(io_type="MY_DATA_TYPE")
class MyData(ComfyTypeIO):
    Type = dict[str, Any]  # type hint for the data

RAM 缓存大小计算:默认的 RAM 压力缓存会计算输出中的 CPU 张量(也包括列表/元组/字典中的张量);不透明对象按较小的默认值计算。对于持有大型张量的自定义类,请添加 def _comfy_cache_tensors(self): return (self.a, self.b)(核心 MESH/VOXEL/SPLAT 也采用此做法,v0.35+),以便正确计算其大小并进行淘汰。

AnyType / 通配符

# Accept any single type (always a connection input, no widget)
io.AnyType.Input("anything")

# Accept specific multiple types
io.MultiType.Input("data", types=[io.Image, io.Mask, io.Latent])

# MultiType with widget override (shows widget for first type)
io.MultiType.Input(
    io.Float.Input("value", default=1.0),
    types=[io.Float, io.Int],
)

从 comfy_api.latest 导入

from comfy_api.latest import (
    ComfyExtension,  # extension registration
    ComfyAPI,        # runtime API (progress, node replacement)
    io,              # all io types (io.Image, io.Schema, io.ComfyNode, etc.)
    ui,              # UI output helpers (ui.PreviewImage, ui.SavedImages, etc.)
    Input,           # Input.Image (ImageInput), Input.Audio, Input.Mask, Input.Latent, Input.Video
    InputImpl,       # InputImpl.VideoFromFile, .VideoFromComponents, .VideoFromList
    Types,           # Types.MESH, Types.VOXEL, Types.File3D, Types.VideoCodec, etc.
)

张量安全

检查张量是否存在时,始终使用 is not None,不要使用真值判断:

# CORRECT
if image is not None:
    process(image)

# WRONG — multi-element tensors don't support bool()
if image:       # raises RuntimeError
    process(image)

# For boolean conditions on tensors, use .all() or .any()
if (mask > 0.5).all():
    ...

类型转换模式

# IMAGE [B,H,W,C] → MASK [B,H,W]
mask = 0.299 * image[:,:,:,0] + 0.587 * image[:,:,:,1] + 0.114 * image[:,:,:,2]

# MASK [B,H,W] → IMAGE [B,H,W,C]
image = mask.unsqueeze(-1).repeat(1, 1, 1, 3)

# Resize image tensor
import torch.nn.functional as F
resized = F.interpolate(
    image.permute(0, 3, 1, 2),  # [B,C,H,W] for interpolate
    size=(new_h, new_w), mode='bilinear', align_corners=False
).permute(0, 2, 3, 1)  # back to [B,H,W,C]

另请参阅

  • comfyui-node-basics - 节点类结构与注册
  • comfyui-node-inputs - 输入配置详情(控件选项)
  • comfyui-node-outputs - 输出类型与 UI 输出
  • comfyui-node-advanced - MatchType、MultiType、Autogrow、DynamicCombo

评论

支持 Markdown