Image > ImageToBase64
How to get a picture out of ComfyUI as plain text — ImageToBase64
- image
- BASE64
Pixels in, string out
Sooner or later you have an image on a wire and the thing that wants it only speaks text. An LLM or vision node that takes the picture as a string. An HTTP request node posting JSON to some service. A note, a log, a CSV, a database column, a shared workflow JSON that should carry its own reference image instead of a file path into your input folder. ImageToBase64 is the adapter: IMAGE in, a raw PNG base64 string out.
It's the mirror of Base64ToImage in the same pack, and the two together are the whole text↔graph bridge. Note what it is not: it saves nothing to disk and uploads nothing anywhere. It re-encodes what's already in the graph so something text-shaped can carry it.
What it actually does
Straight from the source: take the incoming tensor, grab image[0], multiply by 255 and cast to uint8, build a Pillow image from that array, save it as PNG into an in-memory buffer, then base64-encode the bytes and decode them as UTF-8 text. Always PNG, always lossless, no quality slider to argue with. Two consequences fall out of that implementation: image[0] means only the first image of a batch gets encoded, and the PNG is written with no pnginfo, so it carries none of the tEXt chunks a SaveImage PNG would - no workflow, no prompt, no seed.
Input, output, and how to actually read the string
image- theIMAGEto encode. Tooltip: "The image to transform."BASE64- aSTRINGcontaining the raw base64, with nodata:image/png;base64,prefix. The README is explicit about that, and it's the right call: the prefix is a presentation detail, so you add it yourself only where a consumer demands a data URI.
Here's the annoying part: the node returns a plain string with no UI output of its own, so ComfyUI shows you nothing on the canvas. Wire BASE64 into the core Preview as Text node (PreviewAny, under utils) and you get the string rendered in the graph - and that's also the version that turns up in the API's history response, because /history only reports nodes that hand back UI output. Which means this works:
curl -s -X POST http://127.0.0.1:8188/prompt \
-H 'Content-Type: application/json' -d @prompt.json
import json, urllib.request
hist = json.load(urllib.request.urlopen("http://127.0.0.1:8188/history/YOUR_PROMPT_ID"))
string = hist["YOUR_PROMPT_ID"]["outputs"]["PREVIEW_NODE_ID"]["text"][0]
print(len(string), string[:60])
Need a data URI for something picky? Prepend it with the core Concatenate node (StringConcatenate, utils/string): put data:image/png;base64, in string_a, wire BASE64 into string_b, leave the delimiter empty.
Installing it
Same pack, same one install. Manager → search ComfyUI-SimpleUtils → install → restart. Or:
comfy node install comfyui-simpleutils
Or clone it yourself and restart ComfyUI:
cd ComfyUI/custom_nodes
git clone https://github.com/moonstar-x-libs/ComfyUI-SimpleUtils.git
There's nothing else to do. The only dependencies are numpy, pillow and torch - all bundled with ComfyUI - so there are no models, no downloads, no pip resolution roulette, and no reason for an IMPORT FAILED here. The node shows up as Image > ImageToBase64 under the SimpleUtils category.
Gotchas worth knowing before you burn an hour
Batches silently lose images. Only the first one comes out. If you queue eight variations and need eight strings, split the batch upstream with core's ImageFromBatch (batch_index, length) and encode one at a time, or run separate prompts.
Text is fat. Base64 adds about a third on top of the PNG, and PNG is already the big format - a 1024×1024 photoreal render is routinely 2–3 MB, so you're looking at millions of characters. Fine in an API payload, rough inside an LLM context window, and painful inside a workflow JSON. If a vision model is the destination, downscale before you encode.
The metadata is gone, which is either a problem or a feature. No tEXt chunks means no prompt, no seed, no checkpoint name riding along in the string you're about to paste into a chat or a forum post. Given that the default in this ecosystem is disclosure - the PNG is normally your project file, prompt and all - this node quietly doubles as a pre-share scrubber. Just don't expect a workflow embedded in a source PNG to survive the trip out.
No alpha forcing, unlike its sibling. Base64ToImage converts everything to RGB and drops transparency; this encoder doesn't - it writes whatever channel count the tensor has. In practice ComfyUI IMAGE tensors are three-channel, so you'll get an RGB PNG, but that asymmetry is worth remembering if you round-trip.
It's an output node. ComfyUI treats it as a terminal, so it runs even when nothing consumes the string. Convenient - drop it at the end of the graph and queue - but it also means a stray one still does its encode on every run.
Last thing, since it's the honest read on a young, obscure pack: single maintainer, MIT, essentially no community footprint yet, and both nodes are tiny. The test suite covers exactly the edge cases above - first-image-of-batch, no-prefix output, non-RGB input - which is more assurance than most lightly-starred packs ever give you.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | The image to transform. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| BASE64 | STRING | — |