透明图片的异形处理(windows或ppc)

来源:互联网 发布:mac双系统不关机切换 编辑:程序博客网 时间:2024/06/10 09:29

注意:crTransparent设置为RGB(255,0,255),否则可能会有问题。

参考网友资料:

半透明原理: 
  假设LCD是256色的。颜色格式为332(RGB) 
  显存中的每一个字节的数据对应一个象素点。 
  在数据写入显存之前,读取相应相素点值,然后与新的数据按一定的规则混合之后,再写入相应像素点的显存。

  这样主要问题关键是混合算法。 
  混合算法目前在游戏上常用到的算法是AlphaBlend。计算公式如下 
  假设一幅图象是A,另一幅透明的图象是B,那么透过B去看A,看上去的图象C就是B和A的混合图象,设B图象的透明度为alpha(取值为0-1,1为完全透明,0为完全不透明),Alpha混合公式如下:
  R(C)=(1-alpha)*R(B)+alpha*R(A)
  G(C)=(1-alpha)*G(B)+alpha*G(A)
  B(C)=(1-alpha)*B(B)+alpha*B(A)
  R(x)、G(x)、B(x)分别指颜色x的RGB分量原色值。从上面的公式可以知道,Alpha其实是一个决定混合透明度的数值。应用Alpha混合技术,可以实现游戏中的许多特效,比如火光、烟雾、阴影、动态光源等半透明效果。

HBITMAP LoadPngImage(const wchar_t* pfileName, COLORREF crTransparent)

{
    IImagingFactory *pImgFactory = NULL;
    IImage *pImage = NULL;
    HBITMAP hBitmap = NULL;
    // Normally you would only call CoInitialize/CoUninitialize
    // once per thread.  This sample calls CoInitialize in this
    // draw function simply to illustrate that you must call
    // CoInitialize before calling CoCreateInstance.
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    // Create the imaging factory.
    if (SUCCEEDED(CoCreateInstance (CLSID_ImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IImagingFactory,
        (void **)&pImgFactory)))
    {
        // Load the image from the JPG file.
        pImgFactory->CreateImageFromFile(pfileName, &pImage);
        pImgFactory->Release();
    }

    if( pImage ) {
        COLORREF crTransColor = crTransparent;
        ImageInfo tempimageinfo;
        pImage->GetImageInfo(&tempimageinfo);

        HDC hWinDC = ::GetWindowDC(NULL);
        HDC memedc = ::CreateCompatibleDC(NULL);
        RECT rcWin = { 0, 0, tempimageinfo.Width-1, tempimageinfo.Height-1 };
        hBitmap = ::CreateCompatibleBitmap( hWinDC, rcWin.right-rcWin.left, rcWin.bottom-rcWin.top );

        HBITMAP holdBitmap = (HBITMAP)::SelectObject(memedc, hBitmap);
        ::FillSolidRect(memedc, &rcWin, crTransColor);
        pImage->Draw( memedc, &rcWin, NULL);
        pImage->Release();

        ::SelectObject(memedc, holdBitmap);
        ::DeleteDC( memedc );
        ReleaseDC( NULL, hWinDC );
    }

    CoUninitialize();

    return hBitmap;
}

