Programming Windows Maniacs - プログラミング ウィンドウズ マニアックス ■ ご利用に際して ■ 更新履歴 ■ お問い合わせ ■ このホームページについて  
ホーム >> GDI >> ビットマップの背景を透過して描画するには

ビットマップの背景を透過して描画するには

  ビットマップの背景を透過するには、マスク処理を行います。
  背景の上にスプライトを描画したい際の、お決まりの処理です。

  わたしの目的はオーナードローコントロール作成時の基底クラスとしての作成でした。

  背景を透過するには、
        (1) マスクを作成。
        (2) 背景色を黒にしたビットマップ作成。
        (3) マスクをSRCANDで、背景黒ビットマップをSRCPAINTで重ねて描画。
という処理を行います。詳細はコメントも記載していますので、描画クラス TTransparentBitmap のソースコードをご参照ください。

  サンプルは下記になります。"C:\Windows\winnt.bmp"の背景を透過してデスクトップに描画します。


■■■ transparent_bmp プロジェクト
■ stdafx.h


#ifndef _H_YUSU_STDAFX
#define _H_YUSU_STDAFX

#include <windows.h>
#include <tchar.h>

#include "myassert.h"

#endif

■ myassert.h
//----------------------------------------------------------------------
// ASSERT マクロと実装
//----------------------------------------------------------------------
#ifndef _H_YUSU_ASSERT
#define _H_YUSU_ASSERT
//----------------------------------------------------------------------
// ASSERT マクロ定義
#ifndef ASSERT
    #ifdef _DEBUG
        #include <crtdbg.h>
        #define ASSERT(f) \
            _ASSERTE(f)
    #else
        #define ASSERT(f) \
            NULL
    #endif
#endif
//----------------------------------------------------------------------
#endif
■ transparent_bmp.h
//----------------------------------------------------------------------
// 透過ビットマップ 描画クラス
//----------------------------------------------------------------------
#ifndef _H_YUSU_TRANSPARENT_BITMAP
#define _H_YUSU_TRANSPARENT_BITMAP
//----------------------------------------------------------------------
class TTransparentBitmap
{
protected:
// ウィンドウハンドル
    HWND m_hOwnerWnd;
// ビットマップハンドル
    HBITMAP m_hBitmap;
// 透過色
    COLORREF m_clrBackground;

// マスク作成
    HBITMAP CreateMask ( HBITMAP hBitmap );
// 背景色を黒にしたビットマップ作成
    HBITMAP CreateBlackBackgroundBitmap ( HBITMAP hSrcBitmap,
        HBITMAP hMaskBitmap );

// 背景色を黒にしたビットマップ と マスクの組み合わせ描画
    BOOL InternalDraw ( HDC hdc,
        long nX,
        long nY,
        HBITMAP hMaskBitmap,
        HBITMAP hBlackBkgndBitmap,
        DWORD dwMaskRop = SRCAND,
        DWORD dwBlackBkgndRop = SRCPAINT );

// 背景色を黒にしたビットマップ と マスクの組み合わせ伸縮描画
    BOOL InternalDrawStretch ( HDC hdc,
        long nX,
        long nY,
        long nWidth,
        long nHeight,
        HBITMAP hMaskBitmap,
        HBITMAP hBlackBkgndBitmap,
        DWORD dwMaskRop = SRCAND,
        DWORD dwBlackBkgndRop = SRCPAINT );

// コピーコンストラクタ 補助関数
    virtual void InternalCopyConstructor ( void *pvObj );
// 代入演算子 補助関数
    virtual void InternalSubstitutionOperator ( void *pvObj );
public:
// コンストラクタ ( m_hOwnerWnd は NULL 許可 )
    TTransparentBitmap ();
    TTransparentBitmap ( HWND hOwnerWnd );
    TTransparentBitmap ( HWND hOwnerWnd, HBITMAP hBitmap, COLORREF clrBackground );
// デストラクタ
    virtual ~TTransparentBitmap ();
// コピーコンストラクタ
    TTransparentBitmap ( const TTransparentBitmap &obj );
// 代入演算子
    TTransparentBitmap operator = ( const TTransparentBitmap obj );

// ウィンドウハンドル変更
    void SetWindowHandle ( HWND hOwnerWnd );
// ウィンドウハンドル取得
    HWND GetWindowHandle () const;

// ビットマップハンドル アタッチ
    HBITMAP Attach ( HBITMAP hBitmap );
// ビットマップハンドル デタッチ
    HBITMAP Detach ();

// 透過色指定
    void SetBackgroundColor ( COLORREF clrBackground );
// 透過色取得
    COLORREF GetBackgroundColor () const;

// 描画
    virtual BOOL Draw ( long nX, long nY );
// DC指定描画
    virtual BOOL Draw ( HDC hdc, long nX, long nY );

// 伸縮描画
    virtual BOOL DrawStretch ( long nX, long nY, long nWidth, long nHeight );
// DC指定伸縮描画
    virtual BOOL DrawStretch ( HDC hdc, long nX, long nY, long nWidth, long nHeight );

};
//----------------------------------------------------------------------
#endif
■ transparent_bmp.cpp

