FC2ブログ

ホーム > DIBファイルフォーマット > 透過DIB画像の表示

透過DIB画像の表示



透過DIB画像の表示には以下の2種類の方法があります。

  1. マスク画像を用いる方法
    まず画像の四隅の色から透過色を求めてマスク画像を作成し、このマスク画像で背景画像を理論積(AND)で切り取ります。次にマスク画像を反転してから前景画像上でマスクする部分を理論積(AND)で切り取り、最後にマスク部分を切り取った前景画像理論和(OR)背景画像に貼り付けます。

  2. アルファブレンド32ビットDIBを用いる方法
    まず背景画像から表示する画像の部分のコピーと表示する画像のコピーを作成します。次に背景画像前景画像アルファブレンド演算ピクセルビット毎に合成データを算出し、前景画像に戻します。最後に合成した前景画像背景画像に貼り付けます。



画像の四隅の色から透過色を求める関数です。

//BITMAPの四隅の色から透過色を取得する
//透過色テーブルの例
// int nColors=8;
// COLORREF colorMaskTable[nColors]={0x0000FF,0x00FF00,0xFF0000,0x00FFFF,
// 0xFF00FF,0xFFFF00,0xFFFFFF,0x000000};

COLORREF __stdcall _GetMaskColorByEdgeColor(HBITMAP hBitmap,COLORREF* pColorMaskTable,int nColors)
{
//BITMAP構造体の取得
BITMAP bm;
//BITMAP構造体の取得に失敗したら-1を返して終了する。
if (!::GetObject(hBitmap,sizeof(BITMAP),&bm)) return -1;

UINT width =bm.bmWidth; //画像幅
UINT height=bm.bmHeight; //画像高さ

//作業用DCの作成
HDC hMemDC=::CreateCompatibleDC(0);
HGDIOBJ hMemObj=::SelectObject(hMemDC,hBitmap);

//BITMAPの四隅の点を取得する
COLORREF color[4];
color[0]=::GetPixel(hMemDC,0,0); //左上
color[1]=::GetPixel(hMemDC,width-1,0); //右上
color[2]=::GetPixel(hMemDC,0,height-1); //左下
color[3]=::GetPixel(hMemDC,width-1,height-1); //右下

//後片付け
::SelectObject(hMemDC,hMemObj);
::DeleteDC(hMemDC);

//指定された透過色テーブルがあれば、四隅の色が透過色と一致するか調べる
if ((nColors)&&(pColorMaskTable)){
for(int i=0;i<4;i++) //四隅の点のループ
for(int j=0;j<nColors;j++) //透過色テーブルのループ
if (pColorMaskTable[j]==color[i]) //四隅のうちの一つが透過色と一致すれば、
for(int k=0;k<4;k++) //四隅の点の残りとの比較
//四隅の点のうち二つ透過色と一致すれば、透過色を返して終了する。

if ((i!=k)&&(color[i]==color[k])) return color[i];
}
//指定された透過色テーブルがなければ、四隅のうち2つが一致するか調べる
else {
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)//四隅のうち2つが一致すれば終了
if ((i!=j)&&(color[i]==color[j])) return color[i];
}
return -1; //色が一致しなかったので-1を返して終了する
}


入力された透過色から入力されたビットマップマスクビットマップを作成する関数です。

//指定した透過色からマスクビットマップを作成
HBITMAP __stdcall _CreateMaskBitmap(HBITMAP hBitmap,COLORREF colorMask)
{
//透過色が正しくないときは終了
if (colorMask&0xFF000000) return FALSE;

//入力されたビットマップの32ビットDIBのコピーを作成します。
HBITMAP hbmMask=_CopyDIB(hBitmap,32,0);

//作成に失敗したら、FALSEを返して終了します。
BITMAP bmm;
if (!::GetObject(hbmMask,sizeof(BITMAP),&bmm)) return FALSE;

//ピクセルデータの総数を算出します。
UINT nPixels=(bmm.bmWidthBytes*bmm.bmHeight)>>2;

//転送元/転送先ポインタを32ビットDIBのピクセルビットの先頭アドレスにします。
DWORD* src=(DWORD*)bmm.bmBits;
DWORD* dst=src;

//ピクセルビットと比較するために、透過色のRGBをBGRに並べ替えたDWORD変数を用意します。
DWORD bgr=((colorMask&0x00FF)<<16)|(colorMask&0x00FF00)|((colorMask&0xFF0000)>>16);

//ピクセルの数だけループします。
for(UINT i=0;i<nPixels;i++)
//ピクセルビットの色が透過色に一致したら白色、
//それ以外は黒色に色を変更します。

*dst++=(*src++==bgr)? 0xFFFFFF:0x000000;

//出来たマスクビットマップをモノクロDDBに変換
HBITMAP hbmMono=(HBITMAP)::CopyImage(hbmMask,IMAGE_BITMAP,0,0,LR_MONOCHROME);
//32ビットDIBはもういらないので削除します。
::DeleteObject(hbmMask);

return hbmMono;
}


