Jump to content

hBitmap from GDI+ bitmap


grham
 Share

Recommended Posts

Hello,

I was playing around with the bitblt function,

this time I was using it to create a Mask for an image.

It's successfull when I load the image with _WinAPI_LoadImage

It has to be from a BMP file.

Here an simple working example (with double buffering).

In my case the "color for transparency" is black but you can change it.

The "color for transparency has to be BGR.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Don't forget to put your image there!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <Winapi.au3>
#include <Constants.au3>
#include <WindowsConstants.au3>

$sImage      = "(PUT HERE THE PATH OF YOUR IMAGE!!!!!!!!!).bmp"
$hBmp_Source = _WinAPI_LoadImage(0, $sImage, $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)

$stBitmap = DllStructCreate("long bmType;long bmWidth;long bmHeight;long bmWidthBytes;WORD bmPlanes;WORD bmBitsPixel;ptr bmBits")
_WinAPI_GetObject($hBmp_Source, DllStructGetSize($stBitmap), DllStructGetPtr($stBitmap))

$nWidth  = DllStructGetData($stBitmap, "bmWidth")
$nHeight = DllStructGetData($stBitmap, "bmHeight")

$hWindow     = GUICreate("GDI BitBlt (Masked image)", $nWidth, $nHeight)
Global $clrBackground = 0x10A040
GUISetBkColor($clrBackground, $hWindow)

Global $clrTransparent = 0x000000   ;   BGR!
$hBmp_Mask = _CreateMask($hBmp_Source, $clrTransparent)                                     ;   Now we have our source image and its mask that we will use
                                                                                            ;   in the _OnPaint function

GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GUISetState()

While True
    If GUIGetMsg() = -3 Then ExitLoop
WEnd

_WinAPI_DeleteObject($hBmp_Mask)
_WinAPI_DeleteObject($hBmp_Source)

;   ========================================================================
;                                   FUNCTIONS
;   ========================================================================

Func _CreateMask(ByRef $hBmp_Source, $clrTransparent)
    $hDC_Dest           = _WinAPI_CreateCompatibleDC(0)                                     ;   DC (Mask)
    $hBmp_Mask          = _WinAPI_CreateBitmap($nWidth, $nHeight, 1, 1, 0)                  ;   Mask (1 bit per pixel)
    $hBmp_Mask_Prev     = _WinAPI_SelectObject($hDC_Dest, $hBmp_Mask)                       ;   Select Mask to DC

    $hDC_Source         = _WinAPI_CreateCompatibleDC(0)                                     ;   DC (Source)
    $hBmp_Source_Prev   = _WinAPI_SelectObject($hDC_Source, $hBmp_Source)                   ;   Select Source image (BMP) to DC (Source)


    _WinAPI_SetBkColor($hDC_Source, $clrTransparent)                                        ;   Set background color of the Source DC
    _WinAPI_BitBlt    ($hDC_Dest,   0, 0, $nWidth, $nHeight, $hDC_Source, 0, 0, $SRCCOPY)   ;   pixels in the "Source color bitmap" that are equal to the background color
                                                                                            ;   are blitted as white. All the remaining pixels are blitted as black.

    _WinAPI_BitBlt    ($hDC_Source, 0, 0, $nWidth, $nHeight, $hDC_Dest,   0, 0, $SRCINVERT) ;   Paint onto the original image, making sure that
                                                                                            ;   the "transparent" area is set to black.

    _WinAPI_SelectObject($hDC_Source, $hBmp_Source_Prev)                                    ;   Clean te two DCs
    _WinAPI_DeleteDC    ($hDC_Source)

    _WinAPI_SelectObject($hDC_Dest, $hBmp_Mask_Prev)
    _WinAPI_DeleteDC    ($hDC_Dest)

    Return $hBmp_Mask
EndFunc     ; ==> _CreateMask

