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 );
}
