Jump to content

[Solved] GDI+ Transparence problem by image overlapping


 Share

Recommended Posts

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
Link to comment
Share on other sites

  • Moderators

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

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

@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

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