#include "stdafx.h"

#include "transparent_bmp.h"

//----------------------------------------------------------------------
// protected メンバ
//----------------------------------------------------------------------
// マスク作成
HBITMAP TTransparentBitmap::CreateMask ( HBITMAP hBitmap )
{
    ASSERT ( hBitmap != NULL );

    HBITMAP hMask;
    HDC hSrcDc;
    HDC hDstDc;
    HBITMAP hSrcDcPrevBitmap;
    HBITMAP hDstDcPrevBitmap;

// マスク用ビットマップ入れ物 作成
    BITMAP bm;
    HDC hClientDC = GetDC ( m_hOwnerWnd );
    GetObject ( hBitmap, sizeof ( BITMAP ), &bm );
    hMask = CreateBitmap ( bm.bmWidth,
        bm.bmHeight,
        1,
        1,
        NULL );
    ASSERT ( hMask != NULL );


// 下準備
    hSrcDc = CreateCompatibleDC ( hClientDC );
    hSrcDcPrevBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hSrcDc, hBitmap ) );
    hDstDc = CreateCompatibleDC ( hClientDC );
    hDstDcPrevBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hDstDc, hMask ) );

// 作成
    SetBkColor ( hSrcDc, m_clrBackground );
    BitBlt ( hDstDc,
        0,
        0,
        bm.bmWidth,
        bm.bmHeight,
        hSrcDc,
        0,
        0,
        SRCCOPY );

// 後始末
    SelectObject ( hSrcDc, hSrcDcPrevBitmap );
    DeleteDC ( hSrcDc );
    SelectObject ( hDstDc, hDstDcPrevBitmap );
    DeleteDC ( hDstDc );

    ReleaseDC ( m_hOwnerWnd, hClientDC );
    return hMask;
}

// 背景色を黒にしたビットマップ作成
HBITMAP TTransparentBitmap::CreateBlackBackgroundBitmap ( HBITMAP hSrcBitmap,
    HBITMAP hMaskBitmap )
{
    HDC hdc = GetDC ( m_hOwnerWnd );

    HDC hMaskDC = CreateCompatibleDC ( hdc );
    HBITMAP hOldMaskBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hMaskDC, hMaskBitmap ) );

    BITMAP maskBitmap;
    GetObject ( hMaskBitmap, sizeof ( BITMAP ), &maskBitmap );
    BitBlt ( hMaskDC,
        0,
        0,
        maskBitmap.bmWidth,
        maskBitmap.bmHeight,
        hMaskDC,
        0,
        0,
        NOTSRCCOPY );// マスクを反転します(背景が黒になる)

    HDC hSrcMemDC = CreateCompatibleDC ( hdc );
    HBITMAP hOldSrcBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hSrcMemDC, hSrcBitmap ) );

    // hSrcBitmap をコピーした 作業用 HBITMAP である hBitmap を作成
    HDC hMemDC = CreateCompatibleDC ( hdc );
    HBITMAP hBitmap = CreateCompatibleBitmap ( hdc,
        maskBitmap.bmWidth,
        maskBitmap.bmHeight );
    HBITMAP hOldBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hMemDC, hBitmap ) );
    BitBlt ( hMemDC,
        0,
        0,
        maskBitmap.bmWidth,
        maskBitmap.bmHeight,
        hSrcMemDC,
        0,
        0,
        SRCCOPY );

    // hSrcBitmap 関連を削除 ( hSrcBitmap 以外 )
    SelectObject ( hSrcMemDC, hOldSrcBitmap );
    DeleteDC ( hSrcMemDC );

    // マスク部分黒になるSprite作成
    BitBlt ( hMemDC,
        0,
        0,
        maskBitmap.bmWidth,
        maskBitmap.bmHeight,
        hMaskDC,
        0,
        0,
        SRCAND );

    // マスクを反転します(背景が黒になる)
    BitBlt ( hMaskDC,
        0,
        0,
        maskBitmap.bmWidth,
        maskBitmap.bmHeight,
        hMaskDC,
        0,
        0,
        NOTSRCCOPY );

    SelectObject ( hMaskDC, hOldMaskBitmap );
    SelectObject ( hMemDC, hOldBitmap );

    DeleteDC ( hMaskDC );
    DeleteDC ( hMemDC );

    ReleaseDC ( m_hOwnerWnd, hdc );
    return hBitmap;
}