カラービットマップマスクビットマップからアルファブレンド32ビットDIBを作成する関数です。

//カラービットマップとマスクビットマップからアルファブレンドDIBを作成する。
HBITMAP __stdcall _CreateAlphaBlendDIB(HBITMAP hbmColor,HBITMAP hbmMask)
{
//カラー画像の32ビットアルファブレンドDIBのコピーを作成する。
//作成に失敗したら、FALSEを返して終了します。

HBITMAP hbmColor32=_CopyDIB(hbmColor,32,ALPHA32);
if (!hbmColor32) return FALSE;

//マスク画像の32ビットDIBのコピーを作成する。
//作成に失敗したら、前に作成した32ビットカラー画像削除してから、
//FALSEを返して終了します。

HBITMAP hbmMask32=_CopyDIB(hbmMask,32,0);
if (!hbmMask32){
::DeleteObject(hbmColor32);
return FALSE;
}

//カラー/マスク双方の画像のBITMAP構造体を取得します。
BITMAP bmc; ::GetObject(hbmColor32,sizeof(BITMAP),&bmc);
BITMAP bmm; ::GetObject(hbmMask32, sizeof(BITMAP),&bmm);

//カラー/マスク双方の画像のピクセルビットへのポインタを取得します。
DWORD* src=(DWORD*)bmc.bmBits; //カラー画像読み取りのためのポインタ
DWORD* dst=src; //カラー画像書き込みのためのポインタ
DWORD* msk=(DWORD*)bmm.bmBits; //マスク画像読み取りポインタ

//ピクセルの総数を算出します。
UINT nPixels=(bmc.bmWidthBytes*abs(bmc.bmHeight))>>2;

//すべてのピクセルに対してカラー/マスクビットを合成します。
for(UINT i=0;i<nPixels;i++){
//背景透過部分はカラー画像のアルファビットを0にし、
//それ以外はカラー画像のアルファビットを255にします。

if ((*msk++)&0x00FFFFFF) (*src++)&=0x00FFFFFF;
else (*src++)|=0xFF000000;
}

//32ビットマスク画像はもういらないので削除する
::DeleteObject(hbmMask32);

return hbmColor32;
}


アルファブレンド演算マクロです。

//アルファブレンド演算マクロ
#ifndef ALPHA_BLEND
#define ALPHA_BLEND(composite,fg,alpha,bg){\
WORD temp=((WORD)(fg)*(WORD)(alpha)+(WORD)(bg)*(WORD)(255-(WORD)(alpha))+(WORD)128);\
(composite)=(BYTE)((temp+(temp>>8))>>8);\
}
#endif//ALPHA_BLEND



ビットマップ画像を入力されたDCに描画する関数です。

  1. 入力されたビットマップ画像がDIBアルファブレンド32ビットDIBの場合は、入力されたDC背景画像32ビットカラーDIBアルファブレンドしたものを描画します。
  2. 上記以外でマスクビットマップがある場合は、マスクDDBで入力されたDC背景画像のマスクされる部分を切り取り、マスクDDBの反転DDBを作成してこれでカラーDDB/DIBの背景部分を切り取った後、入力されたDCORで書き込みます。
  3. それ以外の場合は、カラーDDB/DIBを入力されたDCにそのまま描画します。


