2011-07-23

freeimage + DDS ( nvidia texture tools )

前段時間遇到一個需求是把 bmp, png 轉成 dds 格式,且在過程中自動把 bmp, png 的圖形放大到二的冪次方大小。 

後來使用兩套工具解決這個需求:
  • Freeimage 來做圖檔的讀取工具,
  • nvidia 提供的 texture tools 來做圖檔的格式轉換及壓縮工具,
freeimage library 提供方便快速的圖形讀取和寫入功能,但對(DirectX Surface)DDS 格式的支援只有到讀取的程度,致使無法儲存 DDS 格式檔案。texture tools 則是提供簡單的圖檔讀取及完整的 DDS 檔案格式支援,其 DDS 支援的部分剛好可以補足 freeimage 在支援 DDS 格式不足之處。

底下為把圖片轉成 DDS 格式的簡單實作:

1) 載入圖檔  (src.jpg):
std::string filename("src.jpg");
FREE_IMAGE_FORMAT fif =FreeImage_GetFileType( filename.c_str() );
FIBITMAP* dib =NULL;
dib = FreeImage_Load( fif, filename.c_str() );

2) 將圖檔轉成 RGBA 32bit 格式:
FIBITMAP* dib32 = FreeImage_ConvertTo32Bits(dib);

3) 取得圖形資料:
int nWidth =FreeImage_GetWidth(dib);
int nHeight =FreeImage_GetHeight(dib);
BYTE* pSrcDIB =FreeImage_GetBits(dib32);

4) 設定欲壓縮的圖形資料格式
nvtt::InputOptions inputOptions;
inputOptions.setTextureLayout(nvtt::TextureType_2D, nWidth, nHeight);
inputOptions.setMipmapData(pSrcDIB, nWidth, nHeight);
inputOptions.setFormat(nvtt::InputFormat_BGRA_8UB);

inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
inputOptions.setAlphaMode(nvtt::AlphaMode_Transparency);

inputOptions.setNormalMap(false);
inputOptions.setConvertToNormalMap(false);
inputOptions.setGamma(2.2f, 2.2f);
inputOptions.setNormalizeMipmaps(false);

inputOptions.setMipmapGeneration(false);

5) 設定 DDS 檔格式,此處使用的是 DXT1a 格式
nvtt::CompressionOptions compressionOptions;
compressionOptions.setFormat(nvtt::Format_DXT1a);
//compressionOptions.setQuality(nvtt::Quality_Fastest);
//compressionOptions.setQuality(nvtt::Quality_Normal);
//compressionOptions.setQuality(nvtt::Quality_Production);
compressionOptions.setQuality(nvtt::Quality_Highest);

6) 壓縮並儲存成 DDS 檔 (dst.dds):
nvtt::OutputOptions outputOptions;
outputOptions.setFileName("dst.dds");

nvtt::Compressor compressor;
compressor.enableCudaAcceleration(false);
compressor.process(inputOptions, compressionOptions, outputOptions);

7) 最後不忘刪除記憶體:
FreeImage_Unload(dib32);
FreeImage_Unload(dib);