わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。

Direct2Dでgifファイルの描画を行う

Direct2Dは、画像はビットマップしか描画できません。gifファイルを描画する為には、 gifファイルから、ID2D1Bitmapに変換する必要があります。

gifファイルからID2D1Bitmapへの変換には、WICを利用します。WICのIWICImagingFactory::CreateDecoderFromFilename()メソッドを使うと、 ファイルからBitmapへ変換するためのデコーダーを取得することができるので、取得したデコーダーのパラメータを設定するとこで、 ID2D1HwndRenderTarget::CreateBitmapFromWicBitmap()関数でgifファイルから、ID2D1Bitmapに変換することができます。

アニメーションgifも描画できます。アニメーションgifの場合は複数フレームあるので、IWICBitmapDecoder::GetFrameCount()メソッドでフレームの枚数が取得できます。 IWICBitmapDecoder::GetFrame()メソッドの第一引数に取得したいフレームを指定します。

サンプルでは、毎回ファイルからID2D1Bitmapに変換してから描画を行っていますが、 ID2D1Bitmapへの変換は、WM_PAINTの外で行って、WM_PAINTの中で変換済みのID2D1Bitmapを利用するようにすれば描画速度を向上できます。

#include <stdio.h>
#include <tchar.h>
#include <locale.h>
#include <iostream>
#include <windows.h>
#include <d2d1.h>
#include <wincodec.h>
#include <wincodecsdk.h>



// lib
#pragma comment( lib, "d2d1.lib" )
#pragma comment( lib, "WindowsCodecs.lib" )



/*
	メインウインドウイベント処理
*/
LRESULT CALLBACK eMainWindowProc(
	  HWND	 hwnd	// handle to window
	, UINT	 uMsg	// message identifier
	, WPARAM wParam // first message parameter
	, LPARAM lParam // second message parameter
);



// グローバル変数
IWICImagingFactory* pWICImagingFactory = NULL;
ID2D1Factory* pD2d1Factory = NULL;
ID2D1HwndRenderTarget* pRenderTarget = NULL;



/*
	Direct2Dでgifを描画する
*/
int _tmain
(
	  int argc
	, _TCHAR* argv[]
)
{
	// std::wcoutのロケールを設定
	std::wcout.imbue( std::locale( "", std::locale::ctype ) );

	// COM初期化
	::CoInitialize( NULL );

	WNDCLASSEX tWndClass;
	HINSTANCE  hInstance;
	TCHAR*	   cpClassName;
	TCHAR*	   cpWindowName;
	TCHAR*	   cpMenu;
	HWND	   hWnd;
	MSG		   tMsg;


	// アプリケーションインスタンス
	hInstance	 = ::GetModuleHandle( NULL );

	// クラス名称
	cpClassName	 = _T("MainWindowClass");

	// メニュー
	cpMenu		 = MAKEINTRESOURCE( NULL );

	// ウインドウ名称
	cpWindowName = _T("Direct2Dでgifを描画");

	// ウインドウクラスパラメータセット
	tWndClass.cbSize		= sizeof( WNDCLASSEX );
	tWndClass.style			= CS_HREDRAW | CS_VREDRAW;
	tWndClass.lpfnWndProc	= eMainWindowProc;
	tWndClass.cbClsExtra	= 0;	// ::GetClassLong で取得可能なメモリ
	tWndClass.cbWndExtra	= 0;	// ::GetWindowLong で取得可能なメモリ
	tWndClass.hInstance		= hInstance; 
	tWndClass.hIcon			= ::LoadIcon( NULL, IDI_APPLICATION );
	tWndClass.hCursor		= ::LoadCursor( NULL, IDC_ARROW );
	tWndClass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
	tWndClass.lpszMenuName	= cpMenu;
	tWndClass.lpszClassName = cpClassName;
	tWndClass.hIconSm		= NULL;

	// ウインドウクラス生成
	if ( 0 == ::RegisterClassEx( &tWndClass ) ) {

		/* 失敗 */
		return( -1 );
	}

	// ウインドウを生成する
	hWnd = ::CreateWindowEx (
		  0						  // extended window style
		, tWndClass.lpszClassName // pointer to registered class name
		, cpWindowName			  // pointer to window name
		, WS_OVERLAPPEDWINDOW	  // window style
		, CW_USEDEFAULT			  // horizontal position of window
		, CW_USEDEFAULT			  // vertical position of window
		, 640					  // window width
		, 480					  // window height
		, NULL					  // handle to parent or owner window
		, NULL					  // handle to menu, or child-window identifier
		, hInstance				  // handle to application instance
		, (VOID*)0x12345678		  // pointer to window-creation data
	);


	/*
		メッセージループ
	*/
	while( 0 != ::GetMessage( &tMsg, NULL, 0, 0 ) ) {
		::TranslateMessage ( &tMsg );
		::DispatchMessage ( &tMsg );
	}

	// COM初期化
	::CoUninitialize();

	// WM_QUITの終了コードを返却する
	return( tMsg.wParam );
}



