Jump to content
Sven-Seyfert

[Solved] GDI+ Transparence problem by image overlapping

Recommended Posts

Sven-Seyfert

Hi Community,

I'm new at the forum but familiar with AutoIt since few years.

I got a problem when I drag a GDI+ loaded image on the GUI to a other position. When I drag the next image (of three) in the nearly position of the first dragged image, I got a overlapped effect which isn't transparence like I would want to have.

The animated GIF should hopefully explain my problem further (like on GitHub).

Why the GDI+ PNG images aren't transparence on the GUI?

I don't want to use a buffer system for the illustration on the GUI or do I have to?

Thanks for any suggestion - I'm grateful!
Sven

[Solved] Final solution:
Thanks to the community, especially to @UEZ and @argumentum .

CODE

Spoiler
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=..\Libraries\icon.ico
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=y
#AutoIt3Wrapper_Res_Fileversion=0.5
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

; ------------------------------------------------------------------------------
; GDIPlusGame_MapEditor (2017-11-13)
; ------------------------------------------------------------------------------

; includes ---------------------------------------------------------------------
#include-once
#include <GDIPlus.au3>
#include <GuiConstantsEx.au3>
#include <String.au3>
#include <WindowsConstants.au3>



; opt and just singleton -------------------------------------------------------
Opt( 'MustDeclareVars', 1 )
Local $aInst = ProcessList( 'GDIPlusGame_MapEditor.exe' )
If $aInst[0][0] > 1 Then Exit



; declaration ------------------------------------------------------------------
Local Const $sPathImg         = '.\tiles\'
Local Const $sExtImg          = '.png'

Local Const $iGuiWidth        = 1000
Local Const $iGuiHeight       = 690
Local Const $iGuiLeft         = 10
Local Const $iGuiTop          = 10
Local Const $iGuiTrans        = 255
Local Const $vTransColor1     = 0xABCDEF
Local Const $vTransColor2     = 0xFFABCDEF

Local $aImgInformations[4][7] = [['Object', 'Width', 'Height', 'X', 'Y', 'Id', 'Name']]



; init -------------------------------------------------------------------------
_GDIPlus_Startup()

Local $aImgWidths[4][1]
Local $iMaxImgWidth

Func _getImageObjectsForGettingWidth( $aArray, $sImgName )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        If StringLen( $i ) == 1 Then $aArray[$i][0] = _GDIPlus_ImageLoadFromFile( $sPathImg & $sImgName & '0' & $i & '_01' & $sExtImg )
        If StringLen( $i ) <> 1 Then $aArray[$i][0] = _GDIPlus_ImageLoadFromFile( $sPathImg & $sImgName & $i & '_01' & $sExtImg )
    Next
    Return $aArray
EndFunc

Func _setMaxImgWidth( $aArray )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        Local $iWidthSave = _GDIPlus_ImageGetWidth( $aArray[$i][0] )
        If $iWidthSave > $iMaxImgWidth Then $iMaxImgWidth = $iWidthSave
    Next
    Return $iMaxImgWidth
EndFunc

$aImgWidths   = _getImageObjectsForGettingWidth( $aImgWidths, 'tree' )
$iMaxImgWidth = _setMaxImgWidth( $aImgWidths )



; gui --------------------------------------------------------------------------
Local $hMainGui = GUICreate( 'GDIPlusGame_MapEditor', $iGuiWidth + $iMaxImgWidth, $iGuiHeight, $iGuiLeft, $iGuiTop, -1, $WS_EX_LAYERED )
GUISetBkColor( $vTransColor1, $hMainGui )
_WinAPI_SetLayeredWindowAttributes( $hMainGui, $vTransColor1, $iGuiTrans )
GUISetState( @SW_SHOW, $hMainGui )



; functions --------------------------------------------------------------------
Func _createGraphicsBufferSystem()
    Global $hDC       = _WinAPI_GetDC( $hMainGui )
    Global $hDCBitmap = _WinAPI_CreateCompatibleBitmap( $hDC, $iGuiWidth + $iMaxImgWidth, $iGuiHeight )
    Global $hDCBuffer = _WinAPI_CreateCompatibleDC( $hDC )
    Global $hDCObject = _WinAPI_SelectObject( $hDCBuffer, $hDCBitmap )
    Global $hGraphics = _GDIPlus_GraphicsCreateFromHDC( $hDCBuffer )
