Jump to content

Create a bitmap object with a chequered background using GDI+


Go to solution Solved by Andreik,

Recommended Posts

I have a gui that displays a colour and alters its transparency based on a sliders value. I thought it would be nice to have a background like that seen in other graphic programs. I made a bmp and successfully implemented Then I thought I would try to do it without using an external image.

I have managed to get this working but it is not smooth. The image does not fade in and out as smooth as with a bmp and the slider control tooltip jumps around. It has taken days throwing stuff at the screen to see what works but I can't sort this. The two functions that make up the main drawing operations are CV_CreateARGBBitmap and  CV_SetARGBOpacity. CV_SetARGBOpacity is butchered from a help file example.

Any advice or code improvements are welcomed. The files are attached.

Colour Viewer.au3 transparent.bmp

Link to comment
Share on other sites

  • Solution

Maybe posting a specific question without unnecessary code increase the chances that you will receive a fast answer from other users. Anyway, here is a demo that should help you. Make the necessary changes to fit your project.

 

#include <GDIPlus.au3>

_GDIPlus_Startup()

Global $hDisplay = _GDIPlus_BitmapCreateFromScan0(178, 146)
Global $hGraphics1 = _GDIPlus_ImageGetGraphicsContext($hDisplay)
Global $hColor = _GDIPlus_BitmapCreateFromScan0(178, 146)
Global $hGraphics2 = _GDIPlus_ImageGetGraphicsContext($hColor)
Global $hTransparent = _GDIPlus_BitmapCreateFromFile(@ScriptDir & '\transparent.bmp')

Global $hGUI, $cPic, $cSlider, $hSlider, $cDummy

$hGUI = GUICreate('Example', 198, 250)
$cPic = GUICtrlCreatePic('', 10, 10, 178, 146)
$cSlider = GUICtrlCreateSlider(10, 165, 178, 40)
$hSlider = GUICtrlGetHandle($cSlider)
$cColor = GUICtrlCreateInput('D62828', 10, 215, 178, 25, 0x01)
$cDummy = GUICtrlCreateDummy()
GUICtrlSetLimit($cSlider, 255, 0)
GUICtrlSetFont($cColor, 12)
GUICtrlSetData($cSlider, 127)
GUISetState(@SW_SHOW, $hGUI)

GUIRegisterMsg(0x0114, 'WM_HSCROLL')
UpdateColor()

While True
    Switch GUIGetMsg()
        Case $cDummy
            If GUICtrlRead($cDummy) = $cSlider Then UpdateColor()
        Case -3
            ExitLoop
    EndSwitch
WEnd

_GDIPlus_GraphicsDispose($hGraphics1)
_GDIPlus_GraphicsDispose($hGraphics2)
_GDIPlus_BitmapDispose($hTransparent)
_GDIPlus_BitmapDispose($hColor)
_GDIPlus_BitmapDispose($hDisplay)
_GDIPlus_Shutdown()

Func UpdateColor()
    Local $sColor = GUICtrlRead($cColor)
    Local $iAlpha = GUICtrlRead($cSlider)
    _GDIPlus_GraphicsDrawImageRect($hGraphics1, $hTransparent, 0, 0, 178, 146)
    _GDIPlus_GraphicsClear($hGraphics2, '0x' & Hex($iAlpha, 2) & $sColor)
    _GDIPlus_GraphicsDrawImageRect($hGraphics1, $hColor, 0, 0, 178, 146)
    ImageToCtrl($hDisplay, $cPic)
    GUICtrlSetTip($cSlider, $iAlpha)
EndFunc

Func ImageToCtrl($hBitmap, $cCtrl)
    Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP))
    _WinAPI_DeleteObject($hHBITMAP)
EndFunc

Func WM_HSCROLL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Switch $lParam
        Case $hSlider
            GUICtrlSendToDummy($cDummy, $cSlider)
    EndSwitch
EndFunc

 

When the words fail... music speaks.

Link to comment
Share on other sites

Firstly, thanks for the reply. I'm sure I can exchange some of my bloated code for your streamlined version. It still uses the bmp that I wanted to get away from though.

20 hours ago, benners said:

Then I thought I would try to do it without using an external image.

I posted the full code as there were other functions that may have impacted the smoothness of the fading and the slider tooltips as has happened to me in the past. I also specified the two functions that were the meat and potatoes of the drawing operations so that  anyone who would be kind enough to help could just examine those specifically'.

20 hours ago, benners said:

The two functions that make up the main drawing operations are CV_CreateARGBBitmap and  CV_SetARGBOpacity.

The CV_CreateCheckerboardBitmap function was my attempt to reproduce the transparent.bmp. It worked but not to my satisfaction. 

Cheers

Link to comment
Share on other sites

Posted (edited)
34 minutes ago, benners said:

Firstly, thanks for the reply. I'm sure I can exchange some of my bloated code for your streamlined version. It still uses the bmp that I wanted to get away from though.

It should be easy to adapt to your current code, just don't create new resources each time the slider is moving.

Edit: here is an example of how you can create the checkerboard

#include <GDIPlus.au3>

_GDIPlus_Startup()

Global $hDisplay = _GDIPlus_BitmapCreateFromScan0(178, 146)
Global $hGraphics1 = _GDIPlus_ImageGetGraphicsContext($hDisplay)
Global $hColor = _GDIPlus_BitmapCreateFromScan0(178, 146)
Global $hGraphics2 = _GDIPlus_ImageGetGraphicsContext($hColor)
Global $hTransparent = CreateTransparentLayer(178, 146)

Global $hGUI, $cPic, $cSlider, $hSlider, $cDummy

