GDI+ Anzeige von Bildern fehlerhaft bei wechselnder Grösse / Performance Tips gesucht

  • Hallo zusammen!

    Das Skript ist nur ein kleiner Auszug und ist entsprechend angepasst worden, damit es lauffähig ist.

    Folgendes Problem tritt bei mir auf:
    Sobald ich mit dem Mausrad durch ein zuvor gewähltes Bilderverzeichnis browse und ein angezeigtes Bild eine andere Auflösung hat als sein Vorgänger, wird es nur kurz dargestellt und verschwindet dann. Was bleibt, ist eine graue Fläche in der Größe des neuen Bildes.
    Die folgenden Bilder werden wieder normal angezeigt, bis die Bildauflösung wechselt., dann tritt wieder der selbe Fehler auf.
    Das geschieht zwar auch, wenn das Mausrad durch die Curser-Tasten "emuliert" wird (Funktionen: _Up und _Down), aber das Bild wird letztendlich doch angezeigt.
    -> bei Tastendruck wird die ?selbe? Nachricht an die Funktion _WM_MOUSEWHEEL gesendet wie bei Benutzung des Mausrades.

    Ich bin mir nicht sicher, ob es sich wirklich um ein GDI+ Problem handelt, oder ob ich einfach irgendwo 'nen Denkfehler eingebaut habe.

    Also habe ich folgende Fragen:
    1. Wieso werden Bilder bei Benutzung des Mausrades nicht angezeigt, wenn die Auflösung wechselt? (Fenster wird mit WinMove angepasst)
    1.1. Nachtrag: Jetzt mußte ich feststellen, dass der Fehler auch beim Minimieren und Wiederherstellen des Fensters auftritt (Maus-Klick aufs Taskbar-Icon). Die WM_PAINT Message wird aber laut Konsole verarbeitet und funktioniert auch noch, wenn man das Bild anschliessend bewegt.
    2. Wie kann ich erreichen, dass das vorige Bild erst gelöscht wird, wenn das neue Bild im Buffer zur Verfügung steht und geblittet werden kann, so dass bei großen Bildern nicht zuerst diese graue Fläche zu sehen ist?

    Weitere Fragen:
    3. Wie kann ich ein Kontext Menü (Zeilen 84-87) auf das Fenster (Bild) legen? Die Möglichkeit, das Fenster mit der Maus zu bewegen darf nicht wegfallen.
    4. Gibt es eine Methode, das Flackern (Tearing) beim Bildwechsel zu beseitigen? Eigendlich dachte ich, dass das durch die Benutzung des Buffers geschieht, was aber nicht der Fall ist. Stickwort: vSync?
    5. Durch die Benutzung des Buffers und WM_PAINT wird das Bild schon relativ schnell dargestellt, wenn sich Teile ausserhalb des Bildschirms befinden (deutlich schneller, als ohne Buffer). Geht das noch schneller, da es immer noch hakt?

    Da die beschriebenen "Effekte" besonders deutlich bei sehr großen Bildern zu sehen sind habe ich eine Funktion eingebaut, einige aus dem Internet zu laden, falls lokal keine vorhanden sind (Abbruch klicken bei Verzeichnisauswahl).

    Und noch eine allgemeine Frage:
    6. Hat noch jemand Tips, die Bilddarstellung zu optimieren, um noch mehr Geschwindigkeit rauszuholen?


    Und nach soviel Text, hier noch das Skript:

    Spoiler anzeigen
    [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)
    Opt("MustDeclareVars", 1)

    [/autoit] [autoit][/autoit] [autoit]

    OnAutoItExitRegister("_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    Global $hBitmap, $hBuffer, $path, $aFileList, $hGUI, $hImage, $iCounter, $hGraphic, $iScreenHeight, $idMsg, $iScreenWidth, $aPos[2] = [0, 0]

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $path = FileSelectFolder("Bilder-Verzeichnis wählen", "")
    If @error Then ;==> Bilderdownload anbieten, wenn kein Verzeichnis gewählt wird
    $idMsg = MsgBox(36, "Bilder laden...?", "Kein Verzeichnis gewählt. " & _
    "Sollen einige (große) Bilder von der Seite interfacelift.com geladen werden?" & @CRLF & _
    "Die 5 höchstbewerteten Bilder mit ~3840 Pixeln Breite (ca. 21 MB)")
    If $idMsg = 6 Then
    $path = @TempDir & "\_temp"
    DirCreate($path)
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02348_caltonhilledinburgh_3840x1024.jpg", $path & "\Bild1.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/03309_damnationcreektrail_3840x2400.jpg", $path & "\Bild2.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02544_aniconfromanewangle_3840x1024.jpg", $path & "\Bild3.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02554_shaftwoods_3840x1024.jpg", $path & "\Bild4.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02367_easternshoresunrise_3840x1024.jpg", $path & "\Bild5.jpg")
    Else
    Exit
    EndIf
    EndIf
    ;$aFileList = _FileListToArray($path, "*.jpg")
    $aFileList = _FileListToArrayMultiSelect($path, "*.gif,*.ico,*.jpg,*.jpeg,*.png,*.bmp", ",", 1)
    If $aFileList[0] = 0 Then MsgBox(16, "Keine Bilder", "Das Verzeichnis enthält keine Bilder." & @CRLF & "Bitte in folgendem Fenster ein korrektes Verzeichnis auswählen oder Abbrechen wählen...", 5)
    Until $aFileList[0] <> 0

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("Show PIC", Default, Default, Default, Default, $WS_POPUP + $WS_MINIMIZEBOX)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    _Benchmark() ;==> einmal alle Bilder eines Verzeichnisses anzeigen und benötigte Zeit in der Konsole ausgeben

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN") ;==> Fenster mit Maus bewegen
    GUIRegisterMsg($WM_PAINT, "_WM_PAINT") ;==> Bild neu zeichnen, wenn es (teilweise) ausserhalb des Bildschirms war
    GUIRegisterMsg($WM_MOUSEWHEEL, "_WM_MOUSEWHEEL") ;==> nächstes/vorheriges Bild
    GUIRegisterMsg($WM_ACTIVATE, "_WM_ACTIVATE") ;==> Curser Tasten (Up/Down) nur abfragen, wenn Fenster aktiv

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While Sleep(1000)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Show()
    HotKeySet("{UP}") ;==> keine Tasten abfangen während das Bild angezeigt wird, dadurch werden Bilder nur fortlaufend angezeigt, solange die Taste gedrückt ist
    HotKeySet("{DOWN}") ;==> wichtig zB bei sehr großen Bildern
    Local $iWidth, $iHeight, $paint, $idExit, $idContext, $idDummy, $hRgn
    Local Static $bDurchlauf = False
    Local Static $iScreenWidthOld, $iScreenHeightOld

    [/autoit] [autoit][/autoit] [autoit]

    $hImage = _GDIPlus_ImageLoadFromFile($path & "\" & $aFileList[$iCounter])

    [/autoit] [autoit][/autoit] [autoit]

    $iHeight = _GDIPlus_ImageGetHeight($hImage)
    $iWidth = _GDIPlus_ImageGetWidth($hImage)
    $iScreenHeight = Int(($iHeight * (@DesktopHeight / $iHeight)) - 40) ; Bild immer an Bildschirmhöhe anpassen minus Taskbar (Win 7, Taskbar unten)
    $iScreenWidth = Int($iWidth * ($iScreenHeight / $iHeight)) ; Anpassung an individuelle Konfiguration folgt

    [/autoit] [autoit][/autoit] [autoit]

    ;ConsoleWrite($iScreenWidth & " X " & $iScreenHeight & @CRLF)
    ;ConsoleWrite($aFileList[$iCounter] & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Switch $bDurchlauf ;==> werden die Grafiken direkt nach Anzeige gelöscht, hat WM_PAINT nichts zum anzeigen, daher in dieser Reihenfolge
    Case False ;==> nur beim ersten Durchlauf ausführen
    WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)

    [/autoit] [autoit][/autoit] [autoit]

    #cs ; Wenn das Menü aktiviert ist, funktioniert das Bewegen des Fensters mit der Maus nicht mehr. Wie gehts richtig???
    $idDummy = GUICtrlCreateLabel("", 0, 0, $iScreenWidth, $iScreenHeight)
    $idContext = GUICtrlCreateContextMenu($idDummy)
    $idExit = GUICtrlCreateMenuItem("Beenden", $idContext)
    GUICtrlSetState($idExit, "_Exit")
    #ce

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    $bDurchlauf = True
    Case Else ;==> darf beim ersten Durchlauf nicht ausgeführt werden
    Select
    Case $iScreenWidthOld <> $iScreenWidth Or $iScreenHeightOld <> $iScreenHeight ;==> nur ausführen, wenn sich die Bildgröße ändert

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hBuffer)
    _GDIPlus_BitmapDispose($hBitmap)
    WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    EndSelect
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    ;WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)
    ;$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    ;$hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    ;$hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($hBuffer, $hImage, 0, 0, $iScreenWidth, $iScreenHeight)
    $paint = _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    If $paint = False Then Beep(1500, 50) ;nur zum debuggen

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_ImageDispose($hImage)

    [/autoit] [autoit][/autoit] [autoit]

    $iScreenWidthOld = $iScreenWidth
    $iScreenHeightOld = $iScreenHeight
    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")
    EndFunc ;==>_Show

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_PAINT() ;==> ist das die beste/schnellste Lösung???
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    ConsoleWrite("WM_PAINT: " & $aFileList[$iCounter] & " -> " & $aPos[0] & "/" & $aPos[1] & " -> " & $iScreenHeight & " X " & $iScreenWidth & @CRLF)
    EndFunc ;==>_WM_PAINT

    [/autoit] [autoit][/autoit] [autoit]

    Func _Benchmark()
    Local $begin
    $begin = TimerInit()
    For $i = 1 To $aFileList[0]
    ;0x00780000, 0xFF880000
    _WM_MOUSEWHEEL(Default, Default, 0xFF880000, Default)
    Next
    ConsoleWrite(TimerDiff($begin) / 1000 & @CRLF)
    ;MsgBox(0, "", TimerDiff($begin) / 1000)
    EndFunc ;==>_Benchmark

    [/autoit] [autoit][/autoit] [autoit]

    Func _Down()
    _WM_MOUSEWHEEL(Default, Default, 0xFF880000, Default)
    EndFunc ;==>_Down

    [/autoit] [autoit][/autoit] [autoit]

    Func _Up()
    _WM_MOUSEWHEEL(Default, Default, 0x00780000, Default)
    EndFunc ;==>_Up

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_MOUSEWHEEL($hWnd, $iMsg, $iWParam, $iLParam)
    ;#forceref $hWnd, $iMsg, $iWParam, $iLParam
    Local $_iWParam
    ConsoleWrite($hWnd & "->" & $iMsg & "->" & $iWParam & "->" & $iLParam & "->>" & BitShift($iWParam, 16) & "->" & $iCounter & @CRLF)
    $_iWParam = BitShift($iWParam, 16) ;mögliche Werte für $iWParam 0x00780000, 0xFF880000

    [/autoit] [autoit][/autoit] [autoit]

    If $_iWParam < 0 Then ; If $iWParam = 0xFF880000 Then
    $iCounter += 1
    If $iCounter > $aFileList[0] Then $iCounter = 1
    Else
    $iCounter -= 1
    If $iCounter < 1 Then $iCounter = $aFileList[0]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    _Show()
    EndFunc ;==>_WM_MOUSEWHEEL

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayMultiSelect($dir, $searchlist, $Separator, $iFlag = 0)
    Local $aFileList[1] = [0], $aFileList1, $iN, $Num, $search
    $search = StringSplit($searchlist, $Separator)
    If $search[0] > 0 Then
    For $iN = 1 To $search[0]
    $aFileList1 = _FileListToArray($dir, $search[$iN], $iFlag)
    If Not @error Then
    $Num = UBound($aFileList)
    _ArrayConcatenate($aFileList, $aFileList1)
    $aFileList[0] = $aFileList[0] + $aFileList[$Num]
    _ArrayDelete($aFileList, $Num)
    EndIf
    Next
    EndIf
    Return $aFileList
    EndFunc ;==>_FileListToArrayMultiSelect

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_ACTIVATE()
    Switch WinActive("Show PIC")
    Case 0
    HotKeySet("{UP}")
    HotKeySet("{DOWN}")
    Case Else
    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")
    EndSwitch
    EndFunc ;==>_WM_ACTIVATE

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam) ;==> Fenster mit Maus bewegen
    If BitAND(WinGetState($hWnd), 32) Then Return $GUI_RUNDEFMSG
    DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", $WM_SYSCOMMAND, "int", 0xF009, "int", 0)
    $aPos = WinGetPos("Show PIC")
    EndFunc ;==>_WM_LBUTTONDOWN

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Local $delete
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hBuffer)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
    If FileExists(@TempDir & "\_temp\") Then
    $delete = DirRemove(@TempDir & "\_temp\", 1)
    If $delete = 0 Then MsgBox(16, "Fehler", "Das temporäre Verzeichnis '" & @TempDir & "\_temp\" & "konnte nicht gelöscht werden.")
    EndIf
    Exit
    EndFunc ;==>_Exit

    [/autoit]


    Vielen Dank an alle, die bereit sind, sich freiwillig durch den Text und das Skript zu quälen... :love:


    Sanfte Grüße :D

  • Die RegisterMsg-Funktionen müssen so schnell wie möglich abgearbeitet werden.
    Die Funktion _Show braucht zu lange und sollte deshalb nicht in _WM_MOUSEWHEEL aufgerufen werden.

    Des weiteren brauchen diese Funktionen noch den Rückgabewert $GUI_RUNDEFMSG

    Du kannst _Show() in _WM_MOUSEWHEEL allerdings so aufrufen:

    [autoit]

    AdlibRegister("_Show", 250)
    Return $GUI_RUNDEFMSG

    [/autoit]

    und in der ersten Zeile von _Show:

    [autoit]

    AdlibUnRegister("_Show")

    [/autoit]

    Beim Wiederherstellen hilft

    [autoit]

    GUIRegisterMsg($WM_ERASEBKGND, "_WM_ERASEBKGND")

    [/autoit]


    wobei diese Funktion genau wie _WM_PAINT aussieht, mit dem Unterschied, dass du TRUE statt $GUI_RUNDEFMSG als Rückgabewert verwendest

    E

  • Hab den Aufbau leider nicht ganz verstanden.
    Was immer hilft ist idr BitBlt statt GDI+. (ca. 10x schneller).
    Habe mal das Skript umgebaut auf DCs statt GFX, damit ist das Tempo ne Ecke höher (beim Zeichnen).
    GDI kommt aber mit dem Skalieren nicht richtig klar (kann man glaube ich über einen Modus beheben, habe ich aber auf die schnelle nicht gefunden udn ich muss jetzt weg).
    Optimal wäre es (für die Performance) wenn man die Bilder vorskalieren würde (mit GDI+ und Interpolationmode). Da man das Fenster nur verkleinern kann dürfte das Skalieren trotzdem funktionieren, und das Programm schiebt nicht jedes Mal 100MB durchs RAM. (Jaaa 100MB für eine 3kx1k Bitmap, im RAM ist nichts komprimiert wie bei JPG)

    Das folgende kannst du wahrscheinlich direkt in die Tonne kloppen, aber drüberschauen hilft dir villeicht dein Skript zu verbessern.

    Spoiler anzeigen
    [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)
    Opt("MustDeclareVars", 1)

    [/autoit] [autoit][/autoit] [autoit]

    OnAutoItExitRegister("_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    Global $hDC_GUI, $hImg_Buffer, $hImg_Bild, $hDC_Buffer, $bNopaint = False
    Global $hBitmap, $hBuffer, $path, $aFileList, $hGUI, $hImage, $iCounter, $hGraphic, $iScreenHeight, $idMsg, $iScreenWidth, $aPos[2] = [0, 0], $iCounterAlt

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $path = FileSelectFolder("Bilder-Verzeichnis wählen", "")
    If @error Then ;==> Bilderdownload anbieten, wenn kein Verzeichnis gewählt wird
    $idMsg = MsgBox(36, "Bilder laden...?", "Kein Verzeichnis gewählt. " & _
    "Sollen einige (große) Bilder von der Seite interfacelift.com geladen werden?" & @CRLF & _
    "Die 5 höchstbewerteten Bilder mit ~3840 Pixeln Breite (ca. 21 MB)")
    If $idMsg = 6 Then
    $path = @TempDir & "\_temp"
    if Not FileExists($path) Then
    DirCreate($path)
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02348_caltonhilledinburgh_3840x1024.jpg", $path & "\Bild1.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/03309_damnationcreektrail_3840x2400.jpg", $path & "\Bild2.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02544_aniconfromanewangle_3840x1024.jpg", $path & "\Bild3.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02554_shaftwoods_3840x1024.jpg", $path & "\Bild4.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02367_easternshoresunrise_3840x1024.jpg", $path & "\Bild5.jpg")
    EndIf
    Else
    Exit
    EndIf
    EndIf
    ;$aFileList = _FileListToArray($path, "*.jpg")
    $aFileList = _FileListToArrayMultiSelect($path, "*.gif,*.ico,*.jpg,*.jpeg,*.png,*.bmp", ",", 1)
    If $aFileList[0] = 0 Then MsgBox(16, "Keine Bilder", "Das Verzeichnis enthält keine Bilder." & @CRLF & "Bitte in folgendem Fenster ein korrektes Verzeichnis auswählen oder Abbrechen wählen...", 5)
    Until $aFileList[0] <> 0

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("Show PIC", Default, Default, Default, Default, $WS_POPUP + $WS_MINIMIZEBOX)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hDC_GUI = _WinAPI_GetDC($hGUI)
    $hImg_Buffer = _Image_Create(@DesktopWidth, @DesktopHeight)
    $hDC_Buffer = DllStructGetData($hImg_Buffer, 1, 1)
    ;~ $hBuffer = _GDIPlus_GraphicsCreateFromHDC($hDC_Buffer)

    [/autoit] [autoit][/autoit] [autoit]

    ;~ _Benchmark() ;==> einmal alle Bilder eines Verzeichnisses anzeigen und benötigte Zeit in der Konsole ausgeben

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN") ;==> Fenster mit Maus bewegen
    GUIRegisterMsg($WM_PAINT, "_WM_PAINT") ;==> Bild neu zeichnen, wenn es (teilweise) ausserhalb des Bildschirms war
    GUIRegisterMsg($WM_MOUSEWHEEL, "_WM_MOUSEWHEEL") ;==> nächstes/vorheriges Bild
    GUIRegisterMsg($WM_ACTIVATE, "_WM_ACTIVATE") ;==> Curser Tasten (Up/Down) nur abfragen, wenn Fenster aktiv

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While Sleep(10)
    If $iCounter <> $iCounterAlt Then
    ToolTip($iCounter)
    $iCounterAlt = $iCounter
    _Show()
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Show()
    HotKeySet("{UP}") ;==> keine Tasten abfangen während das Bild angezeigt wird, dadurch werden Bilder nur fortlaufend angezeigt, solange die Taste gedrückt ist
    HotKeySet("{DOWN}") ;==> wichtig zB bei sehr großen Bildern
    Local $iWidth, $iHeight, $paint, $idExit, $idContext, $idDummy, $hRgn
    Local Static $bDurchlauf = False
    Local Static $iScreenWidthOld, $iScreenHeightOld

    [/autoit] [autoit][/autoit] [autoit]

    ;~ $hImage = _GDIPlus_ImageLoadFromFile($path & "\" & $aFileList[$iCounter])
    $hImg_Bild = _Image_CreateFromFile($path & "\" & $aFileList[$iCounter])

    [/autoit] [autoit][/autoit] [autoit]

    $iWidth = DllStructGetData($hImg_Bild, 1, 2)
    $iHeight = DllStructGetData($hImg_Bild, 1, 3)

    [/autoit] [autoit][/autoit] [autoit]

    ;~ $iHeight = _GDIPlus_ImageGetHeight($hImage)
    ;~ $iWidth = _GDIPlus_ImageGetWidth($hImage)
    $iScreenHeight = Int(($iHeight * (@DesktopHeight / $iHeight)) - 40) ; Bild immer an Bildschirmhöhe anpassen minus Taskbar (Win 7, Taskbar unten)
    $iScreenWidth = Int($iWidth * ($iScreenHeight / $iHeight)) ; Anpassung an individuelle Konfiguration folgt

    [/autoit] [autoit][/autoit] [autoit]

    ;ConsoleWrite($iScreenWidth & " X " & $iScreenHeight & @CRLF)
    ;ConsoleWrite($aFileList[$iCounter] & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Switch $bDurchlauf ;==> werden die Grafiken direkt nach Anzeige gelöscht, hat WM_PAINT nichts zum anzeigen, daher in dieser Reihenfolge
    Case False ;==> nur beim ersten Durchlauf ausführen
    WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)

    [/autoit] [autoit][/autoit] [autoit]

    #cs ; Wenn das Menü aktiviert ist, funktioniert das Bewegen des Fensters mit der Maus nicht mehr. Wie gehts richtig???
    $idDummy = GUICtrlCreateLabel("", 0, 0, $iScreenWidth, $iScreenHeight)
    $idContext = GUICtrlCreateContextMenu($idDummy)
    $idExit = GUICtrlCreateMenuItem("Beenden", $idContext)
    GUICtrlSetState($idExit, "_Exit")
    #ce

    [/autoit] [autoit][/autoit] [autoit]

    ;~ $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    ;~ $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    ;~ $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    $bDurchlauf = True
    Case Else ;==> darf beim ersten Durchlauf nicht ausgeführt werden
    Select
    Case $iScreenWidthOld <> $iScreenWidth Or $iScreenHeightOld <> $iScreenHeight ;==> nur ausführen, wenn sich die Bildgröße ändert

    [/autoit] [autoit][/autoit] [autoit]

    ;~ _GDIPlus_GraphicsDispose($hGraphic)
    ;~ _GDIPlus_GraphicsDispose($hBuffer)
    ;~ _GDIPlus_BitmapDispose($hBitmap)
    WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)
    $bNopaint = True

    [/autoit] [autoit][/autoit] [autoit]

    _Image_Delete($hImg_Buffer)
    $hImg_Buffer = _Image_Create($iScreenWidth, $iScreenHeight)
    $hDC_Buffer = DllStructGetData($hImg_Buffer, 1, 1)
    $bNopaint = False
    ;~ $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    ;~ $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    ;~ $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    EndSelect
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    ;WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)
    ;$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    ;$hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    ;$hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_StretchBlt($hDC_Buffer, 0, 0, $iScreenWidth, $iScreenHeight, DllStructGetData($hImg_Bild, 1, 1), 0, 0, $iWidth, $iHeight, 0xCC0020)
    _WM_PAINT()
    ;~ _GDIPlus_GraphicsDrawImageRect($hBuffer, $hImage, 0, 0, $iScreenWidth, $iScreenHeight)
    ;~ $paint = _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    ;~ If $paint = False Then Beep(1500, 50) ;nur zum debuggen

    [/autoit] [autoit][/autoit] [autoit]

    _Image_Delete($hImg_Bild)
    ;~ _GDIPlus_ImageDispose($hImage)

    [/autoit] [autoit][/autoit] [autoit]

    $iScreenWidthOld = $iScreenWidth
    $iScreenHeightOld = $iScreenHeight
    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")
    EndFunc ;==>_Show

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_PAINT() ;==> ist das die beste/schnellste Lösung???
    If $bNopaint Then Return
    _WinAPI_BitBlt($hDC_GUI, 0, 0, $iScreenWidth, $iScreenHeight, $hDC_Buffer, 0, 0, 0xCC0020)
    ;~ _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    ConsoleWrite("WM_PAINT: " & $aFileList[$iCounter] & " -> " & $aPos[0] & "/" & $aPos[1] & " -> " & $iScreenHeight & " X " & $iScreenWidth & @CRLF)
    EndFunc ;==>_WM_PAINT

    [/autoit] [autoit][/autoit] [autoit]

    Func _Benchmark()
    Local $begin
    $begin = TimerInit()
    For $i = 1 To $aFileList[0]
    ;0x00780000, 0xFF880000
    _WM_MOUSEWHEEL(Default, Default, 0xFF880000, Default)
    Next
    ConsoleWrite(TimerDiff($begin) / 1000 & @CRLF)
    ;MsgBox(0, "", TimerDiff($begin) / 1000)
    EndFunc ;==>_Benchmark

    [/autoit] [autoit][/autoit] [autoit]

    Func _Down()
    _WM_MOUSEWHEEL(Default, Default, 0xFF880000, Default)
    EndFunc ;==>_Down

    [/autoit] [autoit][/autoit] [autoit]

    Func _Up()
    _WM_MOUSEWHEEL(Default, Default, 0x00780000, Default)
    EndFunc ;==>_Up

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_MOUSEWHEEL($hWnd, $iMsg, $iWParam, $iLParam)
    ;#forceref $hWnd, $iMsg, $iWParam, $iLParam
    Local $_iWParam
    ConsoleWrite($hWnd & "->" & $iMsg & "->" & $iWParam & "->" & $iLParam & "->>" & BitShift($iWParam, 16) & "->" & $iCounter & @CRLF)
    $_iWParam = BitShift($iWParam, 16) ;mögliche Werte für $iWParam 0x00780000, 0xFF880000

    [/autoit] [autoit][/autoit] [autoit]

    If $_iWParam < 0 Then ; If $iWParam = 0xFF880000 Then
    $iCounter += 1
    If $iCounter > $aFileList[0] Then $iCounter = 1
    Else
    $iCounter -= 1
    If $iCounter < 1 Then $iCounter = $aFileList[0]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;~ _Show()
    EndFunc ;==>_WM_MOUSEWHEEL

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayMultiSelect($dir, $searchlist, $Separator, $iFlag = 0)
    Local $aFileList[1] = [0], $aFileList1, $iN, $Num, $search
    $search = StringSplit($searchlist, $Separator)
    If $search[0] > 0 Then
    For $iN = 1 To $search[0]
    $aFileList1 = _FileListToArray($dir, $search[$iN], $iFlag)
    If Not @error Then
    $Num = UBound($aFileList)
    _ArrayConcatenate($aFileList, $aFileList1)
    $aFileList[0] = $aFileList[0] + $aFileList[$Num]
    _ArrayDelete($aFileList, $Num)
    EndIf
    Next
    EndIf
    Return $aFileList
    EndFunc ;==>_FileListToArrayMultiSelect

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_ACTIVATE()
    Switch WinActive("Show PIC")
    Case 0
    HotKeySet("{UP}")
    HotKeySet("{DOWN}")
    Case Else
    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")
    EndSwitch
    EndFunc ;==>_WM_ACTIVATE

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam) ;==> Fenster mit Maus bewegen
    If BitAND(WinGetState($hWnd), 32) Then Return $GUI_RUNDEFMSG
    DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", $WM_SYSCOMMAND, "int", 0xF009, "int", 0)
    $aPos = WinGetPos("Show PIC")
    EndFunc ;==>_WM_LBUTTONDOWN

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Local $delete
    _Image_Delete($hImg_Buffer)
    _WinAPI_ReleaseDC($hGUI, $hDC_GUI)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hBuffer)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
    ;~ If FileExists(@TempDir & "\_temp\") Then
    ;~ $delete = DirRemove(@TempDir & "\_temp\", 1)
    ;~ If $delete = 0 Then MsgBox(16, "Fehler", "Das temporäre Verzeichnis '" & @TempDir & "\_temp\" & "konnte nicht gelöscht werden.")
    ;~ EndIf
    Exit
    EndFunc ;==>_Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Create($iW, $iH) ; Flottes DC Image basteln mit GDI+ Puffer
    Local $Ptr, $hDC, $hBmp, $tBMI, $aDIB, $vStruct
    $hDC = _WinAPI_CreateCompatibleDC(0)
    $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, 'Size', DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, 'Width', $iW)
    DllStructSetData($tBMI, 'Height', -$iH)
    DllStructSetData($tBMI, 'Planes', 1)
    DllStructSetData($tBMI, 'BitCount', 32)
    $aDIB = DllCall('GDI32.DLL', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hBmp = $aDIB[0]
    $Ptr = $aDIB[4]
    _WinAPI_SelectObject($hDC, $hBmp)
    $vStruct = DllStructCreate('int[5]')
    DllStructSetData($vStruct, 1, $hDC, 1)
    DllStructSetData($vStruct, 1, $iW, 2)
    DllStructSetData($vStruct, 1, $iH, 3)
    DllStructSetData($vStruct, 1, $Ptr, 4)
    DllStructSetData($vStruct, 1, $hBmp, 5)
    Return $vStruct
    EndFunc ;==>_Image_Create

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_CreateFromFile($s) ; DC Image aus Datei
    Local $hBmp = _GDIPlus_ImageLoadFromFile($s)
    Local $vImg = _Image_Create(_GDIPlus_ImageGetWidth($hBmp), _GDIPlus_ImageGetHeight($hBmp))
    Local $hGfx = _GDIPlus_GraphicsCreateFromHDC(DllStructGetData($vImg, 1, 1))
    _GDIPlus_GraphicsDrawImage($hGfx, $hBmp, 0, 0)
    _GDIPlus_GraphicsDispose($hGfx)
    _GDIPlus_ImageDispose($hBmp)
    Return $vImg
    EndFunc ;==>_Image_CreateFromFile

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Delete(ByRef $vStruct)
    If Not $vStruct Then Return
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

    [/autoit] [autoit][/autoit] [autoit]

    Func _WinAPI_StretchBlt($hDestDC, $iXDest, $iYDest, $iWidth, $iHeight, $hSrcDC, $iXSrc, $iYSrc, $iWidthSrc, $iHeightSrc, $iROP)
    DllCall('GDI32.DLL', 'int', 'StretchBlt', 'hwnd', $hDestDC, 'int', $iXDest, 'int', $iYDest, 'int', $iWidth, 'int', $iHeight, 'hwnd', $hSrcDC, 'int', $iXSrc, 'int', $iYSrc, 'int', $iWidthSrc, 'int', $iHeightSrc, 'int', $iROP)
    EndFunc ;==>_WinAPI_StretchBlt

    [/autoit]

    lg
    Mars

  • eukalyptus:

    ...erstmal vielen dank für deine Mühe :thumbup:

    Ich habe die empfohlenen Änderungen vorgenommen und das Skript läuft jetzt tatsächlich besser, aber leider immer noch sehr "unrund"...
    Neben gelegendlichen Abstürzen fühlt sich das Browsen nun nicht mehr "richtig" an. Man bekommt kein direktes Feedback, sondern hat eine (wenn auch kleine) irritierende Verzögerung.


    Die RegisterMsg-Funktionen müssen so schnell wie möglich abgearbeitet werden.
    Die Funktion _Show braucht zu lange und sollte deshalb nicht in _WM_MOUSEWHEEL aufgerufen werden.

    Wieso bekomme ich keine "Grey Screens" wenn ich _WM_MOUSEWHEEL mit den Hotkeys aufrufe? Ist das so viel schneller, als die Maus abzufragen?

    Des weiteren brauchen diese Funktionen noch den Rückgabewert $GUI_RUNDEFMSG

    Wieso sollte man das so machen? Was hat es mit dem "internen Handler für eine Nachricht", der in der Hilfe erwähnt wird, auf sich?

    Beim Wiederherstellen hilft

    [autoit]

    GUIRegisterMsg($WM_ERASEBKGND, "_WM_ERASEBKGND")

    [/autoit]


    wobei diese Funktion genau wie _WM_PAINT aussieht, mit dem Unterschied, dass du TRUE statt $GUI_RUNDEFMSG als Rückgabewert verwendest

    Das funktioniert super! Deutlicher Performancegewinn :thumbup:

    Hier mal das "bereinigte" Skript:

    Spoiler anzeigen
    [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)
    Opt("MustDeclareVars", 1)

    [/autoit] [autoit][/autoit] [autoit]

    OnAutoItExitRegister("_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    Global $hBitmap, $hBuffer, $path, $aFileList, $hGUI, $hImage, $iCounter, $hGraphic, $iScreenHeight, $idMsg, $iScreenWidth, $aPos[2] = [0, 0]

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $path = FileSelectFolder("Bilder-Verzeichnis wählen", "")
    If @error Then ;==> Bilderdownload anbieten, wenn kein Verzeichnis gewählt wird
    $idMsg = MsgBox(36, "Bilder laden...?", "Kein Verzeichnis gewählt. " & _
    "Sollen einige (große) Bilder von der Seite interfacelift.com geladen werden?" & @CRLF & _
    "Die 5 höchstbewerteten Bilder mit ~3840 Pixeln Breite (ca. 21 MB)")
    If $idMsg = 6 Then
    $path = @TempDir & "\_temp"
    DirCreate($path)
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02348_caltonhilledinburgh_3840x1024.jpg", $path & "\Bild1.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/03309_damnationcreektrail_3840x2400.jpg", $path & "\Bild2.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02544_aniconfromanewangle_3840x1024.jpg", $path & "\Bild3.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02554_shaftwoods_3840x1024.jpg", $path & "\Bild4.jpg")
    InetGet("http://interfacelift.com/wallpaper/7yz4ma1/02367_easternshoresunrise_3840x1024.jpg", $path & "\Bild5.jpg")
    Else
    Exit
    EndIf
    EndIf
    ;$aFileList = _FileListToArray($path, "*.jpg")
    $aFileList = _FileListToArrayMultiSelect($path, "*.gif,*.ico,*.jpg,*.jpeg,*.png,*.bmp", ",", 1)
    If $aFileList[0] = 0 Then MsgBox(16, "Keine Bilder", "Das Verzeichnis enthält keine Bilder." & @CRLF & "Bitte in folgendem Fenster ein korrektes Verzeichnis auswählen oder Abbrechen wählen...", 5)
    Until $aFileList[0] <> 0

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("Show PIC", Default, Default, Default, Default, $WS_POPUP + $WS_MINIMIZEBOX)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    _Benchmark() ;==> einmal alle Bilder eines Verzeichnisses anzeigen und benötigte Zeit in der Konsole ausgeben

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN") ;==> Fenster mit Maus bewegen
    ;GUIRegisterMsg($WM_PAINT, "_WM_PAINT") ;==> Bild neu zeichnen, wenn es (teilweise) ausserhalb des Bildschirms war
    GUIRegisterMsg($WM_ERASEBKGND, "_WM_ERASEBKGND")
    GUIRegisterMsg($WM_MOUSEWHEEL, "_WM_MOUSEWHEEL") ;==> nächstes/vorheriges Bild
    GUIRegisterMsg($WM_ACTIVATE, "_WM_ACTIVATE") ;==> Curser Tasten (Up/Down) nur abfragen, wenn Fenster aktiv

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While Sleep(1000)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Show()
    AdlibUnRegister("_Show")
    HotKeySet("{UP}") ;==> keine Tasten abfangen während das Bild angezeigt wird, dadurch werden Bilder nur fortlaufend angezeigt, solange die Taste gedrückt ist
    HotKeySet("{DOWN}") ;==> wichtig zB bei sehr großen Bildern
    Local $iWidth, $iHeight, $paint, $idExit, $idContext, $idDummy, $hRgn
    Local Static $bDurchlauf = False
    Local Static $iScreenWidthOld, $iScreenHeightOld

    [/autoit] [autoit][/autoit] [autoit]

    $hImage = _GDIPlus_ImageLoadFromFile($path & "\" & $aFileList[$iCounter])

    [/autoit] [autoit][/autoit] [autoit]

    $iHeight = _GDIPlus_ImageGetHeight($hImage)
    $iWidth = _GDIPlus_ImageGetWidth($hImage)
    $iScreenHeight = Int(($iHeight * (@DesktopHeight / $iHeight)) - 40) ; Bild immer an Bildschirmhöhe anpassen minus Taskbar (Win 7, Taskbar unten)
    $iScreenWidth = Int($iWidth * ($iScreenHeight / $iHeight)) ; Anpassung an individuelle Konfiguration folgt

    [/autoit] [autoit][/autoit] [autoit]

    ;ConsoleWrite($iScreenWidth & " X " & $iScreenHeight & @CRLF)
    ;ConsoleWrite($aFileList[$iCounter] & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Switch $bDurchlauf ;==> werden die Grafiken direkt nach Anzeige gelöscht, hat WM_PAINT nichts zum anzeigen, daher in dieser Reihenfolge
    Case False ;==> nur beim ersten Durchlauf ausführen
    WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)

    [/autoit] [autoit][/autoit] [autoit]

    #cs ; Wenn das Menü aktiviert ist, funktioniert das Bewegen des Fensters mit der Maus nicht mehr. Wie gehts richtig???
    $idDummy = GUICtrlCreateLabel("", 0, 0, $iScreenWidth, $iScreenHeight)
    $idContext = GUICtrlCreateContextMenu($idDummy)
    $idExit = GUICtrlCreateMenuItem("Beenden", $idContext)
    GUICtrlSetState($idExit, "_Exit")
    #ce

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    $bDurchlauf = True
    Case Else ;==> darf beim ersten Durchlauf nicht ausgeführt werden
    Select
    Case $iScreenWidthOld <> $iScreenWidth Or $iScreenHeightOld <> $iScreenHeight ;==> nur ausführen, wenn sich die Bildgröße ändert

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hBuffer)
    _GDIPlus_BitmapDispose($hBitmap)
    WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    EndSelect
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    ;WinMove("Show PIC", "", $aPos[0], $aPos[1], $iScreenWidth, $iScreenHeight)
    ;$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    ;$hBitmap = _GDIPlus_BitmapCreateFromGraphics($iScreenWidth, $iScreenHeight, $hGraphic)
    ;$hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($hBuffer, $hImage, 0, 0, $iScreenWidth, $iScreenHeight)
    $paint = _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    If $paint = False Then Beep(1500, 50) ;nur zum debuggen

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_ImageDispose($hImage)

    [/autoit] [autoit][/autoit] [autoit]

    $iScreenWidthOld = $iScreenWidth
    $iScreenHeightOld = $iScreenHeight
    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")
    EndFunc ;==>_Show

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_ERASEBKGND()
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    ConsoleWrite("WM_PAINT: " & $aFileList[$iCounter] & " -> " & $aPos[0] & "/" & $aPos[1] & " -> " & $iScreenHeight & " X " & $iScreenWidth & @CRLF)
    Return True
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_PAINT() ;==> ist das die beste/schnellste Lösung???
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iScreenWidth, $iScreenHeight)
    ConsoleWrite("WM_PAINT: " & $aFileList[$iCounter] & " -> " & $aPos[0] & "/" & $aPos[1] & " -> " & $iScreenHeight & " X " & $iScreenWidth & @CRLF)
    Return $GUI_RUNDEFMSG
    EndFunc ;==>_WM_PAINT

    [/autoit] [autoit][/autoit] [autoit]

    Func _Benchmark()
    Local $begin
    $begin = TimerInit()
    For $i = 1 To $aFileList[0]
    ;0x00780000, 0xFF880000
    _WM_MOUSEWHEEL(Default, Default, 0xFF880000, Default)
    Next
    ConsoleWrite(TimerDiff($begin) / 1000 & @CRLF)
    ;MsgBox(0, "", TimerDiff($begin) / 1000)
    EndFunc ;==>_Benchmark

    [/autoit] [autoit][/autoit] [autoit]

    Func _Down()
    _WM_MOUSEWHEEL(Default, Default, 0xFF880000, Default)
    EndFunc ;==>_Down

    [/autoit] [autoit][/autoit] [autoit]

    Func _Up()
    _WM_MOUSEWHEEL(Default, Default, 0x00780000, Default)
    EndFunc ;==>_Up

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_MOUSEWHEEL($hWnd, $iMsg, $iWParam, $iLParam)
    ;#forceref $hWnd, $iMsg, $iWParam, $iLParam
    Local $_iWParam
    ConsoleWrite($hWnd & "->" & $iMsg & "->" & $iWParam & "->" & $iLParam & "->>" & BitShift($iWParam, 16) & "->" & $iCounter & @CRLF)
    $_iWParam = BitShift($iWParam, 16) ;mögliche Werte für $iWParam 0x00780000, 0xFF880000

    [/autoit] [autoit][/autoit] [autoit]

    If $_iWParam < 0 Then ; If $iWParam = 0xFF880000 Then
    $iCounter += 1
    If $iCounter > $aFileList[0] Then $iCounter = 1
    Else
    $iCounter -= 1
    If $iCounter < 1 Then $iCounter = $aFileList[0]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;_Show()
    AdlibRegister("_Show", 250)
    Return $GUI_RUNDEFMSG
    EndFunc ;==>_WM_MOUSEWHEEL

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayMultiSelect($dir, $searchlist, $Separator, $iFlag = 0)
    Local $aFileList[1] = [0], $aFileList1, $iN, $Num, $search
    $search = StringSplit($searchlist, $Separator)
    If $search[0] > 0 Then
    For $iN = 1 To $search[0]
    $aFileList1 = _FileListToArray($dir, $search[$iN], $iFlag)
    If Not @error Then
    $Num = UBound($aFileList)
    _ArrayConcatenate($aFileList, $aFileList1)
    $aFileList[0] = $aFileList[0] + $aFileList[$Num]
    _ArrayDelete($aFileList, $Num)
    EndIf
    Next
    EndIf
    Return $aFileList
    EndFunc ;==>_FileListToArrayMultiSelect

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_ACTIVATE()
    Switch WinActive("Show PIC")
    Case 0
    HotKeySet("{UP}")
    HotKeySet("{DOWN}")
    Case Else
    HotKeySet("{UP}", "_Up")
    HotKeySet("{DOWN}", "_Down")
    EndSwitch
    EndFunc ;==>_WM_ACTIVATE

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam) ;==> Fenster mit Maus bewegen
    If BitAND(WinGetState($hWnd), 32) Then Return $GUI_RUNDEFMSG
    DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", $WM_SYSCOMMAND, "int", 0xF009, "int", 0)
    $aPos = WinGetPos("Show PIC")
    EndFunc ;==>_WM_LBUTTONDOWN

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Local $delete
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hBuffer)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
    If FileExists(@TempDir & "\_temp\") Then
    $delete = DirRemove(@TempDir & "\_temp\", 1)
    If $delete = 0 Then MsgBox(16, "Fehler", "Das temporäre Verzeichnis '" & @TempDir & "\_temp\" & "konnte nicht gelöscht werden.")
    EndIf
    Exit
    EndFunc ;==>_Exit

    [/autoit]


    Mars:

    ...an dich natürlich auch erstmal mein verbindlichster Dank :thumbup:

    Dein Skript ist von der Performance her großartig, auch wenn ichs noch nicht richtig verstehe. Könntest du das Prinzip von DCs mal näher erläutern? DC bedeutet Device Context, richtig?
    Bisher hatte ich leider noch keine Zeit, mir dein "Werk" zu Gemüte zu führen, werde das aber in den nächsten Tagen nachholen :whistling:

    Folgende Fehler treten regelmässig auf:
    1. Gelegendlich hat zwar das Fenster die korrekte Größe, das Bild selbst wird allerdings zu klein dargestellt. Dieser Effekt tritt auch auf, wenn ich ohne Skalierung die Bilder in Orginalgröße anzeigen lasse.
    Zeile 88 und 89 geändert, um keine Skalierung vorzunehmen:

    [autoit]

    $iScreenHeight = $iHeigh
    $iScreenWidth = $iWidth

    [/autoit]


    ...und so siehts aus:
    [Blockierte Grafik: http://i.imgur.com/XHjg8z3.jpg]

    2. Bei aktivierter Skalierung tritt bei fast allen Bildern eine Art Schachbrettmuster in unterschiedlicher Stärke auf:
    [Blockierte Grafik: http://i.imgur.com/NKOQume.jpg]
    Aber du hattest die Probleme bezüglich der Skalierung ja "angekündigt" :D

    3. Der Speicher füllt sich kontinuierlich mit jedem dargestellten Bild. Das ist sicherlich einfach zu beheben, aber wie gesagt, muß ich mir dein Skript erst noch richtig ansehen ;)


    @all:

    Zu meinem Problem mit dem Kontext Menü auf den Bildern hat sich leider niemand geäußert (Punkt 3 im Startbeitrag).
    Dafür hat nicht zufällig jemand 'ne Lösung parat?


    Sanfte Grüße :D

  • GDI kommt aber mit dem Skalieren nicht richtig klar (kann man glaube ich über einen Modus beheben, habe ich aber auf die schnelle nicht gefunden udn ich muss jetzt weg).


    2. Bei aktivierter Skalierung tritt bei fast allen Bildern eine Art Schachbrettmuster in unterschiedlicher Stärke auf: (Korrektur fürs Zitieren: Der Effekt tritt nur beim Verkleinern auf)
    [Blockierte Grafik: http://i.imgur.com/NKOQume.jpg]
    Aber du hattest die Probleme bezüglich der Skalierung ja "angekündigt"

    Google und MSDN sei Dank, habe ich die Lösung gefunden:

    Die Funktion SetStretchBltMode aus der GDI32.DLL behebt das Problem. Wird der Modus auf HALFTONE gesetzt, gibt es keinerlei Artefakte mehr.
    Ändert man die Funktion _WinAPI_StretchBlt im Skript folgendermaßen ab, läuft dieser Teil des Skriptes so, wie ich es mir vorgestellt habe:

    [autoit]

    Func _WinAPI_StretchBlt($hDestDC, $iXDest, $iYDest, $iWidth, $iHeight, $hSrcDC, $iXSrc, $iYSrc, $iWidthSrc, $iHeightSrc, $iROP)
    DllCall('GDI32.DLL', 'int', 'SetStretchBltMode', 'hwnd', $hDestDC, 'int', 3)
    DllCall('GDI32.DLL', 'int', 'StretchBlt', 'hwnd', $hDestDC, 'int', $iXDest, 'int', $iYDest, 'int', $iWidth, 'int', $iHeight, 'hwnd', $hSrcDC, 'int', $iXSrc, 'int', $iYSrc, 'int', $iWidthSrc, 'int', $iHeightSrc, 'int', $iROP)
    EndFunc ;==>_WinAPI_StretchBlt

    [/autoit]


    3. Der Speicher füllt sich kontinuierlich mit jedem dargestellten Bild. Das ist sicherlich einfach zu beheben, aber wie gesagt, muß ich mir dein Skript erst noch richtig ansehen ;)


    Die Funktion _Image_Delete arbeitet nicht korrekt. Die Variable $vStruct ist immer ohne Wert (warum eigendlich?) und daher wird in folgender Zeile immer aus der Funktion gesprungen, ohne den Speicher zu bereinigen:

    [autoit]

    If Not $vStruct Then Return

    [/autoit]


    Kommtentiert man diese Zeile jedoch aus, läuft alles wie geplant, also so:

    [autoit]

    Func _Image_Delete(ByRef $vStruct)
    ;If Not $vStruct Then Return
    If Not DllStructGetData($vStruct, 1) Then Return ;==> Ich bin nicht sicher, ob das Sinn macht, aber es funktioniert (ganz ohne diese Zeile allerdings auch)
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

    [/autoit]


    Mars:
    Nochmals vielen Dank für dein Skript. So langsam steige ich dahinter, muß mich aber noch durch einiges durchkämpfen, um es so zu verstehen, dass ich DCs ohne stupides copy/paste in eigenen Skripten anwenden kann :D
    Vieleicht kann ich die anderen Probleme ja auch selbstständig lösen 8)


    Sanfte Grüße :D