EndFunc

Func _loadImageObjects( $aArray, $sImgName )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        If StringLen( $i ) == 1 Then $aArray[$i][0] = _GDIPlus_ImageLoadFromFile( $sPathImg & $sImgName & '0' & $i & '_01' & $sExtImg )
        If StringLen( $i ) <> 1 Then $aArray[$i][0] = _GDIPlus_ImageLoadFromFile( $sPathImg & $sImgName & $i & '_01' & $sExtImg )
    Next
    Return $aArray
EndFunc

Func _getImgObjectsSize( $aArray )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        Local $hImg = $aArray[$i][0]
        $aArray[$i][1] = _GDIPlus_ImageGetWidth( $hImg )
        $aArray[$i][2] = _GDIPlus_ImageGetHeight( $hImg )
    Next
    Return $aArray
EndFunc

Func _setImgObjectsPosition( $aArray )
    Local $iTopPosOfFirstImg = 0
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        Local $iImgHeight = $aArray[$i][2]

        $aArray[$i][3] = $iGuiWidth
        $aArray[$i][4] = $iTopPosOfFirstImg

        $iTopPosOfFirstImg += $iImgHeight
    Next
    Return $aArray
EndFunc

Func _setHelpLabelsForImgObjects( $aArray )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        $aArray[$i][5] = GUICtrlCreateLabel( '', $aArray[$i][3], $aArray[$i][4], $aArray[$i][1], $aArray[$i][2] )
    Next
    Return $aArray
EndFunc

Func _setImgNameForImgObjects( $aArray, $sImgName )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        If StringLen( $i ) == 1 Then $aArray[$i][6] = $sImgName & '0' & $i & '_01'
        If StringLen( $i ) <> 1 Then $aArray[$i][6] = $sImgName & $i & '_01'
    Next
    Return $aArray
EndFunc

Func _setGraphicsMode()
    _GDIPlus_GraphicsSetSmoothingMode( $hGraphics, $GDIP_SMOOTHINGMODE_HIGHQUALITY )
    _GDIPlus_GraphicsSetPixelOffsetMode( $hGraphics, $GDIP_PIXELOFFSETMODE_HIGHQUALITY )
    Global $hBrush = _GDIPlus_BrushCreateSolid( $vTransColor2 )
EndFunc

Func _imgControlMoveLoop( $aImgs )
    ; 0 to 6 => 'Object', 'Width', 'Height', 'X', 'Y', 'Id', 'Name'
    Do
        _callGdipFillRectangle()
        _getMouseInfos( $hMainGui )

        If $iMouseLeftDown And $cHoveredCtrl Then
            Local $iCtrl = _findImgCtrl( $cHoveredCtrl, $aImgs )
            Local $iDX   = Abs( MouseGetPos( 0 ) - $aImgs[$iCtrl][3] )
            Local $iDY   = Abs( MouseGetPos( 1 ) - $aImgs[$iCtrl][4] )

            Do
                _callGdipFillRectangle()
                _getMouseInfos( $hMainGui )

                $aImgs[$iCtrl][3] = MouseGetPos( 0 ) - $iDX
                $aImgs[$iCtrl][4] = MouseGetPos( 1 ) - $iDY

                _drawImages( $aImgs )
                _performBitBlockTranfer()
            Until Not $iMouseLeftDown

            _writeImgInfosToConsole( $aImgs )
            ControlMove( $hMainGui, '', $aImgs[$iCtrl][5], $aImgs[$iCtrl][3], $aImgs[$iCtrl][4] )
        Else
            _drawImages( $aImgs )
        EndIf

        _performBitBlockTranfer()
    Until Not Sleep( 10 )
EndFunc

Func _callGdipFillRectangle()
    DllCall( $__g_hGDIPDll, 'int', 'GdipFillRectangle', 'handle', $hGraphics, 'handle', $hBrush, 'float', 0, 'float', 0, 'float', $iGuiWidth + $iMaxImgWidth, 'float', $iGuiHeight )
EndFunc

Func _getMouseInfos( $hWin )
    Global $aMouseInfos    = GUIGetCursorInfo( $hWin )
    Global $iMouseLeftDown = $aMouseInfos[2]
    Global $cHoveredCtrl   = $aMouseInfos[4]
EndFunc

