2013年12月7日土曜日

Windows での画像ファイルの読み書き(2)

画像の読み込みで、IWICFormatConverter を使用して画素フォーマットを変換する例です。

画像を読み込んだ直後の IWICBitmapFrameDecode 上の画素フォーマット、たとえば色空間や画素のビット数などは、画像ファイル形式に依存します。前エントリの Chrysanthemum.jpg は BGR 各 8ビットのフォーマットでしたが、たとえば png などの画像では異なるフォーマットになり、画素値を取り出す方法も異なります。ですが多くの場合、画素の表現は画像ファイル形式によらず一定の表現を使いたい場合が多いと思います。

そのような場合、IWICFormatConverter で所望のフォーマットに変換できます。

コード例は以下になります。ポイントは、IWICBitmapFrameDecode から画素を取り出すのではなく、 さらにIWICFormatConverter を介する点です。IWICFormatConverter の Initialize() メソッドで所望のフォーマットを指定します。この際、さらにフォーマット変換処理内容についていくつかパラメタを指定できます。

#include <wincodec.h> // Windows Imaging Component。windowscodecs.lib もリンクが必要。
#include <iostream>

HRESULT GetPixelsFromImageFileWithConversionTo24bppBGR(LPCWSTR imageFileName, UINT *puiWidth, UINT *puiHeight, BYTE **ppcbBuffer)
{
 IWICImagingFactory *pFactory = NULL; // ファクトリ。デコーダを生成。
 IWICBitmapDecoder *pDecoder = NULL;  // デコーダ。画像ファイルからのフレーム取得に使用。
 IWICBitmapFrameDecode *pFrame = NULL; // フレーム。画像一枚を格納。
 IWICFormatConverter *pConverter = NULL; // コンバータ。目的のフォーマットに変換。
 
 HRESULT hr = S_OK;
 if(SUCCEEDED(hr))
 {
  // ファクトリの生成。
  hr = CoCreateInstance(
      CLSID_WICImagingFactory,
      NULL,
      CLSCTX_INPROC_SERVER,
      IID_IWICImagingFactory,
      (LPVOID*)&pFactory
    );
 }
 
 if(SUCCEEDED(hr))
 {
  // デコーダの生成。ファイル名からデコーダを判別して生成。
  hr = pFactory->CreateDecoderFromFilename(
      imageFileName,
      NULL,
      GENERIC_READ,
      WICDecodeMetadataCacheOnDemand,
      &pDecoder
    );
 }
 
 if(SUCCEEDED(hr))
 {
  // 一枚目のフレームを取得。
  hr = pDecoder->GetFrame(0, &pFrame);
 }
 
 if(SUCCEEDED(hr))
 {
  // コンバータの生成。ファイル名からデコーダを判別して生成。
  hr = pFactory->CreateFormatConverter(&pConverter);
 }
 
 if(SUCCEEDED(hr))
 {
  // コンバータの初期化。
  hr = pConverter->Initialize(
   pFrame,
   GUID_WICPixelFormat24bppBGR, // フォーマット指定
   WICBitmapDitherTypeNone,  // ディザリング指定
   NULL,       // パレット指定
   0.f,       // α スレッショルド
   WICBitmapPaletteTypeMedianCut // パレットトランスレーション
   );
 }
 
 WICPixelFormatGUID guidPixelFormat = GUID_WICPixelFormat24bppBGR;
 if(SUCCEEDED(hr))
 {
  // フォーマット情報を取得。
  hr = pConverter->GetPixelFormat(&guidPixelFormat);
 }
 
 if(SUCCEEDED(hr))
 {
  // フォーマットが 24ビット BGR (1色8ビット) か検査。
  if(guidPixelFormat != GUID_WICPixelFormat24bppBGR)
  {
   hr = E_FAIL;
  }
 }
 
 if(SUCCEEDED(hr))
 {
  // 画像の幅、高さを取得。
  hr = pConverter->GetSize(puiWidth, puiHeight);
 }
 
 if(SUCCEEDED(hr))
 {
  // 画素の領域を確保。
  *ppcbBuffer = new BYTE[*puiWidth * *puiHeight * 3];
  if(*ppcbBuffer == NULL)
  {
   hr = E_FAIL;
  }
 }
 
 if(SUCCEEDED(hr))
 {
  // 画素を取得。
  hr = pConverter->CopyPixels(NULL, (*puiWidth * 3), (*puiWidth * *puiHeight * 3), *ppcbBuffer);
 }
 
 if(FAILED(hr))
 {
  // エラーが発生した場合は、画素の領域を解放。
  if(*ppcbBuffer)
  {
   delete [] *ppcbBuffer;
  }
  *ppcbBuffer = NULL;
 }

 // ファクトリ、デコーダ、フレームの解放。
 if(pFactory)
 {
  pFactory->Release();
 }
 
 if(pDecoder)
 {
  pDecoder->Release();
 }

 if(pFrame)
 {
  pFrame->Release();
 }

 if(pConverter)
 {
  pFrame->Release();
 }
 
 return hr;
}

0 件のコメント:

コメントを投稿