好久没聊 ComfyUI 的底层细节了,今天专门把图片元数据这个话题掰开揉碎讲一遍。玩 ComfyUI 的人基本都遇到过这种情形:群里收到一张别人发的 PNG,往 ComfyUI 画布里一拖,整个工作流瞬间恢复,节点、参数、连线、坐标全在里面,连当时用的大模型叫什么都写得清清楚楚;可另一些 PNG 拖进去却毫无反应,看似一样的图,差别就藏在图片元数据里。ComfyUI 生成的 PNG 默认会嵌入工作流的完整 JSON 和实际执行时的 prompt 信息,相当于给每张图附带了一份“生成配方”。
这篇文章我从元数据的存储机制、提取方式、复用场景,一直聊到清理和隐私防护,包含我平时写过的脚本、踩过的坑、以及从大量图片里批量恢复工作流的经验。无论你是刚开始接触 ComfyUI 的新手,还是已经折腾了很久、想建立自己的工作流素材库的老手,理解这套机制都很值。
1. 元数据这事,为什么偏偏在 ComfyUI 里值得专门研究
1.1 一次翻车经历:归档的图全变“废图”
事情的起因是我想从去年的一批老图里复现当时某个效果。我按时间顺序把生成结果整理成了文件夹,文件名老老实实写了参数缩写,但关键的网络结构、采样器步数、CFG 这些细节,当时觉得“反正自己肯定会记得”就没写。结果半年后翻出来,文件名里那几个数字根本不顶用,我当时用的是什么 LoRA、模型是不是那个微调过的版本,全忘了。
然后我试着把这些 PNG 拖回 ComfyUI,有一部分成功恢复了完整工作流,有一部分拖进去毫无反应。那一刻我才意识到:ComfyUI 把工作流写在图片元数据里这件事,不是“锦上添花”,而是长期创作的救命稻草。可惜很多人的第一反应是压缩图片、改格式、再截图转发,结果把元数据弄丢了,等于把一次创作的完整记录亲手抹掉了。后来我开始系统研究 PNG 里的元数据结构,也写了批处理脚本做归档,现在整理图库的方式完全不一样了。
1.2 ComfyUI 的元数据与 WebUI 的差别到底在哪
用过 Stable Diffusion WebUI 的人都知道,A1111 也会把生成参数写进 PNG,用图片查看器看信息就能看到正向提示词、反向提示词、步数、采样器这些字段。但 WebUI 写入的是“扁平化”的参数键值对,读完你只知道参数,没法把节点的组织方式还原出来。
ComfyUI 不一样,它写入的是整棵节点图的 JSON。你画布上的节点类型、每个节点的输入输出参数、连线关系、甚至节点的位置坐标,全都会被序列化进图片。这意味着只要元数据完整,你把图片拖回 ComfyUI,看到的就是当初画布上那个一模一样的图。这个差异非常关键:WebUI 的元数据是“参数清单”,ComfyUI 的元数据是“工作流的完整快照”。所以 ComfyUI 能从一个 PNG 里完全重建工作流,而 WebUI 只能重建“设置项”。
好处是工作流分享变得极其简单,发一张图等于发了一套可运行的流程。坏处是如果你不理解这套机制,很容易在无意中泄露自己的全部技术细节,或者反过来,因为错误的处理方式而丢失了本可以反复使用的资产。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 元数据藏在哪:PNG 文件里的“双重信息结构”
2.1 PNG 的 tEXt 块:附着在图像里的文本夹层
要理解 ComfyUI 的元数据,先要简单知道 PNG 文件的结构。PNG 不是一整块像素数据,而是由很多“块(chunk)”组成的容器,常见的块有 IHDR(图片头信息)、IDAT(压缩后的像素数据)、IEND(文件结束标记),中间可以夹着很多其他类型的块。
ComfyUI 往 PNG 里写入的文本信息,主要放在 tEXt 块里。tEXt 块是 PNG 规范里的标准文本块,用来保存作者的名称、备注、软件信息等任意文本。ComfyUI 会往里面写入两个关键字段:prompt 和 workflow。简单理解,PNG 文件相当于一个文件夹,像素数据是主体,tEXt 块是贴在外面的便签,而 ComfyUI 在便签上写了满满两页技术笔记。
用 Python 读取 PNG 元数据非常直接,一行代码就能看到这些便签的内容:
python复制from PIL import Image
img = Image.open("example.png")
# 输出图片里所有的文本元数据键名
print(img.info.keys())
# 查看 workflow 内容
print(img.info.get("workflow", "无 workflow"))
我在本地跑这段代码时,输出的 workflow 是一长串 JSON,节点名、class_type、inputs 全部在内,结构跟 ComfyUI 保存的工作流文件(workflow.json)几乎一致。这从根上说明了为什么一张 PNG 可以完整还原整个 ComfyUI 工程。
2.2 workflow 和 prompt:两个 JSON 的分工逻辑
ComfyUI 写入的这两个字段,很多人会混淆,但它们不是同一份数据,作用也不同。
prompt 字段保存的是“执行图”,也就是 ComfyUI 后端真正用来推理的那份 JSON。它里面包含每个节点的 class_type(比如 KSampler、CLIPTextEncode)、具体的参数值、节点之间的数据依赖关系。这份 JSON 是从画布图编译出来的,结构紧凑,适合后端执行和脚本解析。由于 prompt 里只包含执行需要的字段,不含节点在画布上的坐标位置,所以只靠 prompt 无法完美还原画布布局。
workflow 字段保存的是“用户界面图”,是你在 ComfyUI 画布上看到的那张完整图表。它包含节点位置、尺寸、颜色、连线路径、可折叠面板的状态、甚至你给节点加过的备注。把这份数据加载回前端,画布就能恢复成和保存时一样的布局。
两者一起写入,才实现了“图片拖回去就能编辑”的效果。我自己的经验是:如果只需要复现生成结果,用 prompt 就够了;如果想把别人发来的工作流拿到自己画布上继续改,必须靠 workflow。做脚本自动化时通常读 prompt,因为字段稳定;做 UI 恢复时读 workflow,因为布局信息全在那边。
2.3 WebP、JPEG 的元数据情况:为什么建议用 PNG 保存原始结果
ComfyUI 默认输出 PNG 格式,保存时写入完整元数据。但如果保存成 WebP,情况会不同,新版本的 ComfyUI 对 WebP 也支持写入元数据,但兼容性、字段完整性不如 PNG 稳定。而 JPEG 格式因为是有损压缩,很多信息会被转码软件直接丢弃,tEXt 块基本没法保留。
实际使用中,我是这么处理的:原始生成结果一律保存 PNG,这也是 ComfyUI 的默认行为;需要发社交媒体或聊天软件时,再单独导出一份 JPG 或 WebP,并且心里要清楚,这份导出件只是“预览图”,不具备工作流还原能力。很多人习惯把 PNG 压成 JPG,再从聊天软件里重新保存一遍,这是元数据丢失最常见的路径。后面我会专门讲丢失的场景。
所以这里先给一个明确建议:建立自己的图库时,原始 PNG 永远单独保存,不要用平台下载的“二次保存文件”代替原图。一图一源,保证元数据完整,后面所有工作流复用和归档都建立在这个前提上。
3. 实操环节:查看、提取与复用图片元数据的完整路径
3.1 最直接的用法:拖拽 PNG 到 ComfyUI 画布还原工作流
这是 ComfyUI 最让人上瘾的功能之一。你在浏览器里打开 ComfyUI 界面,把一张带有完整元数据的 PNG 直接拖进页面,系统会提示是否加载图片中的工作流,确认后画布上立刻出现完整的节点图,所有参数都在。
这个操作有几种细节值得注意:一是拖拽时如果图片是从聊天软件下载的,注意确认文件是不是被对方或平台二次处理过,很多情况下文件虽然仍叫.png,但内部 tEXt 块已经被剥掉;二是 ComfyUI 的项目文件(.json 文件)直接拖入也可以加载,但 PNG 拖入最方便,因为图片本身就是容器;三是如果你自己用代码批量生成图片,只要保存时带上 workflow JSON,拖拽恢复同样有效。
我在多台电脑之间切换时,大量使用这个功能。从一台机器导出 PNG,在另一台机器拖入,只要模型路径一致,工作流可以无缝继续。路径不一致的话,ComfyUI 会提示找不到某个模型,手动切换到本地对应模型即可。
3.2 代码级读取:用 Python 把元数据提取成 JSON 文件
拖拽适合单张图,但如果你要处理几十张甚至上百张图,手动拖就不现实了。这时候用 Python 脚本批量提取最靠谱。代码如下:
python复制import json
import os
from PIL import Image
def extract_metadata(png_path):
img = Image.open(png_path)
prompt = img.info.get("prompt")
workflow = img.info.get("workflow")
return prompt, workflow
# 单张测试
prompt, workflow = extract_metadata("test.png")
if prompt:
data = json.loads(prompt)
print("提示词节点数:", len(data))
# 批量导出 JSON
def batch_export(folder, output_dir):
os.makedirs(output_dir, exist_ok=True)
for name in os.listdir(folder):
if not name.lower().endswith(".png"):
continue
path = os.path.join(folder, name)
prompt, workflow = extract_metadata(path)
if prompt:
out_path = os.path.join(output_dir, name + ".prompt.json")
with open(out_path, "w", encoding="utf-8") as f:
json.dump(json.loads(prompt), f, ensure_ascii=False, indent=2)
if workflow:
out_path = os.path.join(output_dir, name + ".workflow.json")
with open(out_path, "w", encoding="utf-8") as f:
json.dump(json.loads(workflow), f, ensure_ascii=False, indent=2)
batch_export("images", "metadata_output")
这个脚本的逻辑很简单:遍历文件夹里的 PNG,读取 prompt 和 workflow 两个字段,分别存成 JSON。输出文件的命名我故意保留了原始图片名,方便后续建立图库索引。
实际跑下来要注意编码问题。ComfyUI 写入的 JSON 里可能包含中文提示词,读取后建议立刻 json.loads 再重新序列化,避免保存时因为默认编码出问题。上面代码里 ensure_ascii=False 就是要保留可读的中文。
3.3 命令行工具方案:exiftool 快速查看
不想写代码的时候,用 exiftool 是最高效的。它是一个跨平台命令行工具,可以查看几乎所有图像格式的元数据。ComfyUI 写入的 prompt 和 workflow 字段,在 exiftool 里也能直接看到:
bash复制exiftool -prompt -workflow output.png
如果只想看 workflow 的纯文本内容,可以这样:
bash复制exiftool -workflow -b output.png > saved_workflow.json
-b 参数表示输出原始二进制/文本内容,而不是带标签的封装格式。这样导出的 JSON 可以直接拖回 ComfyUI 画布加载。我在分析别人分享的 PNG 时经常用这个命令,几秒钟就能看到对方工作流的完整结构,比自己肉眼对照节点图方便多了。
另外,如果你习惯用图片管理器浏览图库,可以试试一些支持查看 PNG tEXt 块的工具,比如 XnView MP 的“信息”面板,也能看到部分文本字段,但不一定完整。exiftool 是最稳妥的通用方案。
3.4 清理与重写元数据:避免默认残留
和提取相反,有时候你需要清理元数据。最简单粗暴的方式是用 Python 重写一张不带元数据的 PNG:
python复制from PIL import Image
from PIL.PngImagePlugin import PngInfo
img = Image.open("output.png")
# 新建一个空的 PngInfo 对象,不写入任何字段
clean_png_info = PngInfo()
img.save("output_clean.png", pnginfo=clean_png_info)
需要注意的是,仅执行 img.save 而不传 pnginfo 参数时,Pillow 在某些版本下可能会保留部分原图信息,稳妥做法是显式传入一个空的 PngInfo 对象。上面的代码就是官方推荐的做法,保证清理后图片只有像素数据,不携带任何工作流文本。
ComfyUI 本身也提供了机制来避免生成带元数据的图片。在较新版本中,可以通过启动参数 --disable-metadata 运行 ComfyUI,这样默认保存的图片就不会写入 prompt 和 workflow。UI 设置里是否提供对应开关取决于版本,如果你需要长期对外发布预览图,可以研究一下自己版本对应的关闭路径。不过别急着关,我的建议是:生成阶段保留元数据,发布阶段再清理,别把源头的能力砍掉。
4. 元数据的应用场景:从参数复现到批量归档
4.1 老图复现:把图片变成可运行的工作流
最核心的用途就是参数复现。ComfyUI 生成的图,理论上只要你拥有完整的原文件,就可以随时回到生成那一刻的状态。几年前做过的效果,如果 PNG 还在,拖进 ComfyUI 就能看到当时的所有节点。
但有一个现实问题:节点版本和自定义节点兼容性。老图里的节点可能是某个自定义插件提供的,如果新环境没装对应插件,加载工作流会报错、显示缺失节点。所以“完整还原”是相对的,前提是工作流里用到的东西你都装得有。因此我强烈建议在归档图片的同时,把当时使用的模型和插件版本也记录下来,或者至少保持插件的稳定版本不动,否则图片元数据有了,但“配方里的原料”找不齐也没用。
4.2 批量归档:把图库变成可搜索的工作流库
当你积累了大量生成图片后,单纯靠文件名整理是不够的。我现在的做法是:所有原始 PNG 按日期归档,然后跑一次批量提取脚本,把每张图的 prompt 和工作流都导出成独立的 JSON 文件。
有了这些 JSON,我可以做几件事:按提示词模糊搜索某类作品;按采样器或 CFG 找出当时最满意的参数组合;甚至对比两个工作流的区别。这套流程完全不需要打开 ComfyUI 就能完成,因为元数据已经抽取到文件系统里,任何文本工具都可以参与检索。批量提取脚本我在 3.2 中给出了,实际运行时可以加上日志记录,把没有元数据的 PNG 单独列出来,方便检查是否有什么文件已经损坏。
4.3 自动化流水线:从元数据直接驱动重跑
如果你对 ComfyUI 的 API 模式熟悉,可以把图片里的 prompt JSON 直接作为 API 请求体发送给后端,实现“一键重跑”。这个思路在批量修图、参数微调时特别好用。
大致思路是:从 PNG 中提取 prompt,解析出需要修改的位置,比如把文本提示词换成新的,或把随机种子换掉,然后把修改后的 JSON 发给 ComfyUI 的 /prompt 接口。等于让图片元数据变成可编程的起点。
我在做批量换装测试时,就是先导出一张基准图,提取它的 prompt,然后用脚本将 LoRA 名称或提示词片段做替换,循环提交了一批任务。这个流程比在 UI 里手动改节点高效得多。不过要注意,API 模式下发送的 JSON 必须满足后端对节点依赖关系的要求,直接从图片中提取的 prompt 可以运行,但要做参数替换时,必须确保替换后的值在目标模型或插件里真实存在,否则会报错。
5. 元数据丢失与隐私防护:两个必须知道的方向
5.1 为什么图片一上传聊天软件或社交平台,元数据就没了
这是最普遍的问题:明明本地原图拖回去还能恢复工作流,发到群里让大家下载后却不行了。原因有两个。一是很多社交平台和聊天软件会对上传的图片做转码压缩,最常见的处理是重新编码为 JPG 或 WebP,这会直接丢弃 PNG 的 tEXt 块;二是即使文件扩展名还是 .png,平台在“优化存储”时也可能重写 PNG 文件,只保留像素数据,丢弃文字信息。
实测下来,微信、Telegram 这类软件如果“不勾选原图”发送,图片基本会被转码;即使勾选原图,某些平台仍可能重新封装文件。因此你要有一个心理预期:对外分享过的 PNG,一旦经过平台二次处理,就不再适合作为工作流备份依赖了。分享工作流的正确做法,是把工作流导出为 .json 文件和预览图一起发,或者用支持元数据的直链分享原文件。
5.2 隐私风险:你的工作流细节可能全被别人看到了
很多人没意识到,把一张 ComfyUI 原图直接发给别人,相当于把工作流源码发给了对方。节点怎么搭、模型叫什么、LoRA 权重多高、采样器参数、甚至自定义节点里的 API 密钥之类的敏感输入,只要在元数据里出现,别人用 exiftool 就能全部看到。
尤其要注意自定义节点的某些输入框里可能填有密钥、token、本地文件路径,这些信息会被写进 prompt JSON。如果是你自己用,问题不大;如果要把图发给客户或公开,一定要在发布前清理元数据。我在实际工作中给外部交付预览图时,会专门跑一遍清理脚本,再确认输出文件里没有 workflow 字段。避免“图没问题、元数据全泄露”的尴尬。
5.3 清理元数据的几种操作方法
清理元数据的方法要按使用场景分。对于单张图片,最简单的是用 3.4 里的 Python 脚本重写一张;也可以用 exiftool 直接删除字段:
bash复制exiftool -prompt= -workflow= output.png
这个命令会把 prompt 和 workflow 字段置空,并在原文件旁边生成备份,把备份删掉即可。
如果想在 ComfyUI 层面关闭元数据写入,可以用 --disable-metadata 启动参数。但正如前面所说,我建议保留这个能力,毕竟它是工作流复用和归档的底气。更合理的做法是:原始输出保留完整元数据,对外发布时用脚本生成清理版。
另外注意,其他元数据(如 GPS 信息、相机信息)和 ComfyUI 的工作流元数据是两回事,清理时要区分。普通图片压缩工具可能清理掉的是 EXIF,但对 PNG 的 tEXt 块不一定有效,所以不要想当然地以为“用看图软件另存为”就能清除干净。
6. 常见问题排查速查表
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 拖 PNG 进 ComfyUI 没反应 | 元数据缺失,或图片被平台二次编码 | 用 exiftool 检查 prompt/workflow 字段是否存在 |
| 能恢复工作流但报缺节点 | 自定义节点或模型未安装 | 按报错提示安装对应插件,或手动替换缺失节点 |
| prompt 里的模型路径不符 | 本地模型库结构与原作者不同 | 在加载后的工作流中手动切换到本地模型 |
| 读取元数据时中文乱码 | JSON 编码问题 | 读取后立即 json.loads 再保存,避免直接处理原始文本 |
| 清理元数据后文件变大/变小 | 重新编码导致压缩率变化 | 属于正常现象,重点确认像素数据未损坏 |
| 发出去的图别人没法还原工作流 | 平台已剥离 tEXt 块 | 改用工作流文件 .json 配合预览图分享 |
| 批量提取时部分图没有元数据 | 原图不是 ComfyUI 生成,或被二次处理过 | 列出无元数据的文件,单独确认来源 |
排查元数据问题,我通常遵循先检查后处理的原则。先确认文件本身的元数据还在不在,再决定下一步是提取、恢复还是清理。很多看起来“工作流坏了”的情况,其实只是文件经过了一次转码,原始创作记录还在本地备份里。
根据我个人的实际操作经验,图片元数据这件事最值得做的是在创作早期就建立规范:原始 PNG 永久保存,不轻易删;需要分享时专门生成清理版;定期把关键工作流导出成 JSON 单独归档。这样既能享受 ComfyUI 元数据带来的便利,又不会在发布时暴露过多细节。ComfyUI 的图片元数据机制,用好了是资产库,不注意是隐患,全看你怎么管理它。
