ComfyUI Node

Save DDS for games

PNG is for sharing, DDS is for shipping

By kaanyalova·Created 2 years ago·Updated 2 years ago· 6
Save DDS for games
  • images
    filename_prefixComfyUI
    dds_compressionnone
    generate_mipmapsfalse
    sidecar_formatjson

    If you're making textures for a game - diffuse maps, normal maps, UI sprites for Unity, a mod for whatever you're modding - the PNG your sampler hands you is the wrong final format. Engines want DDS (DirectDraw Surface), the container DirectX, Unity and Unreal all crunch natively, with compression already baked in. That's the one job this node does. The pack calls it "Save DDS for games" on the graph, and the name is honest: it takes your IMAGE tensor, writes a .dds file to your ComfyUI output folder, and - because DDS has no slot for ComfyUI's prompt/workflow metadata - drops a sidecar file next to it so you don't lose the "workflow included" convention.

    The rest of the ExtendedImageFormats pack is about web-friendly formats. This node is the game-dev corner, and for anyone shipping textures it's the reason to install the pack at all.

    How it works

    The node converts each image in the batch to a numpy array and hands it to imageio to write the .dds. imageio sneaks into most ComfyUI installs as a transitive dependency (video nodes pull it in), so it usually just works without extra setup. On top of the write, it serializes the prompt and workflow JSON into a sidecar file, so image_00001_.dds gets an image_00001.json (or .xmp) sitting right beside it in the same folder.

    The inputs that matter

    • dds_compression - none (uncompressed, enormous), bc1 (DXT1: RGB color, no alpha, ~4× smaller), bc3 (DXT5: color plus 8-bit alpha), bc5 (two-channel, the one for normal maps).
    • generate_mipmaps - true/false. Mipmaps are pre-built, downsampled copies so the GPU picks the right LOD by distance instead of shimmering. Engines can generate them on import, but baking them in is the professional move.
    • sidecar_format - json or xmp for the metadata, since DDS can't hold it internally.
    • filename_prefix - same idea as the stock Save Image; files land in ComfyUI/output/prefix_00001_.dds.

    There are no outputs to wire forward - it's a sink node. Output appears in the folder and in the results panel.

    How to install it

    This is one of two nodes in the Extended Image Formats pack, so you install both together. Easiest route is ComfyUI Manager: search "Extended Image Formats" and hit install. Or the manual way:

    cd ComfyUI/custom_nodes
    git clone https://github.com/kaanyalova/ComfyUI_ExtendedImageFormats
    

    Then restart ComfyUI. The pack's requirements.txt only pulls in pillow-avif-plugin and jxlpy, which are for the sibling Extended Save node's avif/jxl formats - DDS itself needs nothing beyond imageio, which is already there in practice.

    Where people get burned

    • DDS can't embed workflow metadata, so the .json sidecar is the only record of your graph. Keep the pair together or you lose the workflow forever. This is the node's one real quirk, and it's why the sidecar option exists.
    • Normal maps should be bc5. BC1 on a normal map is a recipe for garbage seams and color fringing. A "washed out" normal map is usually wrong compression, not a broken node.
    • none compression means uncompressed. Expect dozens of MB per texture. Anything you actually ship should be bc1 or bc3.
    • If the save throws about imageio, pip install imageio into your venv and restart - that's almost always the fix.

    One honest note: DDS output is niche. If you're not targeting a DirectX-style engine pipeline, you don't need this node, and the pack's other node (Extended Save) covers the formats most people actually want. But the day you need a BC5 normal map your engine will import without recompressing, this is the node you'll reach for.

    Categoryimage

    Inputs (5)

    NameTypeDefaultDescription
    imagesIMAGE
    filename_prefixSTRINGComfyUI
    dds_compressionCOMBOnone4 options: none, bc1, bc3, bc5
    generate_mipmapsCOMBOfalse2 options: true, false
    sidecar_formatCOMBOjson2 options: json, xmp

    Outputs (0)

    No outputs