天天看点

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

注意: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;

}

继续阅读