• Welcome to Jose's Read Only Forum 2023.
 

GDI: Alphablending a bitmap

Started by José Roca, August 22, 2011, 11:49:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

José Roca

 
The following code sample divides a window into three horizontal areas. Then it draws an alpha-blended bitmap in each of the window areas as follows:



  • In the top area, constant alpha = 50% but there is no source alpha.

  • In the middle area, constant alpha = 100% (disabled) and source alpha is 0 (transparent) in the middle of the bitmap and 0xff (opaque) elsewhere.

  • In the bottom area, constant alpha = 75% and source alpha changes.


' ########################################################################################
' Alpha Blending a Bitmap
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

' // Include files for external files
#INCLUDE ONCE "CWindow.inc"   ' // CWindow class

' ========================================================================================
' The following code sample divides a window into three horizontal areas. Then it draws an
' alpha-blended bitmap in each of the window areas as follows:
'    * In the top area, constant alpha = 50% but there is no source alpha.
'    * In the middle area, constant alpha = 100% (disabled) and source alpha is 0
'      (transparent) in the middle of the bitmap and 0xff (opaque) elsewhere.
'    * In the bottom area, constant alpha = 75% and source alpha changes.
' ========================================================================================
SUB DrawAlphaBlend (BYVAL hwnd AS LONG, BYVAL hDCwnd AS LONG)

   LOCAL hdc AS LONG              ' handle of the DC we will create
   LOCAL bf AS BLENDFUNCTION      ' structure for alpha blending
   LOCAL hbitmap AS LONG          ' bitmap handle
   LOCAL bmi AS BITMAPINFO        ' bitmap header
   LOCAL pvBits AS DWORD PTR      ' pointer to DIB section
   LOCAL ulWindowWidth AS LONG    ' window width
   LOCAL ulWindowHeight AS LONG   ' window height
   LOCAL ulBitmapWidth AS LONG    ' bitmap width
   LOCAL ulBitmapHeight AS LONG   ' bitmap height
   LOCAL rt AS RECT               ' used for getting window LOCALensions
   LOCAL x AS LONG, y AS LONG     ' stepping variables
   LOCAL ubAlpha AS BYTE          ' used for doing transparent gradient
   LOCAL ubRed   AS BYTE
   LOCAL ubGreen AS BYTE
   LOCAL ubBlue  AS BYTE
   LOCAL fAlphaFactor AS SINGLE   ' used to do premultiply

   ' get window dimensions
   GetClientRect hwnd, rt

   ' calculate window width/height
   ulWindowWidth = rt.nright - rt.nleft
   ulWindowHeight = rt.nbottom - rt.ntop

   ' make sure we have at least some window size
   IF ulWindowWidth = 0 OR ulWindowHeight = 0 THEN EXIT SUB

   ' divide the window into 3 horizontal areas
   ulWindowHeight = ulWindowHeight \ 3

   ' create a DC for our bitmap -- the source DC for AlphaBlend
   hdc = CreateCompatibleDC(hDCwnd)

   ' setup bitmap info
   ' set the bitmap width and height to 60% of the width and height of each of
   ' the three horizontal areas. Later on, the blending will occur in the center
   ' of each of the three areas.
   bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER)
   ulBitmapWidth = ulWindowWidth - (ulWindowWidth \ 5) * 2
   bmi.bmiHeader.biWidth = ulBitmapWidth
   ulBitmapHeight = ulWindowHeight - (ulWindowHeight \ 5) * 2
   bmi.bmiHeader.biHeight = ulBitmapHeight
   bmi.bmiHeader.biPlanes = 1
   bmi.bmiHeader.biBitCount = 32         ' four 8-bit components
   bmi.bmiHeader.biCompression = %BI_RGB
   bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4

   ' create our DIB section and select the bitmap into the dc
   hbitmap = CreateDIBSection(hdc, bmi, %DIB_RGB_COLORS, BYVAL VARPTR(pvBits), 0, 0)
   SelectObject hdc, hbitmap

   ' in top window area, constant alpha = 50%, but no source alpha
   ' the color format for each pixel is &Haarrggbb
   ' set all pixels to blue and set source alpha to zero
   FOR y = 0 TO ulBitmapHeight - 1
      FOR x = 0 TO ulBitmapWidth - 1
         @pvBits[x + y * ulBitmapWidth] = &H000000FF
      NEXT
   NEXT

   bf.BlendOp = %AC_SRC_OVER
   bf.BlendFlags = 0
   bf.SourceConstantAlpha = &H7F  ' half of &HFF = 50% transparency
   bf.AlphaFormat = 0             ' ignore source alpha channel

   IF ISFALSE AlphaBlend(hDCwnd, (ulWindowWidth\5), (ulWindowHeight\5), _
                         ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, _
                         ulBitmapWidth, ulBitmapHeight, bf) THEN
      DeleteObject hbitmap
      DeleteDC hdc
      EXIT SUB
   END IF

   ' in middle window area, constant alpha = 100% (disabled), source
   ' alpha is 0 in middle of bitmap and opaque in rest of bitmap
   FOR y = 0 TO ulBitmapHeight - 1
      FOR x = 0 TO ulBitmapWidth - 1
         IF (x > (ulBitmapWidth \ 5)) AND (x < (ulBitmapWidth-ulBitmapWidth \ 5)) AND _
            (y > (ulBitmapHeight \ 5)) AND (y < (ulBitmapHeight-ulBitmapHeight \ 5)) THEN
            ' in middle of bitmap: source alpha = 0 (transparent).
            ' This means multiply each color component by &H00.
            ' Thus, after AlphaBlend, we have a, &H00 * r,
            ' &H00 * g,and &H00 * b (which is &H00000000)
            ' for now, set all pixels to red
            @pvBits[x + y * ulBitmapWidth] = &H00FF0000
         ELSE
            ' in the rest of bitmap, source alpha = &Hff (opaque)
            ' and set all pixels to blue
            @pvBits[x + y * ulBitmapWidth] = &HFF0000FF
         END IF
      NEXT
   NEXT

   bf.BlendOp = %AC_SRC_OVER
   bf.BlendFlags = 0
   bf.AlphaFormat = %AC_SRC_ALPHA  ' use source alpha
   bf.SourceConstantAlpha = &HFF   ' opaque (disable constant alpha)

   IF ISFALSE AlphaBlend (hDCwnd, ulWindowWidth \ 5, ulWindowHeight \ 5 + ulWindowHeight, _
                         ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, _
                         ulBitmapHeight, bf) THEN
      DeleteObject hbitmap
      DeleteDC hdc
      EXIT SUB
   END IF

   ' bottom window area, use constant alpha = 75% and a changing
   ' source alpha. Create a gradient effect using source alpha, and
   ' then fade it even more with constant alpha
   ubRed   = &H00
   ubGreen = &H00
   ubBlue  = &HFF

   LOCAL f AS SINGLE

   FOR y = 0 TO ulBitmapHeight - 1
      FOR x = 0 TO ulBitmapWidth - 1
         ' for a simple gradient, base the alpha value on the x
         ' value of the pixel
         f = x / ulBitmapWidth * 255
         ubAlpha = f
         ' calculate the factor by which we multiply each component
         fAlphaFactor = ubAlpha / &HFF
         f = ubBlue * fAlphaFactor
         ubBlue = f
         @pvBits[x + y * ulBitmapWidth] = ubAlpha OR _            '&Haa000000
                                          ubRed   OR _            '&H00rr0000
                                          ubGreen OR _            '&H0000gg00
                                          ubBlue                  '&H000000bb
      NEXT
   NEXT

   bf.BlendOp = %AC_SRC_OVER
   bf.BlendFlags = 0
   bf.AlphaFormat = 0
   bf.SourceConstantAlpha = &HBF   ' use constant alpha, with 75% opaqueness

   AlphaBlend hDCwnd, ulWindowWidth \ 5, _
              ulWindowHeight \ 5 + 2 * ulWindowHeight, ulBitmapWidth, _
              ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, _
              ulBitmapHeight, bf

   ' do cleanup
   DeleteObject hbitmap
   DeleteDC hdc

END SUB
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
'   SetProcessDPIAware

   ' // Create an instance of the class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   ' // Note: CW_USEDEFAULT is used as the default value When passing 0's as the width and height
   pWindow.CreateWindow(%NULL, "AlphaBlend Demo", 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Set the client size
   pWindow.SetClientSize 500, 320
   ' // Center the window
   pWindow.CenterWindow

   ' // Default message pump (you can replace it with your own)
   pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main dialog callback.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   LOCAL hdc AS DWORD
   LOCAL ps  AS PAINTSTRUCT

   SELECT CASE wMsg

      CASE %WM_COMMAND
         SELECT CASE LO(WORD, wParam)
            CASE %IDCANCEL
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE %WM_PAINT
         hdc = BeginPaint(hwnd, ps)
         DrawAlphaBlend hwnd, hdc
         EndPaint hwnd, ps
         EXIT FUNCTION

     CASE %WM_DESTROY
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProc(hwnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================