$hGUI = GUICreate('Example', 198, 250)
$cPic = GUICtrlCreatePic('', 10, 10, 178, 146)
$cSlider = GUICtrlCreateSlider(10, 165, 178, 40)
$hSlider = GUICtrlGetHandle($cSlider)
$cColor = GUICtrlCreateInput('D62828', 10, 215, 178, 25, 0x01)
$cDummy = GUICtrlCreateDummy()
GUICtrlSetLimit($cSlider, 255, 0)
GUICtrlSetFont($cColor, 12)
GUICtrlSetData($cSlider, 127)
GUISetState(@SW_SHOW, $hGUI)

GUIRegisterMsg(0x0114, 'WM_HSCROLL')
UpdateColor()

While True
    Switch GUIGetMsg()
        Case $cDummy
            If GUICtrlRead($cDummy) = $cSlider Then UpdateColor()
        Case -3
            ExitLoop
    EndSwitch
WEnd

_GDIPlus_GraphicsDispose($hGraphics1)
_GDIPlus_GraphicsDispose($hGraphics2)
_GDIPlus_BitmapDispose($hTransparent)
_GDIPlus_BitmapDispose($hColor)
_GDIPlus_BitmapDispose($hDisplay)
_GDIPlus_Shutdown()

Func UpdateColor()
    Local $sColor = GUICtrlRead($cColor)
    Local $iAlpha = GUICtrlRead($cSlider)
    _GDIPlus_GraphicsDrawImageRect($hGraphics1, $hTransparent, 0, 0, 178, 146)
    _GDIPlus_GraphicsClear($hGraphics2, '0x' & Hex($iAlpha, 2) & $sColor)
    _GDIPlus_GraphicsDrawImageRect($hGraphics1, $hColor, 0, 0, 178, 146)
    ImageToCtrl($hDisplay, $cPic)
    GUICtrlSetTip($cSlider, $iAlpha)
EndFunc

Func ImageToCtrl($hBitmap, $cCtrl)
    Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP))
    _WinAPI_DeleteObject($hHBITMAP)
EndFunc

Func CreateTransparentLayer($iWidth, $iHeight, $iSquareSize = 10, $iColor1 = 0xFFFFFFFF, $iColor2 = 0xFF808080)
    Local $hLayer = _GDIPlus_BitmapCreateFromScan0($iSquareSize * 2, $iSquareSize * 2)
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hLayer)
    Local $hBrush = _GDIPlus_BrushCreateSolid($iColor1)
    _GDIPlus_GraphicsClear($hContext, $iColor2)
    _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iSquareSize, $iSquareSize, $hBrush)
    _GDIPlus_GraphicsFillRect($hContext, $iSquareSize, $iSquareSize, $iSquareSize, $iSquareSize, $hBrush)
    Local $hTexture = _GDIPlus_TextureCreate($hLayer)
    _GDIPlus_GraphicsDispose($hContext)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_BitmapDispose($hLayer)
    $hLayer = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    $hContext = _GDIPlus_ImageGetGraphicsContext($hLayer)
    _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hTexture)
    _GDIPlus_GraphicsDispose($hContext)
    _GDIPlus_BrushDispose($hTexture)
    Return $hLayer
EndFunc

Func WM_HSCROLL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Switch $lParam
        Case $hSlider
            GUICtrlSendToDummy($cDummy, $cSlider)
    EndSwitch
EndFunc

Changing CV_CreateCheckerboardBitmap() with CreateTransparentLayer() and the lag is already gone (using your current code without any further adaptation). Of course there are other things that can be improved but right now your function is the killer with so many loops and drawing operations.

Add CreateTransparentLayer() to your current code and change this line

Local $g_hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap(CV_CreateCheckerboardBitmap($CV_RECTWIDTH, $CV_RECTHEIGHT, 5))

with

Local $g_hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap(CreateTransparentLayer($CV_RECTWIDTH, $CV_RECTHEIGHT, 5))

 

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

Well I managed to adapt your code to fit in mine and it works better than before. I had to alter the updatecolor slightly as the the input it reads from has argb format. I also got it to work with the checkerboard function as well. Happy days, Thanks.

Func CV_CreateCheckerboardBitmap()
    Local $iCheckerSize = 5 ;_                                                      define the size of each checker square
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($CV_RECTWIDTH, $CV_RECTHEIGHT) ; create a new bitmap with the specified width and height
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) ;_                get the graphics context of the bitmap
    Local $hBrush1 = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) ;_                       create white brush for the checkerboard colors
    Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFFC2C6C3) ;_                       create grey brush for the checkerboard colors

    ; Loop through the bitmap height in steps of checker size
    For $y = 0 To $CV_RECTHEIGHT - 1 Step $iCheckerSize
        ; Loop through the bitmap width in steps of checker size
        For $x = 0 To $CV_RECTWIDTH - 1 Step $iCheckerSize
            ; Determine which color to use based on the checker pattern
            If Mod($x / $iCheckerSize + $y / $iCheckerSize, 2) = 0 Then
                ; Fill the rectangle with the first brush (white)
                _GDIPlus_GraphicsFillRect($hGraphics, $x, $y, $iCheckerSize, $iCheckerSize, $hBrush1)
            Else
                ; Fill the rectangle with the second brush (black)
                _GDIPlus_GraphicsFillRect($hGraphics, $x, $y, $iCheckerSize, $iCheckerSize, $hBrush2)
            EndIf
        Next
    Next

    _GDIPlus_BrushDispose($hBrush1) ;_      dispose of the brushes
    _GDIPlus_BrushDispose($hBrush2)
    _GDIPlus_GraphicsDispose($hGraphics) ;_ dispose of the graphics context

    Return $hBitmap ; return the created bitmap
EndFunc   ;==>CV_CreateCheckerboardBitmap

I'll try your checkerboard function as well>

sshot-1.png

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...