Nodes/AM VFX Tools/AM Reformat
ComfyUI Node

AM Reformat

The resize node that thinks like a compositor

By am-pipeline-prod·Created 4 months ago·Updated 3 months ago· 3
AM Reformat
  • image
  • mask
  • video
  • image
  • mask
  • width
  • height
  • info
  • video
reformat_modeoff
scale1.00
presetWidth/Height
target_width1920
target_height1080
resize_typefit
filtercubic
output_dtypefp16
show_previewtrue

Stock ComfyUI has an ImageScale node. AM Reformat is not that. It's the resize node for people who've reformatted a shot in Nuke or Flame: fit vs. fill vs. crop vs. distort, named broadcast presets, five real pixel filters, and alpha that stays honest through the whole thing. If you're building video pipelines where frames have to land at exactly 1920×1080 or 2048×1556, you'll use this constantly.

It's part of comfyui-am-vfx-tools ("AM VFX Tools" category), Adrian Meyer's 13-node VFX toolkit. The reformat core (_core/reformat.py) is on the hot path of every I/O node in the pack - AM Read Image, AM Write Image, AM Read/Write Video all carry a reformat step - so this is the same engine, exposed standalone.

How it works

OpenCV-backed, four-channel-aware. Three modes:

  • off - passthrough.
  • scale - uniform scale by a factor (0.01–16), output is round(input × scale).
  • to_box - hit a target W×H from a preset or target_width/target_height.

In to_box you also pick how the input maps into the box: width/height (scale to that edge), fit (letterbox), fill (crop the overflow), distort (stretch, changes aspect), or none (no scale, center it). Presets run from HD 1920×1080 through 2K DCI 2048×1080, 4K DCI, and squares.

The detail that shows the VFX thinking: cropped-away and padded regions come out transparent, not black. A 3-channel source gets promoted to RGBA with alpha 0 in the dead areas, so downstream compositing stays clean instead of you discovering black bars in your alpha later.

The filters matter more than you think

Five filters, and the tooltips are worth reading before you pick:

  • impulse - nearest-neighbor. Exact pixels, for masks.
  • linear - bilinear, cheap and smooth.
  • cubic - bicubic, the safe default.
  • Lanczos4 - sharpest, for final stills.
  • area - mean pooling, the right choice for downscaling.

The one people miss: cubic and Lanczos overshoot. Their convolution kernels have negative lobes, so a bright pixel next to a dark edge produces values below the source minimum - sometimes negative. The pack clamps that ringing (only the overshoot, not your legit scene-linear highlights), and it does it because a negative pixel fed into a video model's VAE encode decodes as splotchy firefly artifacts. That's a real, specific failure mode this node prevents by construction.

Inputs and outputs

image, optional mask (reformatted in lockstep with the image, auto-resized to match if dimensions differ), and optional video (lazy per-frame resize). Outputs: image, mask, width, height, a one-line info summary, and video. There's also an output_dtype (fp32/fp16) - fp16 is the default and saves half the memory, but if a downstream node assumes fp32, flip it back.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/am-pipeline-prod/comfyui-am-vfx-tools.git
cd comfyui-am-vfx-tools
pip install -r requirements.txt

Restart ComfyUI, or search comfyui-am-vfx-tools in ComfyUI Manager. The pip line is what pulls in OpenCV headless (the reformat engine), OpenImageIO, OpenColorIO, and PyAV.

Where people get burned

Choosing distort when you meant fill - it stretches the image and changes the aspect, which is almost never what you want. And remember the transparent padding: if you chain a node that assumes RGB after a fit or none reformat, a 4-channel tensor might trip it up. That's the pack's convention doing its job, not a bug.

CategoryAM VFX Tools

Inputs (12)