Func _OnPaint($hWnd)
    $hDC        = _WinAPI_GetDC($hWnd)                                                      ;   DC (Screen / Window)

    $hDC_Buf    = _WinAPI_CreateCompatibleDC($hDC)                                          ;   Do all the painting on this buffer
    $hBmp_Buf   = _WinAPI_CreateCompatibleBitmap($hDC, $nWidth, $nHeight)                   ;   Then copy the content of this buffer to your Window / GUI (see 4.)
    $Buf_Prev   = _WinAPI_SelectObject($hDC_Buf, $hBmp_Buf)

    _WinAPI_BitBlt      ($hDC_Buf, 0, 0, $nWidth, $nHeight, $hDC, 0, 0, $SRCCOPY)           ;   1. Copy the content of your Window / GUI to the buffer

    $hDC_Mem    = _WinAPI_CreateCompatibleDC(0)                                             ;   Memory DC

    $hBmp_Prev  = _WinAPI_SelectObject($hDC_Mem, $hBmp_Mask)
    _WinAPI_BitBlt      ($hDC_Buf, 0, 0, $nWidth, $nHeight, $hDC_Mem, 0, 0, $SRCAND)        ;   2. (AND) BitBlt the mask to the buffer with SRCAND

    _WinAPI_SelectObject($hDC_Mem, $hBmp_Source)
    _WinAPI_BitBlt      ($hDC_Buf, 0, 0, $nWidth, $nHeight, $hDC_Mem, 0, 0, $SRCPAINT)      ;   3. (OR) BitBlt your source image to he buffer with $SRCPAINT

    _WinAPI_BitBlt($hDC, 0, 0, $nWidth, $nHeight, $hDC_Buf, 0, 0, $SRCCOPY)                 ;   4. Copy the content of the buffer back to your Window / GUI

    _WinAPI_SelectObject($hDC_Mem, $hBmp_Prev)                                              ;   Clean ressources
    _WinAPI_DeleteDC    ($hDC_Mem)

    _WinAPI_SelectObject($hDC_Buf, $Buf_Prev)
    _WinAPI_DeleteDC    ($hDC_Buf)
    _WinAPI_DeleteObject($hBmp_Buf)

    _WinAPI_ReleaseDC($hWnd, $hDC)
EndFunc     ; ==> _OnPaint

Func WM_PAINT($hWnd, $Msg, $wParam, $lParam)
    _OnPaint($hWnd)
EndFunc     ; ==> WM_PAINT

but if you load an image from (for instance) a jpg with gdi+,

you have to create a GDI hBitmap from it first.

This hBitmap is not the same as when its loaded directly with GDI.

When you bitblt it to an 1 bit per pixel Bitmap (to create a mask)

the result is all black.

If I understand it correctly, this is because it's a DIB and not a DDB.

In that case it should be "converted" to a DDB Bitmap.

I tried to do it but still without success. There is somethig incorrect in the code.

I use _GDI_CreateDIBitmap (by Prog@ndy).

RGBQuad member of BITMAPINFO has to be an array but I don't know the required

size of that array.

but from MSDN (for a 32 bpp image):

The bitmap has a maximum of 2^32 colors. If the biCompression member of the BITMAPINFOHEADER is BI_RGB, the bmiColors member of BITMAPINFO is NULL. Each DWORD in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used.

_GDI_CreateDIBitmap returns a Handle to a new bitmap but it's all black.

Here is what I tried (and is wrong).

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Don't forget to put your image there!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <GdiPlus.au3>
#include <Winapi.au3>
#include <Constants.au3>
#include <WindowsConstants.au3>

Global Const $BI_RGB         = 0
Global Const $DIB_RGB_COLORS = 0
Global Const $CBM_INIT       = 0x4

;   tagBITMAPINFOHEADER
Global Const $tagBITMAPINFOHEADER = "DWORD     biSize;" & _
                       "LONG     biWidth;" & _
                       "LONG     biHeight;" & _
                       "ushort   biPlanes;" & _
                       "ushort   biBitCount;" & _
                       "DWORD    biCompression;" & _
                       "DWORD    biSizeImage;" & _
                       "LONG     biXPelsPerMeter;" & _
                       "LONG     biYPelsPerMeter;" & _
                       "DWORD    biClrUsed;" & _
                       "DWORD    biClrImportant;"

Global Const $tagBMPInfo256 = $tagBITMAPINFOHEADER & "dword RGBQuad;"

$BMPInfo  = DllStructCreate ($tagBMPInfo256)

$stBitmap = DllStructCreate("long bmType;long bmWidth;long bmHeight;long bmWidthBytes;WORD bmPlanes;WORD bmBitsPixel;ptr bmBits")

;   =============================================

_GDIPlus_Startup()

$pImage      = _GDIPlus_ImageLoadFromFile ("HERE THE IMAGE FROM FILE PATH")
$hBmp_Source = _GDIPlus_BitmapCreateHBITMAPFromBitmap($pImage)
_GDIPlus_ImageDispose($pImage)
_GDIPlus_Shutdown()

;   =========================================================
;   Get DDC Bitmap

$hdcTmp = _WinAPI_GetDC (0)
$hdcMem = _WinAPI_CreateCompatibleDC ($hdcTmp)
_WinAPI_ReleaseDC (0, $hdcTmp)
$hBitmapOld = _WinAPI_SelectObject ($hdcMem, $hBmp_Source)