/*
	メインウインドウイベント処理
*/
LRESULT CALLBACK eMainWindowProc
(
	  HWND	 hWnd	// handle to window
	, UINT	 uMsg	// message identifier
	, WPARAM wParam // first message parameter
	, LPARAM lParam // second message parameter
)
{
	switch( uMsg ) {
	case WM_CREATE:
	//--------------------------------------------
	// WM_CREATE
	//--------------------------------------------
		{
			CREATESTRUCT* tpCreateSt = (CREATESTRUCT*)lParam;

			/* パラメータ表示 */
			wprintf(
				L"CREATESTRUCT¥n"
				L"¥tlpCreateParams = 0x%08x¥n"
				L"¥thInstance	   = 0x%08x¥n"
				L"¥thMenu		   = 0x%08x¥n"
				L"¥thwndParent	   = 0x%08x¥n"
				L"¥tcy			   = %d¥n"
				L"¥tcx			   = %d¥n"
				L"¥ty			   = %d¥n"
				L"¥tx			   = %d¥n"
				L"¥tstyle		   = 0x%08x¥n"
				L"¥tlpszName	   = ¥"%s¥"¥n"
				L"¥tlpszClass	   = ¥"%s¥"¥n"
				L"¥tdwExStyle	   = 0x%08x¥n"
				, tpCreateSt->lpCreateParams
				, tpCreateSt->hInstance
				, tpCreateSt->hMenu
				, tpCreateSt->hwndParent
				, tpCreateSt->cy
				, tpCreateSt->cx
				, tpCreateSt->y
				, tpCreateSt->x
				, tpCreateSt->style
				, tpCreateSt->lpszName
				, tpCreateSt->lpszClass
				, tpCreateSt->dwExStyle
			);

			HRESULT hResult = S_OK;


			/*
				IWICImagingFactoryの生成
			*/
			hResult = ::CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void **>( &pWICImagingFactory ) );
			if ( FAILED( hResult ) ) {

				// エラー
				std::wcout << L"CoCreateInstance失敗" << std::endl;
				break;
			}
			

			/*
				ID2D1Factoryの生成
			*/
			hResult = ::D2D1CreateFactory( D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2d1Factory );
			if ( FAILED( hResult ) ) {

				// エラー
				std::wcout << L"D2D1CreateFactory失敗" << std::endl;
				break;
			}


			/*
				ID2D1HwndRenderTargetの生成
			*/
			{
				D2D1_SIZE_U oPixelSize = {
					  tpCreateSt->cx
					, tpCreateSt->cy
				};

				D2D1_RENDER_TARGET_PROPERTIES oRenderTargetProperties = D2D1::RenderTargetProperties();

				D2D1_HWND_RENDER_TARGET_PROPERTIES oHwndRenderTargetProperties = D2D1::HwndRenderTargetProperties( hWnd, oPixelSize );


				/*
					ID2D1HwndRenderTargetの生成
				*/
				hResult = pD2d1Factory->CreateHwndRenderTarget(
						  oRenderTargetProperties
						, oHwndRenderTargetProperties
						, &pRenderTarget
					);
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"CreateHwndRenderTarget失敗" << std::endl;
					break;
				}
			}

			// ウインドウを表示する
			::ShowWindow( hWnd, SW_SHOW );
		}
		break;


	case WM_DESTROY:
	//--------------------------------------------
	// WM_DESTROY
	//--------------------------------------------
		{
			// ID2D1HwndRenderTargetの破棄
			if ( NULL != pRenderTarget )  {
				pRenderTarget->Release();
			}

			// ID2D1Factoryの破棄
			if ( NULL != pD2d1Factory )  {
				pD2d1Factory->Release();
			}

			// |WICImagingFactoryの破棄
			if ( NULL != pWICImagingFactory ) {
				pWICImagingFactory->Release();
			}

			// 終了する( 引数はそのまま終了コードとなります )
			::PostQuitMessage( 0 );
		}
		break;


	case WM_SIZE:
	//--------------------------------------------
	// WM_SIZE
	//--------------------------------------------
		{
			D2D1_SIZE_U oPixelSize = { LOWORD( lParam ), HIWORD( lParam ) };

			// ターゲットリサイズ
			pRenderTarget->Resize( &oPixelSize );
		}
		break;


	case WM_ERASEBKGND:
	//--------------------------------------------
	// WM_ERASEBKGND
	//--------------------------------------------
		{
			;
		}
		return( TRUE );


	case WM_PAINT:
	//--------------------------------------------
	// WM_PAINT
	//--------------------------------------------
		{
			HRESULT hResult = S_OK;

			// ターゲットサイズの取得
			D2D1_SIZE_F oTargetSize = pRenderTarget->GetSize();

			// 描画開始
			PAINTSTRUCT tPaintStruct;
			::BeginPaint( hWnd, &tPaintStruct );

			// 描画開始(Direct2D)
			pRenderTarget->BeginDraw();

			// 背景のクリア
			D2D1_COLOR_F oBKColor = { 1.0f, 1.0f, 1.0f, 1.0f };
			pRenderTarget->Clear( oBKColor );


			/*
				Gifの描画
			*/
			{
				IWICBitmapDecoder* pWICBitmapDecoder = NULL;
				IWICBitmapFrameDecode* pWICBitmapFrame = NULL;
				IWICFormatConverter* pFormatConverter = NULL;
				ID2D1Bitmap* pBitmap = NULL;


				/*
					デコーダ生成( File to Bitmap )
				*/
				hResult = pWICImagingFactory->CreateDecoderFromFilename(
						  L".¥¥TestData¥¥anime.gif"
						, NULL
						, GENERIC_READ
						, WICDecodeMetadataCacheOnLoad
						, &pWICBitmapDecoder
					);
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"CreateDecoderFromFilename失敗" << std::endl;
					goto err;
				}

				// フレームの数
				UINT qFrameCount = 0;

				// フレームの数を取得
				hResult = pWICBitmapDecoder->GetFrameCount( &qFrameCount );
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"GetFrameCount失敗" << std::endl;
					goto err;
				}
				std::wcout << L"フレーム数 = " << qFrameCount << std::endl;


				/*
					ビットマップのフレーム取得(最終フレーム)
				*/
				hResult = pWICBitmapDecoder->GetFrame( qFrameCount - 1, &pWICBitmapFrame );
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"GetFrame失敗" << std::endl;
					goto err;
				}
				

				/*
					フォーマットコンバータ生成
				*/
				hResult = pWICImagingFactory->CreateFormatConverter( &pFormatConverter );
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"CreateFormatConverter失敗" << std::endl;
					goto err;
				}


				/*
					フォーマットコンバータ初期化
				*/
				hResult = pFormatConverter->Initialize(
							  pWICBitmapFrame					// BitmapSource
							, GUID_WICPixelFormat32bppPBGRA		// ピクセルフォーマット
							, WICBitmapDitherTypeNone			// BitmapDitherType
							, NULL								// バレット
							, 1.0f								// 透過率
							, WICBitmapPaletteTypeMedianCut		// パレットタイプ
						);
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"Initialize失敗" << std::endl;
					goto err;
				}


				/*
					BitmapSource -> Bitmapへ変換
				*/
				hResult = pRenderTarget->CreateBitmapFromWicBitmap( pFormatConverter, NULL, &pBitmap );
				if ( FAILED( hResult ) ) {

					// エラー
					std::wcout << L"CreateBitmapFromWicBitmap失敗" << std::endl;
					goto err;
				}


				/*
					Bitmapの描画
				*/
				{
					// ビットマップのサイズを取得
					D2D1_SIZE_F tBitmapSize = pBitmap->GetSize(); 

					D2D_POINT_2F tLeftTop = D2D1::Point2F(
							  ( oTargetSize.width  - tBitmapSize.width  ) / 2
							, ( oTargetSize.height - tBitmapSize.height ) / 2
						);

					// 描画矩形(画面中央)
					D2D1_RECT_F oDrawRect = D2D1::RectF(
							  tLeftTop.x						// left
							, tLeftTop.y						// top
							, tLeftTop.x + tBitmapSize.width	// right
							, tLeftTop.y + tBitmapSize.height	// bottom
						);

					// Bitmapの描画
					pRenderTarget->DrawBitmap( pBitmap, oDrawRect );
				}

err:
				// IBitmapの破棄
				if( NULL != pBitmap ) {
					pBitmap->Release();
				}

				// IFormatConverterの破棄
				if ( NULL != pFormatConverter ) {
					pFormatConverter->Release();
				}

				// IWICBitmapFrameの破棄
				if( NULL != pWICBitmapFrame ) {
					pWICBitmapFrame->Release();
				}

				// IWICBitmapDecoderの破棄
				if( NULL != pWICBitmapDecoder ) {
					pWICBitmapDecoder->Release();
				}
			}

			// 描画終了(Direct2D)
			pRenderTarget->EndDraw();

			// 描画終了
			::EndPaint( hWnd, &tPaintStruct );
		}
		return( FALSE );
	}

	// デフォルト処理呼び出し
	return ::DefWindowProc( hWnd, uMsg, wParam, lParam );
}



実行結果






わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。