Func _findImgCtrl( $iCtrl, $aArray )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        Local $iHelpLabelCtrlForImage = $aArray[$i][5]
        If $iHelpLabelCtrlForImage    = $iCtrl Then Return $i
    Next
EndFunc

Func _drawImages( $aArray )
    For $i = 1 To UBound( $aArray ) - 1 Step 1
        _GDIPlus_GraphicsDrawImageRect( $hGraphics, $aArray[$i][0], $aArray[$i][3], $aArray[$i][4], $aArray[$i][1], $aArray[$i][2] )
    Next
EndFunc

Func _performBitBlockTranfer()
    _WinAPI_BitBlt( $hDC, 0, 0, $iGuiWidth + $iMaxImgWidth, $iGuiHeight, $hDCBuffer, 0, 0, $SRCCOPY )
EndFunc

Func _writeImgInfosToConsole( $aArray )
    ConsoleWrite( _StringRepeat( '-', 81 ) & @CRLF )
    For $i = 0 To UBound( $aArray ) - 1 Step 1
        ConsoleWrite( $aArray[$i][0] & ', ' & $aArray[$i][1] & ', ' & $aArray[$i][2] & ', ' & _
                      $aArray[$i][3] & ', ' & $aArray[$i][4] & ', ' & $aArray[$i][5] & ', ' & _
                      $aArray[$i][6] & @CRLF )
    Next
EndFunc

Func _disposeAndExit()
    For $i = 1 To UBound( $aImgInformations ) - 1
        _GDIPlus_ImageDispose( $aImgInformations[$i][0] )
    Next

    _GDIPlus_BrushDispose( $hBrush )
    _GDIPlus_GraphicsDispose( $hGraphics )

    _WinAPI_SelectObject( $hDCBuffer, $hDCObject )
    _WinAPI_DeleteDC( $hDCBuffer )
    _WinAPI_DeleteObject( $hDCBitmap )
    _WinAPI_ReleaseDC( $hMainGui, $hDC )

    GUIDelete( $hMainGui )
    _GDIPlus_Shutdown()

    Exit
EndFunc



; processing -------------------------------------------------------------------
AutoItSetOption( 'GUIOnEventMode', 1 )
GUISetOnEvent( $GUI_EVENT_CLOSE, '_disposeAndExit' )

_createGraphicsBufferSystem()

Local $aImgInfos = _loadImageObjects( $aImgInformations, 'tree' )
      $aImgInfos = _getImgObjectsSize( $aImgInfos )
      $aImgInfos = _setImgObjectsPosition( $aImgInfos )
      $aImgInfos = _setHelpLabelsForImgObjects( $aImgInfos )
      $aImgInfos = _setImgNameForImgObjects( $aImgInfos, 'tree' )

_setGraphicsMode()
_imgControlMoveLoop( $aImgInfos )

AutoItSetOption( 'GUIOnEventMode', 0 )

 

BEFORE

Spoiler

ImageOverlappingWithoutTransparence.gif

AFTER

Spoiler

ImageOverlappingTransparenceSolution.gif

tree01_01.png

tree02_01.png

tree03_01.png

Edited by Sven-Seyfert
  • Like 1

// Innovation creates curiosity - curiosity innovation //

Share this post


Link to post
Share on other sites
Sven-Seyfert

I wrote the solution of my problem at post #1. Especially for you @qwert as a hint ;) .

Edited by Sven-Seyfert

// Innovation creates curiosity - curiosity innovation //

Share this post


Link to post
Share on other sites
JLogan3o13

@Sven-Seyfert simply edit your initial post and put [Solved] in front of the title.


√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
Share on other sites
qwert

Thanks for posting this question/solution. 

However, when I attempt to confirm the script, I get an unexpected result: the background of the window is transparent and properly displays the individual PNGs. But the transparency of individual PNGs is lost when they overlap.

Have I misinterpreted your intention for the script?

 

Unexpected Result.PNG

Share this post


Link to post
Share on other sites
UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
qwert

Thanks, UEZ.  Your solution works well. 

But does your response mean that the approach that the OP took can't be made to work?  I ask because the While loop (not OnEventMode) was better suited for an application that I had in mind.

Share this post


Link to post
Share on other sites
UEZ
6 hours ago, qwert said:

But does your response mean that the approach that the OP took can't be made to work?  I ask because the While loop (not OnEventMode) was better suited for an application that I had in mind.

