2014年2月1日土曜日

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

Windows Imaging Component での画像の書き込みです。

画像ファイルから画素を取得するまでの簡単な流れは以下となります。

  1. IWICImaginFactory オブジェクトの生成
  2. IWICImaginFactory オブジェクトからのエンコーダの生成
  3. IWICImaginFactory オブジェクトからの書き込み先ストリームの生成
  4. ストリーム、エンコーダの初期化
  5. エンコーダからのフレームの生成
  6. フレームの画像サイズ、フォーマットを設定、画素を書き込み
  7. フレーム、エンコーダの書き込み完了

コードを以下に記載します。本コードではフォーマットを固定(GUID_WICPixelFormat24bppBGR)にしていますが、異なるフォーマットで書き込む場合は対応したフォーマットを指定すればよいと思います。

フォーマットは以下の URL にまとめられていますが、本当にたくさんサポートされていますね。 http://msdn.microsoft.com/en-us/library/windows/desktop/ee719797(v=vs.85).aspx

以下のコードの GetPixelsFromImageFileWithConversionTo24bppBGR() は前のエントリの関数です。以下コードで jpg を読んで、png を書くことができると思います。

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

HRESULT PutPixelsToImageFile(LPCWSTR imageFileName, UINT uiWidth, UINT uiHeight, BYTE *pcbBuffer)
{
 IWICImagingFactory *pFactory = NULL;    // ファクトリ。エンコーダを生成。
 IWICBitmapEncoder *pEncoder = NULL;     // エンコーダ。画素データを書き込む。
 IWICStream *pStream = NULL;             // ストリーム。書き込み先を指定。
 IWICBitmapFrameEncode *pFrame = NULL;   // フレーム。画素データ。
 
 HRESULT hr = 0;
 if(SUCCEEDED(hr))
 {
  // ファクトリを生成。
  hr = CoCreateInstance(
   CLSID_WICImagingFactory1,
   NULL,
   CLSCTX_INPROC_SERVER,
   IID_IWICImagingFactory,
   (LPVOID*)&pFactory
   );
 }
 
 // ファイルフォーマットを指定。この例ではビットマップ。
 GUID guid = GUID_ContainerFormatBmp;
 
 if(SUCCEEDED(hr))
 {
  // エンコーダを生成。
  hr = pFactory->CreateEncoder(guid, NULL, &pEncoder);
 }

 if(SUCCEEDED(hr))
 {
  // ストリームを生成。
  hr = pFactory->CreateStream(&pStream);
 }
 
 if(SUCCEEDED(hr))
 {
  // ストリームを初期化。
  hr = pStream->InitializeFromFilename(imageFileName, GENERIC_WRITE);
 }
 
 if(SUCCEEDED(hr))
 {
  // エンコーダを初期化。
  hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
 }
 
 if(SUCCEEDED(hr))
 {
  // フレームを生成。
  hr = pEncoder->CreateNewFrame(&pFrame, NULL);
 }
 
 if(SUCCEEDED(hr))
 {
  // フレームを初期化。
  hr = pFrame->Initialize(0);
 }
 
 if(SUCCEEDED(hr))
 {
  // フレームのサイズを設定。
  hr = pFrame->SetSize(uiWidth, uiHeight);
 }
 
 if(SUCCEEDED(hr))
 {
  // 画素フォーマットを設定。
  GUID guidPixelFormat = GUID_WICPixelFormat24bppBGR;
  hr = pFrame->SetPixelFormat(&guidPixelFormat);
 }
 
 if(SUCCEEDED(hr))
 {
  // 画素を書き込み。
  hr = pFrame->WritePixels(uiHeight, uiWidth * 3, uiHeight * uiWidth * 3, pcbBuffer);
 }
 
 if(SUCCEEDED(hr))
 {
  // フレームへの書込みを完了。
  hr = pFrame->Commit();
 }
 
 if(SUCCEEDED(hr))
 {
  // ファイルへの書き込みを完了。
  hr = pEncoder->Commit();
 }
 
 if (pFactory)
 {
  pFactory->Release();
 }
 if (pEncoder)
 {
  pEncoder->Release();
 }
 if (pStream)
 {
  pStream->Release();
 }
 if (pFrame)
 {
  pFrame->Release();
 }

 return hr;
}

int main(int argc, char* argv[])
{
 CoInitialize(NULL);

 LPCWSTR imageFile = L"C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg";
 LPCWSTR imageOutFile = L"C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.png";
 UINT uiWidth = 0, uiHeight = 0;
 BYTE *pcbBuffer = NULL;
 HRESULT hr = GetPixelsFromImageFileWithConversionTo24bppBGR(imageFile, &uiWidth, &uiHeight, &pcbBuffer);
 if(SUCCEEDED(hr))
 {
  PutPixelsToImageFile(imageOutFile, uiWidth, uiHeight, pcbBuffer);
 }

 if(pcbBuffer)
 {
  delete [] pcbBuffer;
 }

 CoUninitialize();

 return 0;
}