PettyPaintStoryImage
Compose a comic page cell from the iPad's camera data
- image
- output
This is the node that earns the pack's name. Petty Paint is a painting app, and PettyPaintStoryImage is where your drawings actually get assembled into a comic page: you paint characters on the iPad, and this node pastes them onto a page cell at the positions the app's camera data says they should sit, then saves the finished panel. If you're not using the iPad side of this pack, skip this node - it's useless without the app's JSON. If you are, it's the payoff.
How it works
The single input, data, is a JSON string with a fixed shape. The node expects keys like page_cell_path (the background panel image), storage_path and model (where and under what folder to save), page_cell (with page and cell numbers), and composition - a list of character placements. Each composition entry carries a character_path, a character_mask_path, and camera_data with project_x, project_y, and top_y giving the on-screen position and height.
The mechanism, per character: open the character image and its mask, apply the mask as the alpha channel, resize the character so its projected height matches what the camera data says, and paste it onto the page cell at the projected position, cropping if it runs off the edge. When every character is placed, the node saves the composite as comic_{page}_{cell}.png inside storage_path/model/ and returns the full output path.
The outputs - and the trap
image- the file path of the saved PNG, typed as a STRING. Not an IMAGE tensor. This trips people up constantly: you can't wire this straight into an image viewer or a sampler. To actually see or process the result, feed the path into an image-loading node first.output- a plain-text log of what the node did per character (image sizes, crop boxes, any skipped placements). Mostly there for debugging; wire it to a text display if you want to watch.
The node validates the JSON before it runs - VALIDATE_INPUTS checks the required keys and that the referenced files exist, and it'll reject the input if a character or mask path is missing. That's genuinely helpful, because a mistyped path otherwise fails halfway through compositing with a confusing PIL error.
Using it
You won't type this JSON by hand. In the normal petty-paint flow, the app's data is parsed from the project file with PettyPaintToJson, fields are pulled out with the pack's JSON nodes, and the composed string is handed here. The node also guards against not-ready-yet states: if data is None or paths are missing, it returns empty strings instead of crashing the queue.
Installing it
Same install as the whole pack - ComfyUI Manager search "Petty Paint", or:
cd ComfyUI/custom_nodes
git clone https://github.com/mephisto83/petty-paint-comfyui-node
then restart. No models to download; the pack's pinned Flask dependency isn't imported by the current source, so nothing heavy installs.
When it bites you
The main gotchas are file-path oriented: the character and mask files have to exist on the machine running ComfyUI (the app's files need to be synced to that folder), and the output path is a string you must load to see. If panels come out blank, check the crop-box logic in the log output - characters placed off-canvas get skipped rather than erroring, so an empty panel is often a camera-data problem, not a compositing one.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| data | STRING | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | STRING | — |
| output | STRING | — |