NameTypeDefaultDescription
reformat_modeCOMBOoffReformat mode. off = bypass, output matches input. scale = uniform scale by `scale` (other widgets ignored). to_box = resize/crop to a target W×H from `preset` or `target_width`/`target_height`.
scaleFLOAT1.000.01–16Uniform scale factor. Used when `reformat_mode=scale`; ignored otherwise. Output dimensions are round(input × scale).
presetCOMBOWidth/HeightNamed output format. Used when `reformat_mode=to_box`. `Width/Height` = use the `target_width` / `target_height` widgets below. Any other entry overrides those widgets with the preset's resolution.
target_widthINT19201–16384Target output width in pixels. Used when `reformat_mode=to_box` AND `preset=Width/Height`; ignored when a named preset is selected.
target_heightINT10801–16384Target output height in pixels. Used when `reformat_mode=to_box` AND `preset=Width/Height`; ignored when a named preset is selected.
resize_typeCOMBOfitHow input maps into the target box. Used when `reformat_mode=to_box`. width/height = scale uniformly to match that edge. fit = scale to fit inside the box (letterbox; black where the box exceeds the scaled image). fill = scale to cover the box (crops the overflow). distort = scale W and H independently to exactly match the box (changes aspect). none = no scale; place input centered in the box (crop if larger, pad if smaller). Cropped-away/padded regions are TRANSPARENT — RGB sources are promoted to RGBA with alpha=0 in the padded area so downstream compositing is clean.
filterCOMBOcubicPixel filter for resampling. impulse = nearest-neighbor (mask passes, exact pixel preservation). linear = bilinear (cheap, smooth). cubic = bicubic (default; the safe Nuke-equivalent). Lanczos4 = sharpest; for high-quality stills / final delivery. area = best for downscaling — anti-aliased mean pooling, softer but artifact-free.
output_dtypeCOMBOfp16Output tensor dtype. fp32 = ComfyUI default (4 bytes/sample). fp16 = half memory + half VRAM (2 bytes/sample). EXR-native precision; fits the [0,1] LDR + scene-linear range with headroom up to ~65504. Some downstream nodes assume fp32 — flip back to fp32 if you hit dtype errors.
show_previewBOOLEANtrueShow a thumbnail of the reformatted result on the node.
imageoptIMAGEImage batch to reformat (N×H×W×C float).
maskoptMASKOptional MASK input (N×H×W float in [0,1]). MASK CONVENTION (stock ComfyUI): mask = 1 - alpha white (1.0) = 'area to inpaint' (source was transparent) black (0.0) = 'keep' (source was opaque) empty mask = all zeros (source has no alpha = fully visible) This is the SD-inpainting convention every stock ComfyUI mask-using node expects (LoadImage, MaskComposite, SetLatentNoiseMask, ImpactPack mask pipeline, etc.). Drop-in compatible with all of them. If you want NUKE-STYLE natural alpha (mask = alpha, where 1.0 = opaque), wire a MaskInvert node between this socket and your downstream consumer. When wired, the same geometric reformat is applied to the mask in lockstep with the image. Mismatched mask dimensions are auto-resized (cubic) to the image's H,W before reformat.
videooptVIDEOOptional VIDEO input. When wired, returns a lazy `ReformatVideo` wrapper applying the resize per-frame on consumption — no IMAGE materialisation here. Alpha (when present) is resized alongside the image. `image` and `mask` are ignored when `video` is wired. See invariant 28.

Outputs (6)

NameTypeDescription
imageIMAGEReformatted image batch (N×H×W×3, dtype per `output_dtype`).
maskMASKReformatted MASK (N×H×W float in [0,1]). MASK CONVENTION (stock ComfyUI): mask = 1 - alpha white (1.0) = 'area to inpaint' (source was transparent) black (0.0) = 'keep' (source was opaque) empty mask = all zeros (source has no alpha = fully visible) This is the SD-inpainting convention every stock ComfyUI mask-using node expects (LoadImage, MaskComposite, SetLatentNoiseMask, ImpactPack mask pipeline, etc.). Drop-in compatible with all of them. If you want NUKE-STYLE natural alpha (mask = alpha, where 1.0 = opaque), wire a MaskInvert node between this socket and your downstream consumer. Sources, in priority order: 1. The wired `mask` input (post-reformat geometry). 2. Extracted from a 4-channel IMAGE input's alpha (mask = 1 - alpha). 3. Empty mask (zeros) — IMAGE was 3-channel with no MASK wired.
widthINTOutput width in pixels (post-reformat).
heightINTOutput height in pixels (post-reformat).
infoSTRINGOne-line summary of the reformat applied.
videoVIDEOLazy VIDEO output — emits a `ReformatVideo` wrapper when `video` is wired, else a zero-copy `VideoFromComponents` around the IMAGE batch. None when no input is wired.