//ビットマップ画像の描画
BOOL __stdcall _DrawBitmap(HDC hDC,int xDst,int yDst,int cxDst,int cyDst,HBITMAP hbmColor,
HBITMAP hbmMask,int xSrc,int ySrc,int cxSrc,int cySrc)
{
//入力されたカラーDIBのDIBSECTION構造体を取得します。
DIBSECTION ds={0};
//DIBSECTION構造体が取得できない場合は、FALSEを返して終了します。
if (!::GetObject(hbmColor,sizeof(DIBSECTION),&ds)) return FALSE;

//画像サイズを取得します。
UINT width =ds.dsBm.bmWidth; //画像幅
UINT height=ds.dsBm.bmHeight; //画像高さ

//メモリーDCを作成します。
HDC hMemDC=::CreateCompatibleDC(hDC);
::SetStretchBltMode(hMemDC,COLORONCOLOR); //きれいに縮小するため。
::SetStretchBltMode(hDC,COLORONCOLOR); //きれいに縮小するため。

//カラービットマップがDIBでアルファブレンド32ビットDIBの場合
if ((ds.dsBmih.biSize==sizeof(BITMAPINFOHEADER))&&
(ds.dsBmih.biBitCount==32)&&(ds.dsBmih.biCompression==BI_BITFIELDS))
{
//背景画像用にもう一つメモリーDCを作成します。
HDC hBackDC=::CreateCompatibleDC(hDC);
::SetStretchBltMode(hBackDC,COLORONCOLOR); //きれいに縮小するため。

//背景画像用のDIBを作成します。
BITMAPINFOHEADER bh={0};
bh.biSize=sizeof(BITMAPINFOHEADER);
bh.biBitCount=24; //ビット深度は24ビット
bh.biWidth=cxDst; //画像幅/高さとも実際に表示するサイズにします。
bh.biHeight=cyDst;
bh.biPlanes=1;
DWORD widthBytes24=WIDTHBYTES(24*cxDst);
bh.biSizeImage=widthBytes24*cyDst;

//DIBセクションを作成します。
LPVOID pBitsBack=0;
HBITMAP hbmBack=::CreateDIBSection(hDC,(BITMAPINFO*)&bh,DIB_RGB_COLORS,&pBitsBack,0,0);
//作成に失敗した場合は、作成したメモリーDCを削除してから、
//FALSEを返して終了します。

if (!hbmBack){
::DeleteDC(hBackDC);
::DeleteDC(hMemDC);
return FALSE;
}

//背景画像用のメモリーDCに背景画像用のDIBを選択します。
HGDIOBJ hOldObj=::SelectObject(hBackDC,hbmBack);

//入力されたDCの画像を背景画像用のメモリーDCにコピーします。
::BitBlt(hBackDC,0,0,cxDst,cyDst,hDC,xDst,yDst,SRCCOPY);

//背景と前景を合成するDIBの作成
bh.biBitCount=32; //ビット深度は32ビット
DWORD widthBytes32=WIDTHBYTES(32*cxDst);
bh.biSizeImage=widthBytes32*cyDst;

//DIBセクションを作成します。
LPVOID pBitsFore;
HBITMAP hbmAlpha=::CreateDIBSection(hDC,(BITMAPINFO*)&bh,DIB_RGB_COLORS,&pBitsFore,0,0);
//作成に失敗した場合は、背景画像用のDIBと
//作成したメモリーDCを削除してから、FALSEを返して終了します。

if (!hbmAlpha){
::DeleteObject(hbmBack);
::DeleteDC(hBackDC);
::DeleteDC(hMemDC);
return FALSE;
}

//カラー画像を背景と前景を合成するDIBにコピーします。
::SelectObject(hBackDC,hbmAlpha);//hbmBackが開放されます。
HGDIOBJ hOldMem=::SelectObject(hMemDC,hbmColor);
::StretchBlt(hBackDC,0,0,cxDst,cyDst,hMemDC,xSrc,ySrc,cxSrc,cySrc,SRCCOPY);

::SelectObject(hBackDC,hOldObj);//hbmAlphaが開放されます。
//背景画像用のメモリーDCはもう必要ないので削除します。
::DeleteDC(hBackDC);

//背景と前景をアルファブレンド合成します。
BYTE r1,g1,b1,r2,g2,b2,a;
PBYTE fore,back,dest;
for(int i=0;i<cyDst;i++){
//ピクセルデータへのポインタの算出
fore=(PBYTE)pBitsFore+i*widthBytes32;//前景画像
back=(PBYTE)pBitsBack+i*widthBytes24;//背景画像
dest=fore;//結果を入れる前景画像へのポインタ
for(int j=0;j<cxDst;j++){
b1=*fore++; //前景画像のピクセルデータの読み出し
g1=*fore++;
r1=*fore++;
a =*fore++;
b2=*back++; //背景画像のピクセルデータの読み出し
g2=*back++;
r2=*back++;
//アルファブレンドマクロで演算処理
ALPHA_BLEND(*dest++,b1,a,b2);
ALPHA_BLEND(*dest++,g1,a,g2);
ALPHA_BLEND(*dest++,r1,a,r2);
dest++;
}
}

//入力されたDCにコピーする
::SelectObject(hMemDC,hbmAlpha);
::BitBlt(hDC,xDst,yDst,cxDst,cyDst,hMemDC,0,0,SRCCOPY);

//この関数内で作成したDIBはもう必要ないので削除します。
::DeleteObject(hbmAlpha);
::DeleteObject(hbmBack);
}

//通常のビットマップ画像の場合
else{
BITMAP bm;
//マスクビットマップがない場合
if (!::GetObject(hbmMask,sizeof(BITMAP),&bm)){
HGDIOBJ hOldObj=::SelectObject(hMemDC,hbmColor);
//カラービットマップのみを入力されたDCにコピーします。
::StretchBlt(hDC,xDst,yDst,cxDst,cyDst,hMemDC,xSrc,ySrc,cxSrc,cySrc,SRCCOPY);
::SelectObject(hMemDC,hOldObj);
}
//マスクビットマップがある場合
else {
//マスクビットマップで入力されたDCのマスクの部分を切り取ります。
HGDIOBJ hOldObj=::SelectObject(hMemDC,hbmMask);
::StretchBlt(hDC,xDst,yDst,cxDst,cyDst,hMemDC,xSrc,ySrc,cxSrc,cySrc,SRCAND);

//マスク用にもうひとつメモリーDCを作成します。
HDC hMaskDC=::CreateCompatibleDC(hDC);
//マスクを反転した画像を格納するモノクロビットマップを作成します。
HBITMAP hbmNotMask=::CreateBitmap(width,height,1,1,NULL);
HGDIOBJ hMaskObj=::SelectObject(hMaskDC,hbmNotMask);
//マスクビットマップを反転して作成したビットマップにコピーします。
::BitBlt(hMaskDC,0,0,width,height,hMemDC,0,0,NOTSRCCOPY);

//カラービットマップのコピーを作成します。
HBITMAP hbmColorCut=(HBITMAP)::CopyImage(hbmColor,IMAGE_BITMAP,0,0,0);

//マスクビットマップの反転画像でカラービットマップのマスク部分を切り取ります。
::SelectObject(hMemDC,hbmColorCut);
::BitBlt(hMemDC,0,0,width,height,hMaskDC,0,0,SRCAND);
::SelectObject(hMaskDC,hMaskObj);

//マスクの反転ビットマップとメモリーDCはもう必要ないので削除します。
::DeleteObject(hbmNotMask);
::DeleteDC(hMaskDC);

//カラー画像を入力されたDCにコピーする
::StretchBlt(hDC,xDst,yDst,cxDst,cyDst,hMemDC,xSrc,ySrc,cxSrc,cySrc,SRCPAINT);
::SelectObject(hMemDC,hOldObj);

//カラービットマップのコピーはもう必要ないので削除します。
::DeleteObject(hbmColorCut);
}
}
//作成したメモリーDCを削除します。
::DeleteDC(hMemDC);

return TRUE;
}