_WinAPI_GetObject($hBmp_Source, DllStructGetSize($stBitmap), DllStructGetPtr($stBitmap))
$xWidth  = DllStructGetData($stBitmap, "bmWidth")
$xHeight = DllStructGetData($stBitmap, "bmHeight")

DllStructSetData ($BMPInfo, 1, DllStructGetSize($BMPInfo))
DllStructSetData ($BMPInfo, "biWidth"      , $xWidth)
DllStructSetData ($BMPInfo, "biHeight"     , -$xHeight)
DllStructSetData ($BMPInfo, "biPlanes"     , 1)
DllStructSetData ($BMPInfo, "biBitCount"   , 32)
DllStructSetData ($BMPInfo, "biCompression", $BI_RGB)
DllStructSetData ($BMPInfo, "biSizeImage"  , $xWidth * $xHeight)
DllStructSetData ($BMPInfo, "biClrUsed"    , 2^32)


$BMPData        = DllStructCreate("byte[" & ($xWidth * $xHeight) & "]")
Local $pBMPData = DllStructGetPtr($BMPData)

$hDDC_BMP = _GDI_CreateDIBitmap($hdcMem, DllStructGetPtr($BMPInfo), 0, $pBMPData, DllStructGetPtr($BMPInfo), $DIB_RGB_COLORS)
ConsoleWrite("New Bitmap Handle: " & $hDDC_BMP & @CRLF & @CRLF)

_WinAPI_SelectObject($hdcMem, $hBitmapOld)
_WinAPI_DeleteDC    ($hdcMem)
_WinAPI_DeleteObject($hBmp_Source)

If Not $hDDC_BMP Then Exit

_WinAPI_GetObject($hDDC_BMP, DllStructGetSize($stBitmap), DllStructGetPtr($stBitmap))   ;   Get Info about the new bitmap

ConsoleWrite("Info about the new bitmap: " & @CRLF)
For $i = 1 To 7
    ConsoleWrite(DllStructGetData($stBitmap, $i) & @CRLF)
Next

;   EndOf DDC Bitmap Creation
;   ===========================================================

$nWidth  = DllStructGetData($stBitmap, "bmWidth")
$nHeight = DllStructGetData($stBitmap, "bmHeight")

$hWindow     = GUICreate("GDI BitBlt", $nWidth, $nHeight)
GUISetState()

;   ====================================================================

$hDC            = _WinAPI_GetDC($hWindow)                                           ;   DC (Screen / Window)

$hDC_Source     = _WinAPI_CreateCompatibleDC($hDC)
$hBmp_Prev      = _WinAPI_SelectObject($hDC_Source, $hDDC_BMP)

;   =====================================================================

_WinAPI_BitBlt($hDC, 0, 0, $nWidth, $nHeight, $hDC_Source, 0, 0, $SRCCOPY)      ;   BitBlt (Source to Buffer)

_WinAPI_SelectObject($hDC_Source, $hBmp_Prev)
_WinAPI_DeleteDC    ($hDC_Source)
_WinAPI_DeleteObject($hDDC_BMP)

_WinAPI_ReleaseDC($hWindow, $hDC)

While True
    If GUIGetMsg() = -3 Then ExitLoop
WEnd

Func _GDI_CreateDIBitmap($hDC, $lpbmih, $fdwInit, $lpbInit, $lpbmi, $fuUsage)
    Local $aResult = DllCall("Gdi32.dll", "ptr", "CreateDIBitmap", "ptr", $hDC, "ptr", $lpbmih, "DWORD", $fdwInit, "ptr", $lpbInit, "ptr", $lpbmi, "UINT", $fuUsage)
    If @error Then Return SetError(1, 0, 0)
    Return $aResult[0]
EndFunc   ;==>_GDI_CreateDIBitmap

Info in Console.

Thanks

(AKA Grham)

Link to comment
Share on other sites

May I ask, why do you want the black parts to be green (transparent)? Is there actually a point other than playing around with _WinAPI_BitBlt()?

:graduated:

Link to comment
Share on other sites

Hi,

if you want to blit "sprites" there are two methods:

Bitblt(background,0,0,x,y,mask,0,0,SRCAND)   ;mask AND background 

Bitblt(background,0,0,x,y,sprite,0,0,SRCINVERT)   ;sprite INVERT background

or 

Transparentblt((background,0,0,x,y,sprite,0,0,x1,y1,COLOR)   ;sprite onto background

The sprite has a backgroundcolor, which will be transparent after Transparentblt(). No mask needed....

#include <WinAPIEX.au3>
_WinAPI_transparentblt()
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...