Sign in to follow this  
Followers 0
grham

hBitmap from GDI+ bitmap

5 posts in this topic

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)

Share this post


Link to post
Share on other sites



#3 ·  Posted (edited)

I started:

here

and here

Edited by grham

Share this post


Link to post
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()

Share this post


Link to post
Share on other sites

Cool! I will give it a try this weekend.

Danke schön für die Information! :graduated:

Share this post


Link to post
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
Sign in to follow this  
Followers 0