Well, I got the same result as you have posted in #4 and I'm wondering why the solution #2 works properly for him!?!?.

But that doesn't mean that the approach he made isn't good and you can use also this way or the OnEventMode - it depends on the architecture (how to achieve the goal of your program) of your code.

The problem of objects (sprites) in GDI+ is that you cannot get information about them using the mouse cursor for drag 'n drop activities. Thus you have to find a workaround, e.g. using hidden GUI elements such as labels. The disadvantage is, as you already seen it, that the position of the hidden control is visible for a short time when you move it. There might be a way to suppress it...


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Sven-Seyfert
On 27.10.2017 at 3:46 PM, qwert said:

However, when I attempt to confirm the script, I get an unexpected result: the background of the window is transparent and properly displays the individual PNGs. But the transparency of individual PNGs is lost when they overlap.

Have I misinterpreted your intention for the script?

Hi @qwert,

no you correctly interpreted my intention. I forgot to say, that I solve the overlap problem of the PNG images with a GDI+ buffer system which I want to implement.
But the solution of @UEZ is a great help for my work.

Thank you @UEZ for the explaination that I cannot get information about the sprites by mouse and so on (I didn't know) ;) .

Thanks for your help - I'm grateful!
Sven


// Innovation creates curiosity - curiosity innovation //

Share this post


Link to post
Share on other sites
qwert
22 hours ago, Sven-Seyfert said:

that I solve the overlap problem of the PNG images with a GDI+ buffer system which I want to implement

@Sven: thanks for clarifying that.  As someone who has become interested in your particular approach (using a While loop) to manipulating images on a background, I would appreciate hearing about what changes you eventually make to solve the issues.  Being somewhat familiar with GDI+ and layered GUIs, I would like to hear if it works out ... or if you use the OnEventMode method UEZ put forth.

In either case, thanks for posting this topic and your example.

Share this post


Link to post
Share on other sites
argumentum
On 11/1/2017 at 0:24 PM, qwert said:

I would appreciate hearing about what changes you eventually make to solve the issues.

I don't mean to butt in but, this is a merge of both and ( in my view ) the solution, as @Sven-Seyfert showed a transparent background as his preference.
190926-solved-gdi-transparence-problem.png

;coded by UEZ
; https://autoit.de/index.php?thread/85580-gdi-transparenz-problem-bei-bild%C3%BCberlappung/&postID=685890#post685890

#include <GDIPlus.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

_GDIPlus_Startup()
Global $hGUI, $bExit
Global Const $iW = @DesktopWidth * 0.95, $iH = @DesktopHeight * 0.90, $iWh = $iW / 2, $iHh = $iH / 2, $sTitle = "GDI+ Test"

AutoItSetOption("GUIOnEventMode", 1)

GDIPlus_Test()

AutoItSetOption("GUIOnEventMode", 0)
_GDIPlus_Shutdown()


Func GDIPlus_Test()
    $bExit = False
    $hGUI = GUICreate($sTitle, $iW, $iH, -1, -1, -1, $WS_EX_LAYERED) ; <- changed here
    GUISetState(@SW_SHOW, $hGUI)

    GUISetBkColor( 0xABCDEF ) ; <- changed here
    _WinAPI_SetLayeredWindowAttributes( $hGUI, 0xABCDEF, 255 ) ; <- changed here

    Local Const $hDC = _WinAPI_GetDC($hGUI)
    Local Const $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH)
    Local Const $hDC_backbuffer = _WinAPI_CreateCompatibleDC($hDC)
    Local Const $DC_obj = _WinAPI_SelectObject($hDC_backbuffer, $hHBitmap)
    Local Const $hCanvas = _GDIPlus_GraphicsCreateFromHDC($hDC_backbuffer)
    _GDIPlus_GraphicsSetSmoothingMode($hCanvas, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsSetPixelOffsetMode($hCanvas, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)

    Local $aSprites[3][6], $i, $iDX, $iDY, $iControl, $aInfo, $aCtrlPos
    For $i = 0 To UBound($aSprites) - 1
        $aSprites[$i][0] = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\tree0" & $i + 1 & "_01.png")
        $aSprites[$i][1] = _GDIPlus_ImageGetWidth($aSprites[$i][0])
        $aSprites[$i][2] = _GDIPlus_ImageGetHeight($aSprites[$i][0])
        $aSprites[$i][3] = Random(0, $iW - $aSprites[$i][1], 1)
        $aSprites[$i][4] = Random(0, $iH - $aSprites[$i][2], 1)
        $aSprites[$i][5] = GUICtrlCreateLabel("", $aSprites[$i][3], $aSprites[$i][4], $aSprites[$i][1], $aSprites[$i][2])
        GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
        _GDIPlus_GraphicsDrawImageRect($hCanvas, $aSprites[$i][0], $aSprites[$i][3], $aSprites[$i][4], $aSprites[$i][1], $aSprites[$i][2])
    Next

    Local Const $hBrush_Clr = _GDIPlus_BrushCreateSolid(0xFFABCDEF), _ ; <- changed here
                $hBrush_FPS = _GDIPlus_BrushCreateSolid(0xFFABCDEF)    ; <- changed here

    $iFPS = 0
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit_About")

    Do
        DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush_Clr, "float", 0, "float", 0, "float", $iW, "float", $iH)
        $aInfo = GUIGetCursorInfo($hGUI)
        If $aInfo[2] And $aInfo[4] Then
            $iControl = FindCtrl($aInfo[4], $aSprites)
            If Not @error Then
                $iDX = Abs(MouseGetPos(0) - $aSprites[$iControl][3])
                $iDY = Abs(MouseGetPos(1) - $aSprites[$iControl][4])
                Do
                    DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush_Clr, "float", 0, "float", 0, "float", $iW, "float", $iH)
                    $aInfo = GUIGetCursorInfo($hGUI)
                    $aCtrlPos = ControlGetPos($hGUI, "", $aSprites[$iControl][5])
                    $aSprites[$iControl][3] = MouseGetPos(0) - $iDX
                    $aSprites[$iControl][4] = MouseGetPos(1) - $iDY
                    For $i = 0 To UBound($aSprites) - 1
                        _GDIPlus_GraphicsDrawImageRect($hCanvas, $aSprites[$i][0], $aSprites[$i][3], $aSprites[$i][4], $aSprites[$i][1], $aSprites[$i][2])
                    Next
                    _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY)
                Until Not $aInfo[2]
                ControlMove($hGUI, "", $aSprites[$iControl][5], $aSprites[$iControl][3], $aSprites[$iControl][4])
            EndIf
        Else
            For $i = 0 To UBound($aSprites) - 1
                _GDIPlus_GraphicsDrawImageRect($hCanvas, $aSprites[$i][0], $aSprites[$i][3], $aSprites[$i][4], $aSprites[$i][1], $aSprites[$i][2])
            Next
        EndIf

        _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY)
        If $bExit Then ExitLoop
    Until Not Sleep(10)

    For $i = 0 To UBound($aSprites) - 1
        _GDIPlus_ImageDispose($aSprites[$i][0])
    Next
    _GDIPlus_BrushDispose($hBrush_Clr)
    _GDIPlus_BrushDispose($hBrush_FPS)
    _GDIPlus_GraphicsDispose($hCanvas)
    _WinAPI_SelectObject($hDC_backbuffer, $DC_obj)
    _WinAPI_DeleteDC($hDC_backbuffer)
    _WinAPI_DeleteObject($hHBitmap)
    _WinAPI_ReleaseDC($hGUI, $hDC)
    GUIDelete($hGUI)
EndFunc   ;==>GDIPlus_Test

Func FindCtrl($iCtrl, $aArray)
    Local $i
    For $i = 0 To UBound($aArray) - 1
        If $aArray[$i][5] = $iCtrl Then Return $i
    Next
    Return SetError(0, 0, -1)
EndFunc

Func _Exit_About()
    $bExit = True
EndFunc   ;==>_Exit_About

 

Edited by argumentum
added pic.

Share this post


Link to post
Share on other sites
qwert

@augumentum:  excellent work!  It worked like you indicated it would.

And by changing one statement, I was able to have a colored backdrop for the PNGs, which was something I was hoping for.

_WinAPI_SetLayeredWindowAttributes( $hGUI, 0xABCDEe, 255 )

Granted, I haven't fully explored things in the context of a real application—like having text and JPGs on the layout—but it's a great start.

Thanks for posting.

 

Blue BG.JPG

  • Like 2

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

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.