Search This Blog

Monday, June 1, 2009

Per-Pixel Alpha Blending in Windows (Win32 Solution)


Introduction.

Well, The Old age of DOS are gone. Now, its time of GUI competitions.. People equally love the look and feel as well as functionality!

With the coming of Windows Vista, many have noticed the Sidebar Gadgets, especially nice looking Clock Gadget. Its beautiful with its blurred edges and Alpha Transparancy effects.

In Windows 7, you may have noticed, the concept of Sidebar has been entirely dropped by Microsoft. Instead, they have integrated the Gadgets directly as desktop objects.

Well, now, can we create such a Gadget or gadget like anything? - The Answer is Yes!

And, the technique i'm describing to you to create a Window with Blurred Edges, like in the above image is known as "Per-Pixel Alpha Blending".

I'm demonstrating to you in a simple and a very easy to do method with code snip.

How to Do.

Open the Microsoft Visual Studio VC++ Editor IDE, create a new project. Dont choose a blank project. Choose a new one with the default Window code in it.

Run the project by hitting F5. Now, you have a window, a blank one with rectangular shape.

Come to the code, lets have some change...

Set the Window style flag to "Layered" (WS_EX_LAYERED) -> Dont Forget!

Now, paste this code, right after you create the Window (Call to CreateWindow() of your window).

Use the attached PNG Image below a resource. you may use any other image, i've provided this as a sample.



// Load our PNG image
CImage img;
img.Load("circle.png");

// Get dimensions of Image
int iWidth = img.GetWidth();
int iHeight = img.GetHeight();

// Make a memory DC + memory bitmap
HDC hdcScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hdcScreen);
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, hBmp);

// Draw image to memory DC
img.Draw(hDC, 0, 0, iWidth, iHeight, 0, 0, iWidth, iHeight);

// Call UpdateLayeredWindow
BLENDFUNCTION blend = {0};
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;

POINT ptPos = {0, 0};
SIZE sizeWnd = {iWidth, iHeight};
POINT ptSrc = {0, 0};

UpdateLayeredWindow(hWnd, hdcScreen, &ptPos, &sizeWnd, hDC, &ptSrc, 0, &blend, ULW_ALPHA); 

SelectObject(hDC, hBmpOld);
DeleteObject(hBmp);
DeleteDC(hDC);
ReleaseDC(NULL, hdcScreen);

SetWindowPos(hWnd, 0, 0, 0, iWidth, iHeight, SWP_NOZORDER | SWP_NOMOVE);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);


Done!... Thats it, Run your code now, and Bingo! a perfect Sphere window has been created :)

The UpdateLayeredWindow() API is the thing, which helps us to clip our Window in size of the Image we have provided. I have documented the code well enough, else you can Look for MSDN Documentation for the API's.

All we have done is simple trick. We have created a Memory DC, and a Bitmap in Memory with width and height of our PNG Image. Nextly we select the Bitmap to our video memory DC (Screen DC).

Nextly we start drawing the Image into the Video Memory, and atlast called the UpdateLayeredWindow(), which then sets the bounds of Window as that of our Image, and sets the Alpha as provided in BLENDFUNCTION structure.

I Highly recommend you to Read MSDN Documentation of the API's to make maximum out of this tutorial. :)



3 comments:

  1. That's very nice, but how to do the same with GDI+ ?

    ReplyDelete
  2. Why? Why doing same thing in GDI+?

    OK, I will tell you.

    1. If you use C# (I suppose), you should import DLL, for example create a wrapper class for needed functions from win. libraries.

    User32.dll has for example UpdateLayeredWindow function inside.

    Search other functions from tutorial in MSDN and find correct libs.

    In C++, I believe there are similar steps, but there are simply ready functions in windows.h or something like that.

    You can create .NET dll library in c#, and use it in MFC (for C++ VCL) also.

    Other questions?

    ReplyDelete
  3. i want a demo project with exe i cant work it out :(

    ReplyDelete