青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

最近工作中有個需求是將Icon轉成帶Alpha通道的Bitmap, 雖然網上有不少這方面的文章,但很多都是錯的, 這里記錄下,或許對后來人有用。

要實現這個功能,我們首先需要理解Icon的格式,我們可以看到Icon的結構如下:
typedef struct _ICONINFO {
    BOOL fIcon;
    DWORD xHotspot;
    DWORD yHotspot;
    HBITMAP hbmMask;
    HBITMAP hbmColor;
} ICONINFO;
typedef ICONINFO 
*PICONINFO;

從上面我們可以看到Icon和cursor的結構基本一樣,主要都包括一幅mask位圖和一幅color位圖
如下一個8個像素的紅色小圖標:


它的Mask位圖如下:

如果我們把Mask位圖畫出來,我們會看到周圍1的區域都是白色的,中間0的區域是黑色的

它的color位圖如下:

如果我們把color位圖畫出來,我們會看到除了中間區域是紅色的,周圍0的區域都是黑色的。

思考將Icon畫到目標位圖上時,他們是如何最終合成的?

實際很簡單,就是先和Mask位圖做與(AND)運算,然后再與Color位圖做異或(XOR)運算: AND運算的結果是除了中間區域變成黑色(0),目標位圖的其他區域都保持不變;XOR 運算的結果是周圍區域只有和0不一樣 (color位圖)才會得到1 (也就是原來是1則保持), 中間區域因為前面經過mask運算后都是0,所以中間R部分XOR后也會保留。

我們看到通過AND和XOR運算,我們將中間紅色部分扣出來貼了上去,而其他周圍區域保持不變, 這種方式實際上也是DrawIconExTransparentBlt的實現原理。
理解了Icon格式,我們要將Icon轉Bitmap就好辦了, 我們只要將Color位圖考出來,然后位圖里將mask部分是1的部分的Alpha通道改成0就可以了。
這里要 注意的是有些icon 的color位圖本身就是帶Alpha通道的,這樣我們就實際上用不到Mask位圖了,也不用再去改Alpha通道了。

另外對于黑白單色Icon( 比如黑白光標), 我們很多時候會發現它的color位圖是空的, 這種情況下所有的數據實際上都存到了Mask位圖里,這時的Mask位圖高度是Icon高度的2倍,上半部分是mask部分,下班部分保存了color位圖部分。

最后簡單貼下代碼:

HBITMAP IconToBitmap(HICON hIcon, SIZE* pTargetSize = NULL)
{
    ICONINFO info = {0};
    
if(hIcon == NULL
        
|| !GetIconInfo(hIcon, &info)
        
|| !info.fIcon)
    {
        
return NULL;
    }

    INT nWidth = 0;
    INT nHeight = 0;
    
if(pTargetSize != NULL)
    {
        nWidth = pTargetSize->cx;
        nHeight = pTargetSize->cy;
    }
    
else
    {
        
if(info.hbmColor != NULL)
        {
            BITMAP bmp = {0};
            GetObject(info.hbmColor, sizeof(bmp), &bmp);

            nWidth = bmp.bmWidth;
            nHeight = bmp.bmHeight;
        }
    }

    if(info.hbmColor != NULL)
   {
      DeleteObject(info.hbmColor);
      info.hbmColor = NULL;
    }

    if(info.hbmMask != NULL)
   {
      DeleteObject(info.hbmMask);
      info.hbmMask = NULL;
   }

    if(nWidth <= 0
        
|| nHeight <= 0)
    {
        
return NULL;
    }

    INT nPixelCount = nWidth * nHeight;

    HDC dc = GetDC(NULL);
    INT* pData = NULL;
    HDC dcMem = NULL;
    HBITMAP hBmpOld = NULL;
    
bool* pOpaque = NULL;
    HBITMAP dib = NULL;
    BOOL bSuccess = FALSE;

    
do
    {
        BITMAPINFOHEADER bi = {0};
        bi.biSize = sizeof(BITMAPINFOHEADER);    
        bi.biWidth = nWidth;
        bi.biHeight = -nHeight;  
        bi.biPlanes = 1;    
        bi.biBitCount = 32;    
        bi.biCompression = BI_RGB;
        dib = CreateDIBSection(dc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (VOID**)&pData, NULL, 0);
        
if(dib == NULL) break;

        memset(pData, 0, nPixelCount * 4);

        dcMem = CreateCompatibleDC(dc);
        
if(dcMem == NULL) break;

        hBmpOld = (HBITMAP)SelectObject(dcMem, dib);
        ::DrawIconEx(dcMem, 00, hIcon, nWidth, nHeight, 0, NULL, DI_MASK);

        pOpaque = new(std::nothrow) bool[nPixelCount];
        
if(pOpaque == NULL) break;
        
for (INT i = 0; i < nPixelCount; ++i)
        {
            pOpaque[i] = !pData[i];
        }

        memset(pData, 0, nPixelCount * 4);
        ::DrawIconEx(dcMem, 00, hIcon, nWidth, nHeight, 0, NULL, DI_NORMAL);

        BOOL bPixelHasAlpha = FALSE;
        UINT* pPixel = (UINT*)pData;
        
for(INT i = 0; i<nPixelCount; ++i, ++pPixel)
        {
            
if((*pPixel & 0xff000000!= 0)
            {
                bPixelHasAlpha = TRUE;
                
break;
            }
        }

        
if(!bPixelHasAlpha)
        {
            pPixel = (UINT*)pData;
            
for(INT i=0;i <nPixelCount; ++i, ++pPixel)
            {
                
if(pOpaque[i])
                {
                    
*pPixel |= 0xFF000000;
                }
                
else
                {
                    
*pPixel &= 0x00FFFFFF;
                }
            }
        }

        bSuccess = TRUE;

    } while(FALSE);


    
if(pOpaque != NULL)
    {
        delete []pOpaque;
        pOpaque = NULL;
    }

    
if(dcMem != NULL)
    {
 
       SelectObject(dcMem, hBmpOld);
        DeleteDC(dcMem);
    }

    ReleaseDC(NULL, dc);

    
if(!bSuccess)
    {
        
if(dib != NULL)
        {
            DeleteObject(dib);
            dib = NULL;
        }
    }

    
return dib;
}

另外感慨Webkit是個寶庫, 我們的Icon轉Bitmap代碼實際上可以參考這里:
http://src.chromium.org/chrome/branches/355/src/gfx/icon_util.cc

另外不知道大家有沒有留意到上面Webkit鏈接的源碼里那個函數有隱秘的資源泄露,
SkBitmap* IconUtil::CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s)
 {
  
// We start with validating parameters.
  ICONINFO icon_info;
  
if (!icon || !(::GetIconInfo(icon, &icon_info)) ||
      
!icon_info.fIcon || s.IsEmpty()) {
    
return NULL;
  }
...
}
面GetIconInfo返回的2個圖像句柄hbmColor 和 hbmMask 最終都沒有釋放, 想不到寫Webkit的高手也有這種失誤...
posted on 2014-08-21 22:23 Richard Wei 閱讀(5114) 評論(0)  編輯 收藏 引用 所屬分類: windows desktop
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美成人精品不卡视频在线观看| 亚洲一二三区在线| 欧美电影在线观看| 久热精品在线视频| 蜜乳av另类精品一区二区| 久久在线免费| 欧美国产精品专区| 欧美午夜在线视频| 国产在线欧美| 亚洲日本欧美天堂| 亚洲免费在线视频一区 二区| 午夜日韩福利| 麻豆精品网站| 亚洲高清视频一区二区| 亚洲国产欧美在线人成| 一区二区三区**美女毛片 | 久久久久中文| 蜜桃av一区| 日韩视频不卡| 欧美日韩在线三区| 亚洲视频在线免费观看| 欧美一区二区三区四区夜夜大片| 久久一区二区三区超碰国产精品| 欧美成人资源| 国产精品视频999| 亚洲电影激情视频网站| 亚洲一区美女视频在线观看免费| 久久精品国产久精国产一老狼| 欧美激情一区二区三区在线视频观看 | 亚洲国产视频直播| 亚洲欧美区自拍先锋| 免费欧美高清视频| 国产美女精品一区二区三区| 亚洲高清在线精品| 久久精品成人一区二区三区 | 亚洲综合色视频| 亚洲国产高清aⅴ视频| 新狼窝色av性久久久久久| 欧美激情免费在线| 在线观看日韩| 久久国产日本精品| 正在播放亚洲一区| 欧美精品精品一区| 亚洲国产精品一区二区第一页| 亚洲男人的天堂在线观看| 亚洲成色999久久网站| 欧美一区二视频在线免费观看| 欧美精品18+| 亚洲欧洲一区二区三区| 久久久久久9| 欧美亚洲在线播放| 国产精品毛片| 亚洲欧美一区二区视频| 日韩亚洲不卡在线| 欧美日韩一区二区三区四区在线观看| 亚洲大片av| 免费观看成人鲁鲁鲁鲁鲁视频| 亚洲欧美在线看| 国产乱码精品一区二区三区av| 亚洲免费综合| 午夜视频一区在线观看| 国产亚洲精品资源在线26u| 欧美在线视频免费| 久久国产精品电影| 亚洲国产乱码最新视频| 欧美黄色小视频| 欧美久久久久久久久| 宅男噜噜噜66一区二区| 亚洲午夜精品网| 在线亚洲欧美| 日韩视频在线免费| 欧美午夜精品电影| 亚洲一区在线播放| 亚洲一二三级电影| 国产婷婷精品| 你懂的一区二区| 欧美成人tv| 亚洲天堂av综合网| 亚洲一二三区精品| 国内精品视频久久| 亚洲国产美女精品久久久久∴| 欧美69wwwcom| 亚洲一区二区免费在线| 亚洲欧美日韩精品| 极品日韩久久| 日韩视频在线你懂得| 国产精品一区免费视频| 久久综合色一综合色88| 欧美成人精品在线观看| 亚洲一区二区三区精品在线观看| 宅男在线国产精品| 曰本成人黄色| 亚洲最黄网站| 国产一级精品aaaaa看| 亚洲成色精品| 国产欧美一区二区三区久久人妖 | 久久精品人人做人人爽| 久久久久久穴| 一区二区免费在线播放| 午夜久久久久久| 亚洲精品一区二区网址| 午夜精彩视频在线观看不卡| 亚洲电影自拍| 亚洲曰本av电影| 亚洲三级电影全部在线观看高清| 亚洲视频综合在线| 亚洲免费高清| 久久久久欧美精品| 欧美一区二区三区日韩视频| 欧美成人黑人xx视频免费观看| 欧美一二三视频| 欧美日韩hd| 欧美国产精品一区| 国产欧美日本| 亚洲无人区一区| 亚洲毛片一区| 久久伊伊香蕉| 久久影视精品| 国产亚洲欧美一级| 一本色道久久综合狠狠躁篇怎么玩| 国模精品一区二区三区色天香| 一本不卡影院| 一区二区91| 欧美精品1区2区| 欧美韩日一区二区三区| 国一区二区在线观看| 亚洲欧美成人网| 亚洲女人小视频在线观看| 欧美精品二区| 亚洲日本欧美天堂| 另类综合日韩欧美亚洲| 国产日韩一区二区三区| 日韩一级精品| 日韩香蕉视频| 欧美激情第二页| 亚洲第一综合天堂另类专| 精品av久久久久电影| 欧美在线啊v| 久久亚洲一区二区| 韩国女主播一区二区三区| 翔田千里一区二区| 久久久久国产精品一区| 国产一区二区三区四区在线观看| 亚洲女ⅴideoshd黑人| 欧美亚洲一区二区在线观看| 国产精品色午夜在线观看| 午夜国产一区| 久久影院午夜片一区| 影音先锋中文字幕一区二区| 久久青草久久| 亚洲国产另类久久久精品极度| 亚洲精品日韩欧美| 欧美日韩国产限制| 亚洲一区免费看| 久久久久久亚洲精品中文字幕 | 亚洲人成啪啪网站| 欧美成人免费观看| 亚洲免费观看高清完整版在线观看熊| 9色porny自拍视频一区二区| 欧美另类99xxxxx| 亚洲专区一区二区三区| 久热精品视频在线观看一区| 亚洲精品久久久久久久久久久久久| 欧美精品日日鲁夜夜添| 亚洲视频高清| 免费在线一区二区| 99国产精品久久久久久久成人热| 欧美日本在线看| 亚洲男女自偷自拍图片另类| 久久香蕉国产线看观看av| 亚洲裸体视频| 国产亚洲精品v| 欧美精品午夜视频| 欧美伊久线香蕉线新在线| 欧美高清在线视频| 欧美一级成年大片在线观看| 亚洲国产精品电影| 国产精品一级在线| 欧美va亚洲va日韩∨a综合色| 亚洲深夜av| 亚洲缚视频在线观看| 欧美一区二区三区啪啪| 日韩午夜精品视频| 极品少妇一区二区三区精品视频| 欧美久久久久久| 久久三级福利| 午夜久久一区| 日韩视频永久免费观看| 免费精品视频| 久久久精品日韩| 亚洲尤物在线视频观看| 亚洲国产导航| 国产视频精品xxxx| 国产精品久久久久av| 欧美韩日高清| 久久综合久久美利坚合众国| 亚洲欧美日韩国产另类专区| 亚洲免费观看高清完整版在线观看熊 | 久久国产88| 亚洲网站在线观看|