サンプルプログラム(VisualC++net2003ソリューション)DIBFileTest09.zip

上記のzipファイルをダウンロードしてからWinRAR等で解凍し、DIBFileTest09フォルダー内にある「DIBFileTest.sln」を開きます。「F5」キーを押すとビルド確認のダイヤログが表示されるので、「Yes」ボタンを押してソリューションをビルドします。



ビルドが終わると、直ちにプログラムが自動起動してウィンドウが表示されます。ウィンドウ内にあるトラッカーの範囲内で、右クリックしてポップアップメニューで「開く」を選択して、「ファイルを開く」ダイヤログを表示させます。



resフォルダー内の「1729_01.bmp」を背景画像として選択し、「開く」ボタンを押して読み込みます。画像が表示されたところで、画像のない所を左クリックしてトラッカーのフォーカスを移動させます。



新しいトラッカーの範囲内で再び右クリックしてポップアップメニューで「開く」を選択し、「ファイルを開く」ダイヤログを表示させます。



「purikick.bmp」を選択し、「開く」ボタンを押して読み込みます。画像が表示されたところで、トラッカーの範囲内で右クリックしてポップアップメニューで「画像のプロパティ」を選択し、「画像のプロパティ」ダイヤログを表示させます。



「透過色を使ってマスク透過する」にチェックを入れて「適用」ボタンを押します。画像のマスク部分が透過されて背景が見えるようになったかを確認してください。



再び画像のない所を左クリックしてトラッカーのフォーカスを移動させ、そのトラッカーの範囲内で右クリックしてポップアップメニューで「開く」を選択し、「ファイルを開く」ダイヤログを表示させます。



「tp_sphere_3.bmp」を選択し、「開く」ボタンを押して読み込みます。



画像が表示されたところで、その画像を移動させて、画像の下に背景が透けて見えるかを確認してください。

スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/20-732c0a35
Listed below are links to weblogs that reference
透過DIB画像の表示 from マルチメディアファイルフォーマット

Home > DIBファイルフォーマット > 透過DIB画像の表示

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る