Nodes/Mememage/Mememage Encode
ComfyUI Node

Mememage Encode

Stamp a 2-pixel proof of what made your image

By sememtac·Created 3 months ago·Updated 2 months ago· 1
Mememage Encode
  • image
  • image
  • identifier
  • record
fields
fields_json{}
prefixmememage
embed_workflowtrue
encrypt_workflowfalse
password_file
private
use_identifierfalse
identifier

This is the node the whole pack is named after, and it does something genuinely unusual in ComfyUI: it doesn't rely on the PNG metadata that usually carries your workflow. ComfyUI bakes the entire graph into every saved image as text chunks, and the moment that image is re-encoded - Discord, Reddit, Instagram, a JPEG conversion, a screenshot - that metadata is gone forever. Mememage Encode takes a different bet: it writes your provenance into the pixels themselves, as a two-pixel-tall bar along the bottom edge. Pixels survive re-encoding. Metadata doesn't.

What it actually does

You wire in an image and it hands you three things out:

  • image - your image with the bar stamped in. Wire this into Save Image (or Mememage Save Record) and save.
  • identifier - a key to a record you store wherever you like: a folder, a CDN, IPFS, the Internet Archive. The identifier is access.
  • record - a plain JSON object of whatever fields you chose: your generation data, a creator name, a license, anything.

The bar carries the identifier plus a content hash - a fingerprint of the record. Change a field in the record and it no longer matches the image's bar, which is how you later prove the data belongs to this exact image and hasn't been touched (that's Mememage Verify's job).

Nothing here is a watermark you'd notice - at two pixels it reads as a hairline at the bottom of the image. And despite the mystical name, there's no API, no account, no key. It's all local: mememage.encode() in memory, no disk round-trip.

The inputs that matter

  • image - required, the only one. Wire your VAEDecode output here.
  • fields - the socket for a Mememage Fields / Field / Workflow Fields node. This is where your record data comes from. Values here override matching keys you type in fields_json.
  • fields_json - the inline alternative: type a JSON object directly if you don't want to build fields up node-by-node.
  • embed_workflow (on by default) - stores the generating graph in the record as comfy_prompt. This is the killer feature: the workflow rides inside the verifiable record, so it survives even when the PNG's own metadata is stripped.
  • use_identifier + identifier - this pair is where people get confused. Off by default, meaning the node is content-addressed: change the image, get a fresh identity and a fresh record. That's right for finished work. Flip use_identifier on and pin an identifier (from a Mememage Reserve ID node, or paste <prefix>-<16 hex>) and you iterate one piece - every run overwrites the same record while the hash tracks what actually changed. Content-addressing is the sane default; the toggle just lets you leave a pin wired in and opt in deliberately.
  • password_file / private - for encryption. There is deliberately no plaintext password field: the password comes from a file path or the MEMEMAGE_PASSWORD env var only, so it can never ride the graph into the PNG metadata. private is a comma-separated list of field names to encrypt; leave it empty with a password set and everything gets encrypted (AES-256).

Installing it

This ships in mememage-comfy, a small MIT-licensed pack with a light footprint. Easiest is ComfyUI Manager: search "Mememage" → Install → restart. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/sememtac/mememage-comfy
# install the core library into ComfyUI's OWN python:
<ComfyUI-python> -m pip install mememage

Restart and you'll find it under the Mememage category. The mememage core does all the bar work; Manager pulls it from requirements.txt for you. One optional extra: encryption needs pip install "mememage[encrypt]" (the cryptography library). The pack also pins certifi for HTTPS - that's for the Fetch Record node, not this one.

Where people get burned

  • The PNG metadata leak. ComfyUI's stock SaveImage bakes the whole graph into the file. If you typed a secret into a node widget, its plaintext rides along. The password can't leak (file/env only), but other field values can. The clean path: wire Encode's image into Mememage Save Record, which writes the PNG with no metadata at all - or run ComfyUI with --disable-metadata, or just don't type secrets into widgets.
  • Encryption silently does nothing if cryptography isn't installed - the record stays plaintext. Check the backend log.
  • This pack is new and quiet (zero community threads in the reddit corpus we search), so don't expect a support forum. The README and node tooltips are unusually good - trust them.

The minimal flow: CheckpointLoader → KSampler → VAEDecode → Encode → SaveImage, with record wired into Save Record. The repo's two example workflows drag straight onto the canvas to show it wired.

CategoryMememage

Inputs (10)

NameTypeDefaultDescription
imageIMAGE
fieldsoptSTRINGWire a Mememage Fields / Field node here. Overrides matching keys typed in fields_json.
fields_jsonoptSTRING{}
prefixoptSTRINGmememage
embed_workflowoptBOOLEANtrueEmbed the generating graph in the record as comfy_prompt. When you also encrypt fields, the graph is sealed with them — its widget values ARE those fields' plaintext.
encrypt_workflowoptBOOLEANfalseSeal the embedded workflow (comfy_prompt) too. Encrypting ANY field now does this automatically — the graph carries that field's plaintext — so this is belt-and-braces there. On its own it's a no-op: with no `private` list, a password already encrypts every field including the workflow. To seal ONLY the recipe and keep your other fields public, put `comfy_prompt` in `private` instead.
password_fileoptSTRINGTo encrypt, put your passphrase in a file and give its PATH here (or set the MEMEMAGE_PASSWORD env var). The path rides the graph — the password never does, so it can't leak into the PNG metadata. Empty = public record. Needs mememage[encrypt].
privateoptSTRINGComma-separated top-level field names to encrypt. Empty + a password = encrypt EVERY field. Encrypting anything also seals the embedded workflow, which would otherwise carry those fields' plaintext.
use_identifieroptBOOLEANfalseOFF (default): content-address — a fresh identity per change, ignoring the identifier below EVEN IF a Reserve ID wire is connected. ON: honor the wired/typed identifier to iterate ONE piece (each conceive overwrites the same record). Lets you leave a pin connected but opt in to it deliberately, instead of disconnecting the wire.
identifieroptSTRINGPin a reserved identifier (wire a Mememage Reserve ID node, or paste a <prefix>-<16 hex>) to keep iterating ONE piece — each conceive overwrites the SAME record. Honored only when the 'use_identifier' toggle above is ON. Empty = content-addressed (a fresh identity per change).

Outputs (3)

NameTypeDescription
imageIMAGE
identifierSTRING
recordSTRING