Today プラグインサンプルプログラム3 †Today プラグインサンプルプログラム2では、背景を透過して、文字を書いてみました。 というわけで、ただ表示するだけでは面白くないので、α(アルファ/透明度)の情報を持ったPNG画像を、背景上にBlendして表示してみましょう。 具体的には、以下のような画像を用意し、数字を背景上に描画します。 絵じゃなくて字じゃん!というツッコミはなしでw ファイルパス作成 †まずは、読み込む画像ファイルのフルパスを作る必要があります。 今回は、DLLと同じところに画像ファイルを置きます。 自分自身のパスを得るには、DllMainの第1引数を指定して、GetModuleFileNameをコールします。 実際に画像ファイルのパスを作りたい時には、このDLLのパスをベースに、ファイル名を入れ替えればいい事になります。 // パス作成
bool CApp::makePath( LPTSTR path, LPCTSTR fname )
{
int len = 0;
int len2 = 0;
int i = 0;
if( NULL == path || NULL == fname ){
return false;
}
if( NULL == ::lstrcpy( path, m_dllPath )){
return false;
}
len = ::lstrlen( path );
len2 = ::lstrlen( fname );
if( 0 >= len || 0 >= fname ){
return false;
}
if( MAX_PATH < len + len2 + 1 ){
return false;
}
for( i = 0; i < len; i++ ){
if( TEXT( '\\' ) == path[len-i-1] ){
break;
}
}
if( i == len ){
return false;
}
if( NULL == ::lstrcpy( path + len - i, fname )){
return false;
}
return true;
}
DIBSection †PNGファイルをロードする前に、ロードした画像を保存しておく領域が必要です。 今回は、ロード用のDIBSectionだけではなく、今まで表画面との互換性を持った状態だった裏画面もDIBSectionにします。 裏画面はそのまま表画面へと転送するので、透明度を持つ必要はなく、24bitのRGB。 ただし、今まで裏画面は表画面との互換性があるものを作成していましたが、固定で24bitのものとすることにより、裏画面と表画面の形式が異なってしまいます。 まぁ、ゲーム等の頻繁に画面の書き換えが発生するような用途の場合には、このあたりを考慮してやり方を工夫する必要があると思いますが、必要なときに必要なところだけ書き換えればいいようなTodayアイテムであれば、あまり気にしなくてもいいでしょう。 DIBSection作成処理は、以下のような感じです。 // DIBセクション作成
bool CDIBSection::create( HWND hwnd, int width, int height, int cbit )
{
HDC hdc = NULL; // Windowデバイスコンテキストハンドル
destroy();
// デバイスコンテキストの作成
hdc = ::GetDC( hwnd );
if( NULL == hdc ){
goto Error;
}
m_hdc = CreateCompatibleDC( hdc );
if( NULL == m_hdc ){
goto Error;
}
// BITMAPINFOHEADER構造体の初期化
ZeroMemory( &m_bi, sizeof( m_bi ));
m_bi.biSize = sizeof( m_bi );
m_bi.biWidth = width;
m_bi.biHeight = height;
m_bi.biPlanes = 1;
m_bi.biBitCount = cbit;
m_bi.biCompression = BI_RGB;
m_bi.biSizeImage = 0;
m_bi.biXPelsPerMeter = 0;
m_bi.biYPelsPerMeter = 0;
m_bi.biClrUsed = 0;
m_bi.biClrImportant = 0;
// DIBSectionの作成
m_hBitmap = CreateDIBSection( m_hdc, ( LPBITMAPINFO )&m_bi, DIB_RGB_COLORS, ( LPVOID* )&m_dibmem, NULL, 0 );
if( NULL == m_hBitmap ){
goto Error;
}
// ビットマップの関連付け
m_hOldBitmap = SelectBitmap( m_hdc, m_hBitmap );
if( NULL == m_hOldBitmap ){
goto Error;
}
if( hdc ){
::ReleaseDC( hwnd, hdc );
hdc = NULL;
}
return true;
Error:
destroy();
if( hdc ){
::ReleaseDC( hwnd, hdc );
hdc = NULL;
}
return false;
}
IImagingFactory †透明度付きの画像をロードするには、SHLoadImageFileではなく、COMのIImagingFactoryを使用しなければならないようです。 CoInitializeExとCoUninitializeはペアで呼び出す必要があり、スレッドに対して呼び出す必要があります。 このため、COMの初期化/解放は、Windowに同期して行うようにします。 画像データは、本来であればリソースとして、Dllのプロセスアタッチ時にロードして、何回Windowが作り直されたとしても、使い回しが出きるべきですが、今回はCOMをWindowに同期させて初期化するため、アタッチ時にはCOMがなく、ロードが出来ません。 COMからPNGファイルをロードして保持する手順としては、CoCreateInstanceでCLSID_ImagingFactoryを指定してIImagingFactoryを取得し、画像ファイルのパスを指定してIImageを取得します。 この辺りのソース的な流れは以下のような感じです。 // イメージロード
bool CTodayWnd::loadImage( HWND hwnd, LPCDIBSection lpCDib, LPCTSTR path )
{
IImagingFactory *lpImageFactory = NULL; // ImagingFactoryインターフェイスへのポインタ
IImage *lpImage = NULL; // Imageインターフェイスへのポインタ
ImageInfo imageInfo; // 画像情報
RECT rect; // 描画矩形
bool ret = false; // 戻り値
// ImagingFactoryインスタンス生成
if( S_OK != ::CoCreateInstance( CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, ( LPVOID* )&lpImageFactory )){
goto Error;
}
if( NULL == lpImageFactory ){
goto Error;
}
// 画像ファイル読み込み
if( S_OK != lpImageFactory->CreateImageFromFile( path, &lpImage )){
goto Error;
}
if( NULL == lpImage ){
goto Error;
}
// 画像情報取得
ZeroMemory( &imageInfo, sizeof( imageInfo ));
if( S_OK != lpImage->GetImageInfo( &imageInfo )){
goto Error;
}
// DIBセクション作成
if( !lpCDib->create( hwnd, &imageInfo )){
goto Error;
}
// DIBセクションに描画
ZeroMemory( &rect, sizeof( rect ));
rect.right = imageInfo.Width;
rect.bottom = imageInfo.Height;
if( S_OK != lpImage->Draw( m_digital.getDC(), &rect, NULL )){
goto Error;
}
ret = true;
Error:
if( NULL != lpImage ){
lpImage->Release();
lpImage = NULL;
}
if( NULL != lpImageFactory ){
lpImageFactory->Release();
lpImageFactory = NULL;
}
return ret;
}
色深度は、ImageInfoのPixelFormatの、PixelFormatAlphaが立っている場合は透過画像なので32bitのDIBSectionを、立っていない場合は非透過画像なので、24bitのDIBSectionを作るようにします。 |