Search code examples
directxtexturesdxgi

how to convert dx10 dds image to png using DirectXTex


I've been working with DirectXTex tools and was wondering if is possible to use texconv.exe backwards, to convert DDS -> TGA (or other supported format) instead of TGA, BMP, PNG -> DDS. To convert PNG image to DDS can be done like this:

texconv -f <DXGI_FORMAT> source.png

I am looking for something like this:

texconv source.dds output.png

Or is there anything able to do it ?


Solution

  • The DirectXTex library can certainly convert a DDS to another image format like PNG. Remember that the DDS file format is capable of encoding every possible Direct3D resource type and DXGI_FORMAT, but PNG is not.

    If the source.dds in this case is a single image (i.e. no mipmaps, no arrays, no cube maps, not a volume map) and the format of the source.dds is a DXGI-equivalent of one of the supported WIC pixel formats for PNG, then this works:

    texconv source.dds -ft png
    

    Likely if it's encoded as a DX10 extended header, it's not a WIC pixel format equivalent that's supported by the PNG codec, so you need to provide a conversion format. Something like:

    texconv source.dds -ft png -f R8G8B8A8_UNORM
    

    If source.dds has mipmaps, then those can easily be stripped out by using:

    texconv source.dds -m 1 -ft png -f R8G8B8A8_UNORM
    

    If the source.dds is a cubemap or a texture array, the problem is that png can't encode multiple images. You can get it to write as a TIFF which does support multi-image as:

    texconv source.dds -m 1 -ft tif -f R8G8B8A8_UNORM
    

    I realized that the current behavior of the WIC writer to default to using multi-frame encoding is inconsistent with the behavior of the TGA and HDR writers which always write the first image. I added new behavior in this commit so that the WIC writer also defaults to writing just the first image unless you use -wicmulti. This will be in the next binary release, but currently you need to sync the master branch and build it yourself to get this new behavior.

    With the new version, to get a multiframe write you'd use texconv source.dds -m 1 -ft tif -f R8G8B8A8_UNORM -wicmulti. If you just want the first image, you can use texconv source.dds -ft png -f R8G8B8A8_UNORM. This also removes the need to explicitly use -m 1 in the case where you just want the first image written.

    When dealing with cubemaps, you can make use of the texassemble tool to convert it to a strip or a cross single image:

    texassemble h-strip source.dds -o output.png -f R8G8B8A8_UNORM
    

    If the source.dds is written using a DXGI_FORMAT_*_SRGB format, then when it writes a PNG it will encode the sRGB chunk to indicate the colorspace. This might or might not result in the expected appearance. You can explicitly convert it to a non-SRGB format (which is what will happen above), you can keep it in the sRGB colorspace by using -f R8G8B8A8_UNORM_SRGB, or you can use the -srgbi or -srgbo switches to 'cast' it to/from an sRGB format without changing the data.

    If source.dds is a High-Dynamic Range texture (i.e. R32G32B32A32_FLOAT or the like), then the resulting image might get blown-out converting it to R8G8B8A8_UNORM. You can use the -tonemap switch in this case.

    See Texconv and Texassemble for more details.