// 背景色を黒にしたビットマップ と マスクの組み合わせ描画
BOOL TTransparentBitmap::InternalDraw ( HDC hdc,
    long nX,
    long nY,
    HBITMAP hMaskBitmap,
    HBITMAP hBlackBkgndBitmap,
    DWORD dwMaskRop,
    DWORD dwBlackBkgndRop )
{
    ASSERT ( hMaskBitmap != NULL );
    ASSERT ( hBlackBkgndBitmap != NULL );
    if ( hMaskBitmap == NULL || hBlackBkgndBitmap == NULL )
        return FALSE;

// ビットマップの幅、高さ取得
    BITMAP bm;
    int nResult = GetObject ( hMaskBitmap, sizeof ( BITMAP ), &bm );
    ASSERT ( nResult != 0 );
    if ( nResult == 0 )
        return FALSE;

// 作業用として メモリデバイスコンテキスト 作成
    HDC hMemDC = CreateCompatibleDC ( hdc );

    HBITMAP hOldMemBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hMemDC, hMaskBitmap ) );
    BitBlt ( hdc,
        nX,
        nY,
        bm.bmWidth,
        bm.bmHeight,
        hMemDC,
        0,
        0,
        dwMaskRop );

    SelectObject ( hMemDC, hBlackBkgndBitmap );
    BitBlt ( hdc,
        nX,
        nY,
        bm.bmWidth,
        bm.bmHeight,
        hMemDC,
        0,
        0,
        dwBlackBkgndRop );
    SelectObject ( hMemDC, hOldMemBitmap );

// 削除    
    DeleteDC ( hMemDC );
    return TRUE;
}

// 背景色を黒にしたビットマップ と マスクの組み合わせ伸縮描画
BOOL TTransparentBitmap::InternalDrawStretch ( HDC hdc,
    long nX,
    long nY,
    long nWidth,
    long nHeight,
    HBITMAP hMaskBitmap,
    HBITMAP hBlackBkgndBitmap,
    DWORD dwMaskRop,
    DWORD dwBlackBkgndRop )
{
    ASSERT ( hMaskBitmap != NULL );
    ASSERT ( hBlackBkgndBitmap != NULL );
    if ( hMaskBitmap == NULL || hBlackBkgndBitmap == NULL )
        return FALSE;

// ビットマップの幅、高さ取得
    BITMAP bm;
    int nResult = GetObject ( hMaskBitmap, sizeof ( BITMAP ), &bm );
    ASSERT ( nResult != 0 );
    if ( nResult == 0 )
        return FALSE;

// 作業用として メモリデバイスコンテキスト 作成
    HDC hMemDC = CreateCompatibleDC ( hdc );

    HBITMAP hOldMemBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hMemDC, hMaskBitmap ) );
    StretchBlt ( hdc,
        nX,
        nY,
        nWidth,
        nHeight,
        hMemDC,
        0,
        0,
        bm.bmWidth,
        bm.bmHeight,
        dwMaskRop );

    SelectObject ( hMemDC, hBlackBkgndBitmap );
    StretchBlt ( hdc,
        nX,
        nY,
        nWidth,
        nHeight,
        hMemDC,
        0,
        0,
        bm.bmWidth,
        bm.bmHeight,
        dwBlackBkgndRop );
    SelectObject ( hMemDC, hOldMemBitmap );

// 削除    
    DeleteDC ( hMemDC );
    return TRUE;
}



