Tiling DXT1 texture with mipmaps
- Input
- disturb_dxt1_mip.dds, 174,904 bytes, 512×512 DXT1, 10 mip levels.
- Output
- 423,771-byte RGBA PNG of the top level in 0.9 s; alpha is 255 everywhere.
DDS → PNG pulls the full-size picture out of a GPU texture so you can view or edit it, leaving the smaller mip levels behind.
From real runs
| Element | Result | What happens |
|---|---|---|
| Block-compressed formats | Kept | DXT1, DXT3, DXT5, BC5, BC6H and BC7 textures from the three.js examples and Pillow's test set all decoded; the PNG holds what the GPU would sample, block artefacts included. |
| Mip levels | Lost | Only the largest level is exported: a 512×512 DXT1 texture with 10 mip levels gave one 512×512 PNG. |
| Cubemap faces | Lost | A 786,560-byte cubemap holding six 512×512 faces produced a PNG of the first face only; the result carries a warning that the other five were not converted. |
| Alpha in DXT3, DXT5 and BC7 | Kept | The DXT5 explosion sprite kept its smooth alpha falloff (87,536 → 77,480 bytes), and the DXT3 plant kept its cut-out leaves. |
| DXT1 opacity | Changed | DXT1 always decodes with an alpha channel, so an opaque texture still becomes an RGBA PNG: 423,771 bytes for the 512×512 sample, about 7 percent more than RGB would need. |
| BC5 normal maps | Changed | BC5 stores only the red and green channels; the PNG's blue channel is 0 everywhere, so a tool expecting a three-channel normal map has to rebuild Z. |
| BC6H HDR | Changed | BC6H half-float values are clipped to 8 bits per channel, so anything brighter than white in a lighting or sky texture is lost. |
DXT1, DXT3, DXT5, BC5, BC6H and BC7 textures from the three.js examples and Pillow's test set all decoded; the PNG holds what the GPU would sample, block artefacts included.
Only the largest level is exported: a 512×512 DXT1 texture with 10 mip levels gave one 512×512 PNG.
A 786,560-byte cubemap holding six 512×512 faces produced a PNG of the first face only; the result carries a warning that the other five were not converted.
The DXT5 explosion sprite kept its smooth alpha falloff (87,536 → 77,480 bytes), and the DXT3 plant kept its cut-out leaves.
DXT1 always decodes with an alpha channel, so an opaque texture still becomes an RGBA PNG: 423,771 bytes for the 512×512 sample, about 7 percent more than RGB would need.
BC5 stores only the red and green channels; the PNG's blue channel is 0 everywhere, so a tool expecting a three-channel normal map has to rebuild Z.
BC6H half-float values are clipped to 8 bits per channel, so anything brighter than white in a lighting or sky texture is lost.
We converted our DirectDraw Surface (DDS) sample (281 KB) with Image engine on 2026-10-20. It took 1.3 s and produced a 283 KB PNG file, about the same size as the input. The engine raised 1 warning, listed below.
Input · sample.dds · 281 KB
288,128 bytes
Output · sample.png · 283 KB
480 × 600 px, 8-bit, colour type 6
texconv (DirectXTex, Windows)
texconv -ft png -o out texture.ddsReads every DXGI format, including ones Pillow does not. Add -y to overwrite existing files.
GIMP
File → Open texture.dds (tick Load mipmaps in the DDS dialog) → File → Export As → texture.pngGIMP's DDS import can load mip levels and cubemap faces as layers, which is the way to get at faces we do not export.
Python (Pillow)
from PIL import Image
Image.open("texture.dds").save("texture.png")Pillow reads only the top mip level and the first face. Upgrade to Pillow 11.3 or later before using it to write DDS files.
The HTTP API and the MCP server run the exact engine this page uses (Image engine); the response carries the same warnings the web converter shows. Check support first with GET /api/v1/pairs?from=dds&to=png.
curl -X POST https://filetypeconverters.com/api/v1/convert \
-H "Authorization: Bearer $FTC_API_KEY" \
-F "file=@input.dds" -F "from=dds" -F "to=png" \
-F 'options={"width":0}' \
--output output.png| Key | Applies to | Type | Default |
|---|---|---|---|
| width | Writing PNG | number | 0 |
| height | Writing PNG | number | 0 |
| fit | Writing PNG | contain · cover · fill | contain |
| quality | Writing PNG | number | 90 |
| background | Writing PNG | string | #ffffff |
| stripMetadata | Writing PNG | boolean | true |
The largest one, level 0. Smaller levels in the chain are generated by the tool that made the DDS and are usually not worth keeping, since any texture tool can rebuild them.
It is a BC5 texture, which stores only X and Y. The game computes Z in the shader. Your PNG shows the stored channels; to see a familiar blue normal map, rebuild Z in an image editor or keep using BC5-aware tools.
No new loss. DDS block compression is already lossy, and the PNG stores the decoded result exactly. BC6H is the exception: its HDR range is clipped to ordinary 8-bit colour.