Nougan V2 PNG Baker π
The Nougan V2 PNG Baker
- image
- saved_path
- character_name
A character card in SillyTavern, Chub, RisuAI or Agnai is a PNG. Not a PNG plus a JSON file - the PNG is the card. The picture is the avatar, and buried in a text chunk inside the same file is the name, the description, the first message, the tags. Import the image, get the character.
That's awkward when the portrait came out of ComfyUI, because Save Image writes a workflow into your PNG, not a character. So you generate, download, open a card editor in the browser, paste the JSON, export a fresh PNG. Ten characters and you've lost an afternoon. The Nougan V2 PNG Baker moves that last step into the graph: the image comes out of the run already being the card.
What it actually writes
The node adds a PNG tEXt chunk keyed chara, whose value is your card JSON, base64-encoded. Decoded, it's the standard shape real cards use:
{"spec": "chara_card_v2", "spec_version": "2.0", "data": {"name": "...", "first_mes": "..."}}
tEXt chunks are ancillary - a viewer that doesn't understand them still shows the picture, which is how card apps work. It's the same trick ComfyUI uses for workflows, with the same trap: the metadata is the payload, so anything that re-encodes the file deletes the character.
Two details worth knowing: it does not embed your ComfyUI workflow (this PNG carries a card and nothing else), and it reopens the file after saving to decode the chunk back, raising an error if the round trip doesn't match. A silently half-broken card is rare here.
The inputs you'll touch
Four inputs; only one ever causes trouble.
image is any IMAGE - JPEG or WebP sources are fine, since Load Image has already decoded them to pixels.
json_text is the card JSON, and it's a socket-only input - you can't type into it. Wire ComfyUI's native String (Multiline) node in and paste the JSON there. This is the number one beginner snag: "Required input is missing: json_text" means the String node is absent or unconnected.
filename_prefix defaults to V2_cards/%name%, saved under ComfyUI's output folder. %name% becomes the card's data.name with path-hostile characters swapped for underscores and the result capped at 80 characters - so Adele/2 gives you Adele_2_00001_.png, not a surprise subfolder.
fill_missing_fields defaults to on: omitted fields get empty defaults (alternate_greetings as [], extensions as {}). Turn it off to store the JSON exactly as pasted.
Outputs are saved_path - the written file, one line per image in a batch - and character_name, the data.name used. Both are plain STRINGs.
It forgives more JSON than you'd expect
The only hard requirement is a non-empty data.name. The rest it repairs, printing each fix to the console and the first one on the node's status line:
- Wraps bare fields into a proper V2 card, and unwraps a card nested under
character,card,result,output,json, or any single key - which covers most "ask a local model for a character" pipelines. - Strips
```jsonfences, a BOM, and double-encoded JSON. - Converts old TavernAI keys (
char_nameβname,char_greetingβfirst_mes, and three more), relabels a V3 card as V2 (extra fields kept, older apps ignore them), lowercases capitalized keys, and turns a comma-separatedtagsstring into a real list.
Unknown keys like character_book pass through untouched. If you're batching twenty sloppy LLM-written characters, that forgiveness is the feature.
Install
In ComfyUI Manager search Nougan, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Winnougan/Nougan_Nodes
# restart ComfyUI
No pip step - the pack declares zero Python dependencies, and this node needs only PIL, numpy and folder_paths, all of which ComfyUI ships (the pyoxipng install in the README is for the Image Converter). Each family loads in its own guard, so an unrelated node failing on boot can't take this one with it.
When it goes wrong
"This doesn't look like a character card β¦ Top-level keys received: [...]" - read that list. nodes and links means you pasted a ComfyUI workflow; that's the Workflow PNG Baker. error and message usually means an upstream LLM node returned its own failure text instead of a card.
"The card has no 'name'" - V2 requires data.name; nothing else is mandatory, but that one is.
"Verification failed β¦ did not round-trip" - the PNG didn't keep the card. In practice that's disk space or folder permissions.
Then the one that isn't the node's fault: the app says your image has no card. Uploaded inline to Discord, X or an image host, it got recompressed and the chunk is gone. Share the file as a file, and test by re-importing your own downloaded copy.
Also worth knowing: the same JSON feeds the pack's Nougan Refmod Baker, which stores a character in a .safetensors header for in-ComfyUI chat.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| json_text | STRING | β | |
| filename_prefix | STRING | V2_cards/%name% | %name% is replaced by the character's name. Saved in the ComfyUI output folder. |
| fill_missing_fields | BOOLEAN | true | β |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| saved_path | STRING | β |
| character_name | STRING | β |