Comfy for Advertising - OOH Visualization
简介
This ComfyUI workflow helps brand and creative teams quickly place an existing poster into realistic Out-of-Home (OOH) scenarios. It’s organized in two clear stages. STEP 1 – POSTER REFORMAT takes your source poster and non-destructively reformats it to multiple aspect ratios (vertical, horizontal, square, or custom) while preserving the original design. This stage is driven by LoadImage, PrimitiveNode (for width/height values), PrimitiveBoolean (to enable/disable formats), ComfySwitchNode (to route only the formats you want), and BatchImagesNode (to package multiple outputs).
SaveImage captures clean, reformatted versions ready for placement.
STEP 2 – OOH VISUALIZATION composites a chosen reformatted poster into a real or described environment. You can supply a location photo with LoadImage via the IMAGE ENVIRONMENT group or describe a scene in plain language (for example, "OOH billboard in downtown San Francisco, on top of a two-story building, pedestrian eye level") in the PROMPT ENVIRONMENT group. GeminiImage2Node is used as a prompt helper to convert your plain-language description into structured scene notes and file-name context.
Two custom processing nodes (ae42e662-5e2b-4f52-b31d-267bd68f1c6f and 88b611c3-ce43-4e7a-a59f-dd16f57a8853) handle the perspective mapping and blending of the poster onto the target surface, so you can fine-tune scale, skew, and overlay strength for believable placement. SaveImage then outputs the final mockups, optionally in batches, so you can compare formats and scenes side by side.
你需要提供
- 正在读取工作流
在 ComfyUI 中运行。 此工作流无法在本页面运行。你可以在 Comfy Cloud 中打开(已预先加载所需内容),或下载后在自己的 ComfyUI 中使用。
在 Cloud 中试用试试一个示例
查看工作流内部
节点图的只读预览。在 Comfy Cloud 中打开或下载后即可编辑节点。
Loading the graph
Open full-size workflow preview- 作者
- ComfyUI
需要自定义节点
- 正在读取工作流
通过代码使用此工作流
尽可能根据工作流图和输入自动生成代码,否则显示已保存的示例。运行代码可能产生费用,请先核对凭据和端点。
What you need
- Runs on
- Comfy Cloud
- 密钥
- COMFY_API_KEY
- 你的文件
- 由代码根据链接上传
需要付费的 Cloud 方案和额度。
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"64": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Poster_Resize_Custom",
"images": [
"252:251",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"66": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "INPUT POSTER"
}
},
"127": {
"class_type": "GeminiImage2Node",
"inputs": {
"aspect_ratio": "1:1",
"images": [
"128",
0
],
"model": "gemini-3-pro-image-preview",
"prompt": "visualize this poster (keep its aspect ratio) to a OOH billboard in the street of downtown San Francisco, on top of a two story building. Shot from the perspective of a pedestrian",
"resolution": "2K",
"response_modalities": "IMAGE+TEXT",
"seed": 0,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests."
},
"_meta": {
"title": "Nano Banana Pro (Google Gemini Image)"
}
},
"128": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_2_FILENAME"
},
"_meta": {
"title": "INPUT POSTER"
}
},
"129": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Poster_Mockup",
"images": [
"136",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"135": {
"class_type": "BatchImagesNode",
"inputs": {
"images.image0": [
"142",
0
],
"images.image1": [
"235:162",
0
]
},
"_meta": {
"title": "Batch Images"
}
},
"136": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"127",
0
],
"on_true": [
"138",
0
],
"switch": [
"141",
0
]
},
"_meta": {
"title": "If/Else Switch"
}
},
"138": {
"class_type": "GeminiImage2Node",
"inputs": {
"aspect_ratio": "auto",
"images": [
"135",
0
],
"model": "gemini-3-pro-image-preview",
"prompt": "replace the billboard of the first image to the poster of the second image",
"resolution": "2K",
"response_modalities": "IMAGE+TEXT",
"seed": 303461698342474,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests."
},
"_meta": {
"title": "Nano Banana Pro (Google Gemini Image)"
}
},
"141": {
"class_type": "PrimitiveBoolean",
"inputs": {
"value": True
},
"_meta": {
"title": "SWITCH TO IMAGE ENVIRONMENT"
}
},
"142": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_3_FILENAME"
},
"_meta": {
"title": "IMAGE"
}
},
"243": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Poster_Resize1",
"images": [
"252:250",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"245": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Poster_Resize2",
"images": [
"252:249",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"247": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Poster_Resize3",
"images": [
"252:248",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"235:152": {
"class_type": "Paste By Mask",
"inputs": {
"image_base": [
"235:230",
0
],
"image_to_paste": [
"235:229",
0
],
"mask": [
"235:229",
0
],
"resize_behavior": "keep_ratio_fit"
},
"_meta": {
"title": "Paste By Mask"
}
},
"235:153": {
"class_type": "ImageToMask",
"inputs": {
"channel": "red",
"image": [
"235:152",
0
]
},
"_meta": {
"title": "Convert Image to Mask"
}
},
"235:158": {
"class_type": "ImageToMask",
"inputs": {
"channel": "red",
"image": [
"235:231",
0
]
},
"_meta": {
"title": "Convert Image to Mask"
}
},
"235:159": {
"class_type": "InvertMask",
"inputs": {
"mask": [
"235:153",
0
]
},
"_meta": {
"title": "Invert Mask"
}
},
"235:162": {
"class_type": "ImageRemoveAlpha+",
"inputs": {
"image": [
"235:165",
0
]
},
"_meta": {
"title": "🔧 Image Remove Alpha"
}
},
"235:163": {
"class_type": "Get Image Size",
"inputs": {
"image": [
"128",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"235:165": {
"class_type": "Paste By Mask",
"inputs": {
"image_base": [
"235:231",
0
],
"image_to_paste": [
"128",
0
],
"mask": [
"235:152",
0
],
"resize_behavior": "keep_ratio_fit"
},
"_meta": {
"title": "Paste By Mask"
}
},
"235:168": {
"class_type": "MaskComposite",
"inputs": {
"destination": [
"235:158",
0
],
"operation": "add",
"source": [
"235:159",
0
],
"x": 0,
"y": 0
},
"_meta": {
"title": "Combine Masks"
}
},
"235:191": {
"class_type": "FluxResolutionNode",
"inputs": {
"aspect_ratio": "1:1 (Perfect Square)",
"custom_aspect_ratio": "1:1",
"custom_ratio": False,
"divisible_by": "8",
"megapixel": "2.1"
},
"_meta": {
"title": "Flux Resolution Calc"
}
},
"235:229": {
"class_type": "LayerUtility: ColorImage V2",
"inputs": {
"color": "#ffffff",
"custom_height": [
"235:163",
1
],
"custom_width": [
"235:163",
0
],
"size": "custom"
},
"_meta": {
"title": "LayerUtility: ColorImage V2"
}
},
"235:230": {
"class_type": "LayerUtility: ColorImage V2",
"inputs": {
"color": "#000000",
"custom_height": [
"235:191",
1
],
"custom_width": [
"235:191",
0
],
"size": "custom"
},
"_meta": {
"title": "LayerUtility: ColorImage V2"
}
},
"235:231": {
"class_type": "LayerUtility: ColorImage V2",
"inputs": {
"color": "#ffffff",
"custom_height": [
"235:191",
1
],
"custom_width": [
"235:191",
0
],
"size": "custom"
},
"_meta": {
"title": "LayerUtility: ColorImage V2"
}
},
"252:131": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "",
"string_a": "Resize the OOH poster to ",
"string_b": "3:1"
},
"_meta": {
"title": "Concatenate Text"
}
},
"252:132": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "",
"string_a": [
"252:131",
0
],
"string_b": " aspect ratio. Only move and rescale elements to fit the new format. Maintain all original typography, colors, graphics, logos, and visual hierarchy exactly as they are. No design changes."
},
"_meta": {
"title": "Concatenate Text"
}
},
"252:248": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"66",
0
],
"on_true": [
"252:260",
0
],
"switch": True
},
"_meta": {
"title": "If/Else Switch"
}
},
"252:249": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"66",
0
],
"on_true": [
"252:259",
0
],
"switch": True
},
"_meta": {
"title": "If/Else Switch"
}
},
"252:250": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"66",
0
],
"on_true": [
"252:258",
0
],
"switch": True
},
"_meta": {
"title": "If/Else Switch"
}
},
"252:251": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"66",
0
],
"on_true": [
"252:264",
0
],
"switch": True
},
"_meta": {
"title": "If/Else Switch"
}
},
"252:258": {
"class_type": "GeminiNanoBanana2",
"inputs": {
"aspect_ratio": "9:16",
"images": [
"66",
0
],
"model": "Nano Banana 2 (Gemini 3.1 Flash Image)",
"prompt": "Resize this OOH poster to the new aspect ratio. Only move and rescale elements to fit the new format. Maintain all original typography, colors, graphics, logos, and visual hierarchy exactly as they are. No design changes.",
"resolution": "2K",
"response_modalities": "IMAGE",
"seed": 806105455324093,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.",
"thinking_level": "HIGH"
},
"_meta": {
"title": "Nano Banana 2"
}
},
"252:259": {
"class_type": "GeminiNanoBanana2",
"inputs": {
"aspect_ratio": "16:9",
"images": [
"66",
0
],
"model": "Nano Banana 2 (Gemini 3.1 Flash Image)",
"prompt": "Resize this OOH poster to the new aspect ratio. Only move and rescale elements to fit the new format. Maintain all original typography, colors, graphics, logos, and visual hierarchy exactly as they are. No design changes.",
"resolution": "2K",
"response_modalities": "IMAGE",
"seed": 952769964755599,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.",
"thinking_level": "HIGH"
},
"_meta": {
"title": "Nano Banana 2"
}
},
"252:260": {
"class_type": "GeminiNanoBanana2",
"inputs": {
"aspect_ratio": "1:1",
"images": [
"66",
0
],
"model": "Nano Banana 2 (Gemini 3.1 Flash Image)",
"prompt": "Resize this OOH poster to the new aspect ratio. Only move and rescale elements to fit the new format. Maintain all original typography, colors, graphics, logos, and visual hierarchy exactly as they are. No design changes.",
"resolution": "2K",
"response_modalities": "IMAGE",
"seed": 521333244527813,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.",
"thinking_level": "HIGH"
},
"_meta": {
"title": "Nano Banana 2"
}
},
"252:264": {
"class_type": "GeminiNanoBanana2",
"inputs": {
"aspect_ratio": "auto",
"images": [
"66",
0
],
"model": "Nano Banana 2 (Gemini 3.1 Flash Image)",
"prompt": [
"252:132",
0
],
"resolution": "2K",
"response_modalities": "IMAGE",
"seed": 188565245405213,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.",
"thinking_level": "HIGH"
},
"_meta": {
"title": "Nano Banana 2"
}
}
})
# Replace each example.com URL with a public URL of your file.
workflow.set_input("66", "image", client.assets.from_url("https://example.com/replace-with-a-url/image"))
workflow.set_input("128", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_2"))
workflow.set_input("142", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_3"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)常见问答
You can do either. Use IMAGE ENVIRONMENT with LoadImage to supply a real location photo, or use PROMPT ENVIRONMENT if you want GeminiImage2Node to turn your plain-language description into scene notes and file-name context. You can switch between paths with the provided switches.
STEP 1 reformats by resizing and padding/cropping according to the PrimitiveNode dimensions you set, driven by toggles in PrimitiveBoolean and routing via ComfySwitchNode. This preserves your design while producing standard OOH-friendly canvases (vertical, horizontal, square, or custom).
They handle the OOH placement step: warping the selected poster to match the billboard plane and blending it into the scene. Use their UI controls to fine-tune perspective (corner/scale/rotation) and the blend for a realistic result.
Yes. Enable the formats you want with the PrimitiveBoolean switches in STEP 1. Then, in STEP 2, connect those outputs to your chosen environment path. BatchImagesNode and SaveImage will export a consistent set of mockups in one run.