// コピーコンストラクタ 補助関数
void TTransparentBitmap::InternalCopyConstructor ( void *pvObj )
{
    TTransparentBitmap *pObj = static_cast < TTransparentBitmap * > ( pvObj );

    m_hOwnerWnd = pObj->m_hOwnerWnd;
    m_clrBackground = pObj->m_clrBackground;
    // hBitmap が NULL でないとき、同じイメージを作成する
    if ( pObj->m_hBitmap != NULL )
    {
        HDC hdc = GetDC ( m_hOwnerWnd );

        // 元
        HDC hSrcMemDC = CreateCompatibleDC ( hdc );
        HBITMAP hOldSrcBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hSrcMemDC, pObj->m_hBitmap ) );

        // 先
        BITMAP bm;
        GetObject ( pObj->m_hBitmap, sizeof ( BITMAP ), &bm );
        HDC hMemDC = CreateCompatibleDC ( hdc );
        m_hBitmap = CreateCompatibleBitmap ( hdc,
            bm.bmWidth,
            bm.bmHeight );
        HBITMAP hOldBitmap = reinterpret_cast < HBITMAP > ( SelectObject ( hMemDC, m_hBitmap ) );

        // 描画
        BitBlt ( hMemDC,
            0,
            0,
            bm.bmWidth,
            bm.bmHeight,
            hSrcMemDC,
            0,
            0,
            SRCCOPY );

        SelectObject ( hSrcMemDC, hOldSrcBitmap );
        SelectObject ( hMemDC, hOldBitmap );

        // 先 関連 削除
        DeleteDC ( hMemDC );

        // 元 関連 削除
        DeleteDC ( hSrcMemDC );

        ReleaseDC ( m_hOwnerWnd, hdc );
    }
    else
        m_hBitmap = NULL;
    
}
// 代入演算子 補助関数
void TTransparentBitmap::InternalSubstitutionOperator ( void *pvObj )
{
    TTransparentBitmap *pObj = static_cast < TTransparentBitmap * > ( pvObj );

    // すでに hBitmap があるときは 削除
    if ( m_hBitmap != NULL )
        DeleteObject ( m_hBitmap );

    // あとはコピーコンストラクタと同じ
    InternalCopyConstructor ( pObj );
}

//----------------------------------------------------------------------
// public メンバ
//----------------------------------------------------------------------
// コンストラクタ ( m_hOwnerWnd は NULL 許可 )
TTransparentBitmap::TTransparentBitmap ()
: m_hOwnerWnd ( NULL ),
m_hBitmap ( NULL ),
m_clrBackground ( 0 )
{
}

TTransparentBitmap::TTransparentBitmap ( HWND hOwnerWnd )
: m_hOwnerWnd ( hOwnerWnd ),
m_hBitmap ( NULL ),
m_clrBackground ( 0 )
{
}

TTransparentBitmap::TTransparentBitmap ( HWND hOwnerWnd, HBITMAP hBitmap, COLORREF clrBackground )
: m_hOwnerWnd ( hOwnerWnd ),
m_hBitmap ( hBitmap ),
m_clrBackground ( clrBackground )
{
    ASSERT ( m_hBitmap != NULL );
}

// コピーコンストラクタ
TTransparentBitmap::TTransparentBitmap ( const TTransparentBitmap &obj )
{
    InternalCopyConstructor ( const_cast < TTransparentBitmap * > ( &obj ) );
}

// 代入演算子
TTransparentBitmap TTransparentBitmap::operator = ( const TTransparentBitmap obj )
{
    InternalSubstitutionOperator ( const_cast < TTransparentBitmap * > ( &obj ) );
    return *this;
}

// デストラクタ
TTransparentBitmap::~TTransparentBitmap ()
{
    if ( m_hBitmap != NULL )
        DeleteObject ( m_hBitmap );
}

// ウィンドウハンドル変更
void TTransparentBitmap::SetWindowHandle ( HWND hOwnerWnd )
{
    m_hOwnerWnd = hOwnerWnd;
}
// ウィンドウハンドル取得
HWND TTransparentBitmap::GetWindowHandle () const
{
    return m_hOwnerWnd;
}

// ビットマップハンドル アタッチ
HBITMAP TTransparentBitmap::Attach ( HBITMAP hBitmap )
{
    HBITMAP hBitmapBuffer = m_hBitmap;
    m_hBitmap = hBitmap;
    return hBitmapBuffer;
}

// ビットマップハンドル デタッチ
HBITMAP TTransparentBitmap::Detach ()
{
    m_hBitmap = NULL;
    return m_hBitmap;
}

// 透過色指定
void TTransparentBitmap::SetBackgroundColor ( COLORREF clrBackground )
{
    m_clrBackground = clrBackground;
}

// 透過色取得
COLORREF TTransparentBitmap::GetBackgroundColor () const
{
    return m_clrBackground;
}

// 描画
BOOL TTransparentBitmap::Draw ( long nX, long nY )
{
    HDC hdc = GetDC ( m_hOwnerWnd );
    BOOL bResult = Draw ( hdc, nX, nY );
    ReleaseDC ( m_hOwnerWnd, hdc );
    return bResult;
}

