Windows Imaging Componentで画像を読み込む

Windows Imaging Component (WIC)は、.NET Framework 3.0でも利用されている画像処理のフレームワークで、Vistaでは標準インストールされており、Windows フォトギャラリーなどでも利用されているほか、Windows XPでも、.NET Framework 3.5をインストールしたり、または、WICを直接インストールしたり、あるいは、Windows Live フォトギャラリーをインストールしたりすることによって利用できるようになる。

また、Windows Imaging Componentは、サードパーティによって拡張可能なように設計されており、実際、カメラメーカーからは、RAW画像用のコーデックが公開されていたりもするため、今後、画像処理のコードを書くに当たっては、是非とも利用を検討したいフレームワークだ。

C++からだと、GDI+を使って画像を読み込むことは結構あると思うが、GDI+の画像ローダはバグも多く、Old JPEGなどの比較的難しいフォーマットは読めないことが多い。それから比べると、WICの完成度はかなりのもので、特に何の問題も感じずに利用することができる。.NETからであれば、BitmapDecoder クラスを使って画像のロードを行えるが、C++/CLIではなく、C++から使いたい場合には、COM経由で利用できる。その際、ほとんどのクラスは、IWIC + .NETのクラス名という形で存在している。下記は、利用例(エラーチェックは省いているので注意)。

CComPtr<IWICImagingFactory> imagingFactory;
CoCreateInstance(
  CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
  __uuidof(IWICImagingFactory), (LPVOID*)&imagingFactory);

// input.tifを開く
CComPtr<IStream> stream;
SHCreateStreamOnFile(_T("input.tif"), STGM_READ, &stream);

imagingFactory->CreateDecoderFromStream(
  stream, NULL, WICDecodeMetadataCacheOnDemand, &m_decoder);

UINT frameCount = 0;
m_decoder->GetFrameCount(&frameCount);
for(UINT idx = 0; idx < frameCount; idx++)
{
  CComPtr<IWICBitmapFrameDecode> frameDecode;
  m_decoder->GetFrame(idx, &frameDecode);

  UINT width, height;
  frameDecode->GetSize(&width, &height);

  double resX, resY;
  frameDecode->GetResolution(&resX, &resY);
  
  CComQIPtr<IWICBitmapSource> bmpSrc = frameDecode;

  WICPixelFormatGUID fmt;
  bmpSrc->GetPixelFormat(&fmt);
  
  UINT stride;
  if(fmt == GUID_WICPixelFormatBlackWhite)
  {
    stride = (w + 7) ~7;
  }
  else if(fmt == GUID_WICPixelFormat8bppGray)
  {
    stride = w;
  }
  else if(fmt == GUID_WICPixelFormat24bppBGR)
  {
    stride = w * 3;
  }
  else if(fmt == GUID_WICPixelFormat24bppRGB)
  {
    stride = w * 3;
  }
  else
  {
    // Unsupported pixel format
  }
  
  UINT size = stride * height;
  BYTE* buf = new BYTE[size];
  WICRect rc = {0, 0, width, height};
  HRESULT hr = bmpSrc->CopyPixels(&rc, stride, size, buf);
  
  ...
    
  delete[] buf;
}