HRGN GetRegionFromImage(HBITMAP hBmp, COLORREF cTransparentColor, COLORREF cTolerance)
{
    HRGN hRgn = NULL;
    if (hBmp)
    {
        //Create a memory DC inside which we will scan the bitmap content
        HDC hMemDC = CreateCompatibleDC(NULL);
        if (hMemDC)
        {
            //Get bitmap size
            BITMAP bm;
            GetObject(hBmp, sizeof(bm), &bm);

            // Create a 32 bits depth bitmap and select it into the memory DC
            BITMAPINFOHEADER RGB32BITSBITMAPINFO = {
                sizeof(BITMAPINFOHEADER), //biSize
                bm.bmWidth,  //biWidth;
                bm.bmHeight, //biHeight;
                1,  //biPlanes;
                32,  //biBitCount
                BI_RGB,  //biCompression;
                0,  //biSizeImage;
                0,  //biXPelsPerMeter;
                0,  //biYPelsPerMeter;
                0,  //biClrUsed;
                0  //biClrImportant;
            };

            VOID * pbits32;
            HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0);
            if (hbm32)
            {
                HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32);

                //Create a DC just to copy the bitmap into the memory DC
                HDC hDC = CreateCompatibleDC(hMemDC);
                if (hDC)
                {
                    //Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits)
                    BITMAP bm32;
                    GetObject(hbm32, sizeof(bm32), &bm32);
                    while (bm32.bmWidthBytes % 4)
                        bm32.bmWidthBytes++;

                    //Copy the bitmap into the memory DC
                    HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
                    //cTransparentColor =  ::GetPixel(hDC, 0, 0);   
                    BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);

                    //For better performances, we will use the ExtCreateRegion() function to create the
                    //region. This function take a RGNDATA structure on entry. We will add rectangles by
                    //amount of ALLOC_UNIT number in this structure.
#define ALLOC_UNIT 100
                    DWORD maxRects = ALLOC_UNIT;
                    HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
                    RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
                    pData->rdh.dwSize = sizeof(RGNDATAHEADER);
                    pData->rdh.iType = RDH_RECTANGLES;
                    pData->rdh.nCount = pData->rdh.nRgnSize = 0;
                    SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);

                    //Keep on hand highest and lowest values for the "transparent" pixels
                    BYTE lr = GetBValue(cTransparentColor);
                    BYTE lg = GetGValue(cTransparentColor);
                    BYTE lb = GetRValue(cTransparentColor);
                    BYTE hr = min(0xff, lr + GetRValue(cTolerance));
                    BYTE hg = min(0xff, lg + GetGValue(cTolerance));
                    BYTE hb = min(0xff, lb + GetBValue(cTolerance));

                    //Scan each bitmap row from bottom to top (the bitmap is inverted vertically)
                    BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
                    for (int y = 0; y < bm.bmHeight; y++)
                    {
                        //Scan each bitmap pixel from left to right
                        for (int x = 0; x < bm.bmWidth; x++)
                        {
                            //Search for a continuous range of "non transparent pixels"
                            int x0 = x;
                            LONG *p = (LONG *)p32 + x;
                            while (x < bm.bmWidth)
                            {
                                BYTE b = GetRValue(*p);
                                if (b >= lr && b <= hr)
                                {
                                    b = GetGValue(*p);
                                    if (b >= lg && b <= hg)
                                    {
                                        b = GetBValue(*p);
                                        if (b >= lb && b <= hb)
                                            //This pixel is "transparent"
                                            break;
                                    }
                                }
                                p++;
                                x++;
                            }

                            if (x > x0)
                            {
                                //Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region
                                if (pData->rdh.nCount >= maxRects)
                                {
                                    GlobalUnlock(hData);
                                    maxRects += ALLOC_UNIT;
                                    hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
                                    pData = (RGNDATA *)GlobalLock(hData);
                                }
                                RECT *pr = (RECT *)&pData->Buffer;
                                SetRect(&pr[pData->rdh.nCount], x0, y, x, y + 1);
                                if (x0 < pData->rdh.rcBound.left)
                                    pData->rdh.rcBound.left = x0;
                                if (y < pData->rdh.rcBound.top)
                                    pData->rdh.rcBound.top = y;
                                if (x > pData->rdh.rcBound.right)
                                    pData->rdh.rcBound.right = x;
                                if (y+1 > pData->rdh.rcBound.bottom)
                                    pData->rdh.rcBound.bottom = y + 1;
                                pData->rdh.nCount++;

                                //On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
                                //large (ie: > 4000). Therefore, we have to create the region by multiple steps.
                                if (pData->rdh.nCount == 2000)
                                {
                                    HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
                                    if (hRgn)
                                    {
                                        CombineRgn(hRgn, hRgn, h, RGN_OR);
                                        DeleteObject(h);
                                    }
                                    else  hRgn = h;

                                    pData->rdh.nCount = 0;
                                    SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
                                }
                            }
                        }

                        //Go to next row (remember, the bitmap is inverted vertically)
                        p32 -= bm32.bmWidthBytes;
                    }

                    //Create or extend the region with the remaining rectangles
                    HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
                    if (hRgn)
                    {
                        CombineRgn(hRgn, hRgn, h, RGN_OR);
                        DeleteObject(h);
                    }
                    else
                        hRgn = h;

                    //Clean up
                    GlobalFree(hData);
                    SelectObject(hDC, holdBmp);
                    DeleteDC(hDC);
                }
                DeleteObject(SelectObject(hMemDC, holdBmp));
            }
            DeleteDC(hMemDC);
        }
    }
    return hRgn;
}


原创粉丝点击