Expand Image
Extend your image by filling in the surrounding scene.
查看工作流内部
源模板的只读预览。在 Cloud 中打开,即可查看节点并进行修改。
Loading the graph
Open full-size workflow preview- 输出
- 图像
- 作者
- Rob
从代码中调用该模型
以下请求使用与体验区相同的预设图和设置。每次提交都可能开始一次付费运行;如果提交结果未知,请勿自动重试。
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({
"130": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"262": {
"class_type": "ImageCompare",
"inputs": {
"compare_view": {
"__value__": [
"",
""
]
},
"image_a": [
"302",
0
],
"image_b": [
"264",
0
]
},
"_meta": {
"title": "Compare Images"
}
},
"264": {
"class_type": "ImageResizeKJv2",
"inputs": {
"crop_position": "center",
"device": "cpu",
"divisible_by": 2,
"height": [
"265",
1
],
"image": [
"303",
0
],
"keep_proportion": "stretch",
"pad_color": "0, 0, 0",
"upscale_method": "lanczos",
"width": [
"265",
0
]
},
"_meta": {
"title": "Resize Image v2"
}
},
"265": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"280:175",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"276": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"291",
0
],
"on_true": [
"283",
0
],
"switch": False
},
"_meta": {
"title": "Automatic Outpaint Caption"
}
},
"277": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"276",
0
]
},
"_meta": {
"title": "Caption Preview"
}
},
"278": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "\n",
"string_a": "Outpaint/fill the solid green pixels with new image content that seamlessly continues the scene. DO NOT modify the original non-green pixels — they must remain exactly as they are. Do not copy/paste existing pixels into the green area. The new content must blend seamlessly in lighting, color, perspective, and detail. The green region should be replaced with:",
"string_b": [
"277",
0
]
},
"_meta": {
"title": "Assemble Outpaint Prompt"
}
},
"279": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"298",
0
]
},
"_meta": {
"title": "Final Prompt"
}
},
"283": {
"class_type": "TextGenerateLTX2Prompt",
"inputs": {
"clip": [
"285",
0
],
"image": [
"303",
0
],
"max_length": 400,
"mtp": "auto",
"prompt": [
"297",
0
],
"sampling_mode": "on",
"sampling_mode.min_p": 0.05,
"sampling_mode.presence_penalty": 0,
"sampling_mode.repetition_penalty": 1.05,
"sampling_mode.seed": 123456789,
"sampling_mode.temperature": 0.7,
"sampling_mode.top_k": 64,
"sampling_mode.top_p": 0.95,
"thinking": False,
"use_default_template": True
},
"_meta": {
"title": "Generate Prompt"
}
},
"285": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "qwen3.5_4b_bf16.safetensors",
"device": "default",
"type": "stable_diffusion"
},
"_meta": {
"title": "CLIP Loader"
}
},
"291": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": "Ochre adobe walls with peeling plaster continue on both sides, a shuttered window with a wrought-iron grille on the left, terracotta pots of red geraniums along the base of the wall on the right, and the cobbled street running on in bright morning sun."
},
"_meta": {
"title": "Manual Caption (describe the expanded region)"
}
},
"292": {
"class_type": "CustomCombo",
"inputs": {
"choice": "Centered"
},
"_meta": {
"title": "Image Position"
}
},
"293": {
"class_type": "JsonExtractString",
"inputs": {
"json_string": "{\"Image at Start (Left / Top)\": \"0\", \"Image at 1/3 (Rule of Thirds)\": \"33\", \"Centered\": \"50\", \"Image at 2/3 (Rule of Thirds)\": \"67\", \"Image at End (Right / Bottom)\": \"100\"}",
"key": [
"292",
0
]
},
"_meta": {
"title": "Position % (JSON)"
}
},
"294": {
"class_type": "JsonExtractString",
"inputs": {
"json_string": "{\"Image at Start (Left / Top)\": \"Placement: the original photograph sits flush at the LEFT edge of the final frame; all new content extends to the RIGHT of the visible scene.\", \"Image at 1/3 (Rule of Thirds)\": \"Placement: the original photograph sits left of center; a narrow band of new content extends to the LEFT and a wider area extends to the RIGHT.\", \"Centered\": \"Placement: the original photograph is centered; new content extends equally to the LEFT and to the RIGHT.\", \"Image at 2/3 (Rule of Thirds)\": \"Placement: the original photograph sits right of center; a wider area of new content extends to the LEFT and a narrow band extends to the RIGHT.\", \"Image at End (Right / Bottom)\": \"Placement: the original photograph sits flush at the RIGHT edge of the final frame; all new content extends to the LEFT of the visible scene.\"}",
"key": [
"292",
0
]
},
"_meta": {
"title": "Placement Phrase (Horizontal)"
}
},
"295": {
"class_type": "JsonExtractString",
"inputs": {
"json_string": "{\"Image at Start (Left / Top)\": \"Placement: the original photograph sits flush at the TOP edge of the final frame; all new content extends BELOW the visible scene.\", \"Image at 1/3 (Rule of Thirds)\": \"Placement: the original photograph sits above center; a narrow band of new content extends ABOVE and a wider area extends BELOW.\", \"Centered\": \"Placement: the original photograph is centered; new content extends equally ABOVE and BELOW.\", \"Image at 2/3 (Rule of Thirds)\": \"Placement: the original photograph sits below center; a wider area of new content extends ABOVE and a narrow band extends BELOW.\", \"Image at End (Right / Bottom)\": \"Placement: the original photograph sits flush at the BOTTOM edge of the final frame; all new content extends ABOVE the visible scene.\"}",
"key": [
"292",
0
]
},
"_meta": {
"title": "Placement Phrase (Vertical)"
}
},
"296": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"295",
0
],
"on_true": [
"294",
0
],
"switch": [
"224:255",
2
]
},
"_meta": {
"title": "Placement Phrase (axis auto-selected)"
}
},
"297": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "\n\n",
"string_a": "You are writing a scene-continuation description for an image outpainting model. The flat solid green area in this image is a placeholder that will be replaced with new scenery extending the photograph. Study the visible non-green content — the space, surfaces, objects, materials, lighting, colors, and perspective — and describe in 2-4 sentences exactly what should appear in that area as a natural continuation of the scene.\n\nBe concrete and specific: name the surfaces that extend (floor, walls, ceiling, sky, ground) with their materials, patterns, and colors; any furniture or objects that would plausibly continue or appear; the light direction, temperature, and shadows; and the depth and perspective as the scene recedes.\n\nWrite ONLY the description of the new content itself, as if captioning a photograph of that area. Never mention \"green\", \"region\", \"placeholder\", \"pixels\", \"image\", or the editing process. Never use instructional phrasing like \"should contain\" or \"must match\". Start directly with the content — for example: \"A continuation of the terracotta tiled floor, its beige grout lines receding toward a plaster wall washed in warm lamplight...\"",
"string_b": [
"296",
0
]
},
"_meta": {
"title": "Caption Instruction + Placement"
}
},
"298": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "\n",
"string_a": [
"278",
0
],
"string_b": [
"296",
0
]
},
"_meta": {
"title": "Final Prompt + Placement"
}
},
"299": {
"class_type": "ComfyNumberConvert",
"inputs": {
"value": [
"293",
0
]
},
"_meta": {
"title": "Convert Number (% -> INT)"
}
},
"302": {
"class_type": "SaveImageAdvanced",
"inputs": {
"filename_prefix": "Qwen-2511-outpaint",
"format": "png",
"format.bit_depth": "8-bit",
"format.input_color_space": "sRGB",
"images": [
"280:175",
0
]
},
"_meta": {
"title": "Save Image (Advanced)"
}
},
"303": {
"class_type": "SaveImageAdvanced",
"inputs": {
"filename_prefix": "Qwen-2511-outpaint_region",
"format": "png",
"format.bit_depth": "8-bit",
"format.input_color_space": "sRGB",
"images": [
"224:249",
0
]
},
"_meta": {
"title": "Save Image (Advanced)"
}
},
"224:191": {
"class_type": "FluxResolutionNode",
"inputs": {
"aspect_ratio": "16:9 (Panorama)",
"custom_aspect_ratio": "1:1",
"custom_ratio": False,
"divisible_by": "8",
"megapixel": "2.1"
},
"_meta": {
"title": "Flux Resolution Calc"
}
},
"224:240": {
"class_type": "PrimitiveInt",
"inputs": {
"value": [
"299",
1
]
},
"_meta": {
"title": "top_or_left_outpaint_pct"
}
},
"224:241": {
"class_type": "ImageResize+",
"inputs": {
"condition": "always",
"height": [
"224:191",
1
],
"image": [
"130",
0
],
"interpolation": "lanczos",
"method": "keep proportion",
"multiple_of": 0,
"width": [
"224:191",
0
]
},
"_meta": {
"title": "🔧 Image Resize"
}
},
"224:242": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "floor((a - b) * (c / 100))",
"values.a": [
"224:191",
0
],
"values.b": [
"224:241",
1
],
"values.c": [
"224:240",
0
]
},
"_meta": {
"title": "pad_left"
}
},
"224:243": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "(a - b) - floor((a - b) * (c / 100))",
"values.a": [
"224:191",
0
],
"values.b": [
"224:241",
1
],
"values.c": [
"224:240",
0
]
},
"_meta": {
"title": "pad_right"
}
},
"224:244": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "floor((a - b) * (c / 100))",
"values.a": [
"224:191",
1
],
"values.b": [
"224:241",
2
],
"values.c": [
"224:240",
0
]
},
"_meta": {
"title": "pad_top"
}
},
"224:245": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "(a - b) - floor((a - b) * (c / 100))",
"values.a": [
"224:191",
1
],
"values.b": [
"224:241",
2
],
"values.c": [
"224:240",
0
]
},
"_meta": {
"title": "pad_bottom"
}
},
"224:246": {
"class_type": "ImagePadForOutpaint",
"inputs": {
"bottom": [
"224:245",
1
],
"feathering": 0,
"image": [
"224:241",
0
],
"left": [
"224:242",
1
],
"right": [
"224:243",
1
],
"top": [
"224:244",
1
]
},
"_meta": {
"title": "Pad Image for Outpainting"
}
},
"224:247": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"224:246",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"224:248": {
"class_type": "EmptyImage",
"inputs": {
"batch_size": 1,
"color": 65280,
"height": [
"224:247",
1
],
"width": [
"224:247",
0
]
},
"_meta": {
"title": "Empty Image"
}
},
"224:249": {
"class_type": "ImageCompositeMasked",
"inputs": {
"destination": [
"224:246",
0
],
"mask": [
"224:246",
1
],
"resize_source": False,
"source": [
"224:248",
0
],
"x": 0,
"y": 0
},
"_meta": {
"title": "Image Composite Masked"
}
},
"224:255": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "a - b",
"values.a": [
"224:191",
0
],
"values.b": [
"224:241",
1
]
},
"_meta": {
"title": "has_horizontal_slack"
}
},
"280:152": {
"class_type": "CFGNorm",
"inputs": {
"model": [
"280:155",
0
],
"pre_cfg": False,
"strength": 1
},
"_meta": {
"title": "CFGNorm"
}
},
"280:155": {
"class_type": "ModelSamplingAuraFlow",
"inputs": {
"model": [
"280:166",
0
],
"sampling": "flow",
"shift": 3.1
},
"_meta": {
"title": "ModelSamplingAuraFlow"
}
},
"280:156": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "qwen_image_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"280:161": {
"class_type": "TextEncodeQwenImageEditPlus",
"inputs": {
"clip": [
"280:167",
0
],
"image1": [
"280:176",
0
],
"prompt": [
"279",
0
],
"vae": [
"280:156",
0
]
},
"_meta": {
"title": "TextEncodeQwenImageEditPlus (Positive)"
}
},
"280:162": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "Qwen-Image-Edit-2511-Lightning-4steps-V1.0-bf16.safetensors",
"model": [
"280:152",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"280:163": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 4
},
"_meta": {
"title": "CFG"
}
},
"280:164": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 1
},
"_meta": {
"title": "CFG"
}
},
"280:165": {
"class_type": "VAEEncode",
"inputs": {
"pixels": [
"280:176",
0
],
"vae": [
"280:156",
0
]
},
"_meta": {
"title": "VAE Encode"
}
},
"280:166": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "qwen_image_edit_2511_bf16.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"280:167": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
"device": "default",
"type": "qwen_image"
},
"_meta": {
"title": "Load CLIP"
}
},
"280:168": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"280:152",
0
],
"on_true": [
"280:162",
0
],
"switch": [
"280:171",
0
]
},
"_meta": {
"title": "Switch (Model)"
}
},
"280:169": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 6
},
"_meta": {
"title": "Steps"
}
},
"280:170": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 30
},
"_meta": {
"title": "Steps"
}
},
"280:171": {
"class_type": "PrimitiveBoolean",
"inputs": {
"value": True
},
"_meta": {
"title": "Enable 4steps LoRA?"
}
},
"280:172": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"280:163",
0
],
"on_true": [
"280:164",
0
],
"switch": [
"280:171",
0
]
},
"_meta": {
"title": "Switch (CFG)"
}
},
"280:173": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"280:170",
0
],
"on_true": [
"280:169",
0
],
"switch": [
"280:171",
0
]
},
"_meta": {
"title": "Switch (Steps)"
}
},
"280:174": {
"class_type": "KSampler",
"inputs": {
"cfg": [
"280:172",
0
],
"denoise": 1,
"latent_image": [
"280:165",
0
],
"model": [
"280:168",
0
],
"negative": [
"280:229",
0
],
"positive": [
"280:161",
0
],
"sampler_name": "euler",
"scheduler": "simple",
"seed": 927215755554477,
"steps": [
"280:173",
0
]
},
"_meta": {
"title": "KSampler"
}
},
"280:175": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"280:174",
0
],
"vae": [
"280:156",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"280:176": {
"class_type": "FluxKontextImageScale",
"inputs": {
"image": [
"303",
0
]
},
"_meta": {
"title": "FluxKontextImageScale"
}
},
"280:229": {
"class_type": "TextEncodeQwenImageEditPlus",
"inputs": {
"clip": [
"280:167",
0
],
"image1": [
"280:176",
0
],
"prompt": "",
"vae": [
"280:156",
0
]
},
"_meta": {
"title": "Text Encode Qwen Image Edit Plus"
}
}
})
workflow.set_input("130", "image", client.assets.from_url("https://comfy.org/catalog-media/c6df7625-c30c-4730-9f25-7ef00ee1d5cd/3a3c3a6e-c9ff-4609-a07d-a6c065021249"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)
for output in job.get_outputs("302"):
output.to_file(output.name)试试一个示例
关于此工作流
Expand Image is a guided outpainting workflow that grows a single photo to any target aspect ratio without cropping or distorting the original pixels. It wraps your image in a flat green matte to reach the new canvas size, then uses Qwen Image Edit 2511 to replace only the green area with believable scene continuation. Core utility nodes—GetImageSize, ImageResizeKJv2, CustomCombo, and ComfyNumberConvert—calculate the new dimensions and margins so the source stays centered and untouched while the surrounding frame becomes the editable region.
To keep the new content on-style and on-topic, the workflow can automatically write a scene-continuation caption for the missing region using TextGenerateLTX2Prompt and a local VLM backend (configured by you), then JsonExtractString parses the result. A ComfySwitchNode lets you flip between that auto caption and a manual description you type in PrimitiveStringMultiline. The final instruction is assembled with StringConcatenate and, together with CLIPLoader (for text conditioning when required), guides Qwen Image Edit 2511 to synthesize lighting, materials, and perspective that match the visible photo.
PreviewAny and ImageCompare help you evaluate changes, and SaveImageAdvanced stores the outpainted result and metadata for reproducibility.
常见问答
No. The workflow keeps your source image intact and adds a flat green border to reach the new canvas size. Only that green area is replaced during outpainting.
Set the ComfySwitchNode to Manual and type your continuation description in PrimitiveStringMultiline. You can still get excellent results by describing surfaces, lighting, perspective, and what should extend into the green area.
Be specific in the region description: mention horizon position, floor/wall continuation, materials (brick, marble, foliage), time of day, and color temperature. Keep the prompt grounded in what’s visible. Adjust the base style string and try moderate aspect changes before extreme ones.
GetImageSize + ImageResizeKJv2 (with CustomCombo and ComfyNumberConvert) compute the new canvas and green margins. TextGenerateLTX2Prompt (auto) or PrimitiveStringMultiline (manual) supplies the region description, selected via ComfySwitchNode and assembled with StringConcatenate. CLIPLoader provides text conditioning if required by the edit model.