// DC指定描画
BOOL TTransparentBitmap::Draw ( HDC hdc, long nX, long nY )
{
    ASSERT ( m_hBitmap != NULL );
    if ( m_hBitmap == NULL )
        return FALSE;

// ビットマップ情報取得
    BITMAP bm;
    GetObject ( m_hBitmap, sizeof ( BITMAP ), &bm );

// マスク作成
    HBITMAP hMaskBitmap = CreateMask ( m_hBitmap );
    ASSERT ( hMaskBitmap != NULL );
    if ( hMaskBitmap == NULL )
        return FALSE;
// 背景色が黒のビットマップ作成
    HBITMAP hBlackBkgndBitmap = CreateBlackBackgroundBitmap ( m_hBitmap, hMaskBitmap );
    ASSERT ( hBlackBkgndBitmap != NULL );
    if ( hBlackBkgndBitmap == NULL )
    {
        DeleteObject ( hMaskBitmap );
        return FALSE;
    }

// 描画
    BOOL bResult = InternalDraw ( hdc,
        nX,
        nY,
        hMaskBitmap,
        hBlackBkgndBitmap );

// 削除    
    DeleteObject ( hBlackBkgndBitmap );
    DeleteObject ( hMaskBitmap );

    return bResult;
}

// 伸縮描画
BOOL TTransparentBitmap::DrawStretch ( long nX, long nY, long nWidth, long nHeight )
{
    HDC hdc = GetDC ( m_hOwnerWnd );
    BOOL bResult = DrawStretch ( hdc,
        nX,
        nY,
        nWidth,
        nHeight );
    ReleaseDC ( m_hOwnerWnd, hdc );
    return bResult;
}

// DC指定伸縮描画
BOOL TTransparentBitmap::DrawStretch ( HDC hdc, long nX, long nY, long nWidth, long nHeight )
{
    ASSERT ( m_hBitmap != NULL );
    if ( m_hBitmap == NULL )
        return FALSE;

// ビットマップ情報取得
    BITMAP bm;
    GetObject ( m_hBitmap, sizeof ( BITMAP ), &bm );

// マスク作成
    HBITMAP hMaskBitmap = CreateMask ( m_hBitmap );
    ASSERT ( hMaskBitmap != NULL );
    if ( hMaskBitmap == NULL )
        return FALSE;
// 背景色が黒のビットマップ作成
    HBITMAP hBlackBkgndBitmap = CreateBlackBackgroundBitmap ( m_hBitmap, hMaskBitmap );
    ASSERT ( hBlackBkgndBitmap != NULL );
    if ( hBlackBkgndBitmap == NULL )
    {
        DeleteObject ( hMaskBitmap );
        return FALSE;
    }

// 描画
    BOOL bResult = InternalDrawStretch ( hdc,
        nX,
        nY,
        nWidth,
        nHeight,
        hMaskBitmap,
        hBlackBkgndBitmap );

// 削除    
    DeleteObject ( hBlackBkgndBitmap );
    DeleteObject ( hMaskBitmap );

    return bResult;
}

■ main.cpp

#include "stdafx.h"

#include "transparent_bmp.h"

int WINAPI _tWinMain ( HINSTANCE hThisInstance,
    HINSTANCE,
    _TCHAR *,
    int )
{

// "C:\\Windows\\winnt.bmp" を読み込む
    HBITMAP hBitmap;
    hBitmap = reinterpret_cast < HBITMAP > ( LoadImage ( hThisInstance,
        _TEXT ( "C:\\Windows\\winnt.bmp" ),
        IMAGE_BITMAP,
        0,
        0,
        LR_DEFAULTSIZE | LR_LOADFROMFILE ) );

    TTransparentBitmap transparentBitmap;
// 透過色を黒にする
    COLORREF clrrefTransparent = 0x00000000;
    transparentBitmap.SetBackgroundColor ( clrrefTransparent );
// hBitmapを設定
    transparentBitmap.Attach ( hBitmap );

// デスクトップのDC取得
    HDC hDesktopDC;
    hDesktopDC = GetDC ( NULL );
// デスクトップに描画
    transparentBitmap.Draw ( hDesktopDC, 0, 0 );
// デスクトップのDC解放
    ReleaseDC ( NULL, hDesktopDC );

// hBitmapはTTransparentBitmapのデストラクタで自動削除

    return 0;
}
  ■ ご利用に際して ■ 更新履歴 ■ お問い合わせ ■ このホームページについて Copyright © 2014 A.Morita