Jump to content

Capture screen and display in gui


Recommended Posts

Hello,

i would like to capture a part of the screen and then display it in my gui (refreshing it every X seconds).

When i capture the screen with _ScreenCapture_Capture ("",10,10,100,100) it returns a handle to the captured screen (as i understand the help file).

How can i display this captured screen in my gui without saving it to a file?

It is probably simple, so sorry for the dumb question :-)

 

Link to comment
Share on other sites

  • Moderators

Edit: Just saw your "without saving to a file". See next post

The very first parameter of _ScreenCapture_Capture is the filename you would like to save the image to; I don't know that you'll be . You can save to a temp file and then use that in your image. This works for me:

#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>

_ScreenCapture_Capture(@TempDir & "\1.jpg", 1, 1, 500, 500)

GUICreate("Test", 600, 600)
GUICtrlCreatePic(@TempDir & "\1.jpg", 10, 10, 280, 280)

GUISetState(@SW_SHOW)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

GUIDelete()

Of course, depending on how often you're refreshing you may well run into some "blinking" issues.

Edited by JLogan3o13

"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

  • Moderators

You could do something like this with GDI+ (code shamelessly stolen from Melba):

#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>

    _GDIPlus_Startup()
    Local $hHBmp = _ScreenCapture_Capture("", 0, 0, 500, 500)
    Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
    _WinAPI_DeleteObject($hHBmp)

     Local $hGUI = GUICreate("GDI+ test", 800, 800, -1, -1)
    GUISetState()

    Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    ;cleanup resources
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_Shutdown()
    GUIDelete($hGUI)

 

"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

  • Moderators

JLogan3o13,

Quote

code shamelessly stolen from Melba

And who shamelessly stole it from someone else (probably Malkey or UEZ)!

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Works great, thanks a lot.

I never used gdiplus before...learned something new today :-)

Edit: As always there is a new question:

When i capture the screen every x seconds in would like to only update the gui when the picture changed.

Is there a way to campare two captured images? I can not compare the handles, i need a way to compare the bmp that is referenced by the handle.

Edited by Allow2010
Link to comment
Share on other sites

Thank you, this works (needs <AssembleIt.au3> and fasm). But as soon as i try to move the gui it is reduced to a very small gui (from 600x600 to aprox 20x600). It is hard to explain, maybe you can try it.

This bug happends even if i do not use any assembleit function.

Including the <AssembleIt.au3> triggers the bug, because <AssembleIt.au3> calls a FasmInit() when included... i do not know how to fix this as the <AssembleIt.au3> is a bit to complex for me.

Can you help here?

#include <AssembleIt.au3>
#include <ScreenCapture.au3>
#include <GUIConstantsEx.au3>

$hGraphics = ""
$hBitmap = ""
$hBitmaplast = ""
$hHBmp = ""
$hHBmplast = ""

_GDIPlus_Startup()

Local $hGUI = GUICreate("TestGUI", 600, 600, -1, -1)
GUISetState()

RefreshImage()

AdlibRegister(RefreshImage, 500)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

;cleanup resources
_WinAPI_DeleteObject($hHBmp)
_WinAPI_DeleteObject($hHBmplast)
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_BitmapDispose($hBitmaplast)
_GDIPlus_Shutdown()
GUIDelete($hGUI)

Func RefreshImageMini()
    _GDIPlus_GraphicsDrawImage(_GDIPlus_GraphicsCreateFromHWND($hGUI), _GDIPlus_BitmapCreateFromHBITMAP(_ScreenCapture_Capture("", 0, 0, 500, 500)), 0, 0)
EndFunc   ;==>RefreshImageMini

Func RefreshImageStandard()
    $hHBmp = _ScreenCapture_Capture("", 0, 0, 500, 500)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)
EndFunc   ;==>RefreshImageStandard

Func RefreshImage()
    $hHBmp = _ScreenCapture_Capture("", 0, 0, 500, 500)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
    If _ASM_BitCompareBitmapsMMX($hBitmap, $hBitmaplast) = 0 Then
        $hBitmaplast = $hBitmap
        $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
        _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)
        ConsoleWrite("change" & @CRLF)
    Else
        ConsoleWrite("no change" & @CRLF)
    EndIf
EndFunc   ;==>RefreshImage

Func _ASM_BitCompareBitmapsMMX($hBitmap1, $hBitmap2)
    If $hBitmap1<>"" and $hBitmap2<>"" then
    Local $aDim1 = _GDIPlus_ImageGetDimension($hBitmap1)
    Local $aDim2 = _GDIPlus_ImageGetDimension($hBitmap2)
    If BitOR($aDim1[0] <> $aDim2[0], $aDim1[1] <> $aDim2[1]) Then Return False

    Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $aDim1[0], $aDim1[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan1 = $tBitmapData1.Scan0
    Local $iStride1 = $tBitmapData1.Stride * 4
    Local $tPixelData1 = DllStructCreate("dword[" & Abs($iStride1 * $aDim1[1]) & "]", $pScan1)

    Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hBitmap2, 0, 0, $aDim2[0], $aDim2[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan2 = $tBitmapData2.Scan0
    Local $tPixelData2 = DllStructCreate("dword[" & Abs($iStride1 * $aDim1[1]) & "]", $pScan2)

    Local $tCodeBuffer = DllStructCreate("byte ASM[55]") ;reserve memory for ASM opcodes
    $tCodeBuffer.ASM = "0x8B7424048B7C24088B4C240CB801000000F30F6F0EF30F6F17660FEFCA660F3817C9750D83C61083C71083E90477E2EB05B800000000C3"
;~  Local $fTimer = TimerInit()
;~  Local $iRet = _AssembleIt("uint", "_BitCompareMMX", "ptr", DllStructGetPtr($tPixelData1), "ptr", DllStructGetPtr($tPixelData2), "int", $aDim1[0] * $aDim1[1])

    Local $aRet = DllCall("user32.dll", "uint", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), _
            "ptr", DllStructGetPtr($tPixelData1), _
            "ptr", DllStructGetPtr($tPixelData2), _
            "uint", $aDim1[0] * $aDim1[1], _
            "int", Null)

;~  Local $fTimer_End = TimerDiff($fTimer)
;~  ConsoleWrite("Runtime ASM only: " & $fTimer_End & " ms" & @CRLF)

    _GDIPlus_BitmapUnlockBits($hBitmap1, $tBitmapData1)
    _GDIPlus_BitmapUnlockBits($hBitmap2, $tBitmapData2)

;~  Return $iRet
    Return $aRet[0]
    Else
        SetError(1)
        Return 0
    EndIf
EndFunc   ;==>_ASM_BitCompareBitmapsMMX

Func _BitCompareMMX()
    _("use32") ;32Bit!
;~  _("org " & FasmGetBasePtr($Fasm))  ;needed for assembleit debugger
    _("mov esi, dword[esp+4]") ;points to beginning of the bitmap1 in the memory (scan0)
    _("mov edi, dword[esp+8]") ;points to beginning of the bitmap2 in the memory (scan0)
    _("mov ecx, dword[esp+12]") ;amount of pixels to read (width * height)
    _("mov eax, 1") ;eax it the return value -> 1 = equal, 0 = not equal
    _("_loop1:")
    _("movdqu   xmm1,   [esi]") ;copy 4 byte to xmm1 register (128 bit) from bitmap1
    _("movdqu   xmm2,   [edi]") ;copy 4 byte to xmm1 register (128 bit) from bitmap2
    _("pxor     xmm1,   xmm2") ;xmm1 xor xmm2 ->  0xor0 and 1xor1 = 0, otherwise 1
    _("ptest    xmm1,   xmm1") ;PTEST set the ZF flag if all bits in the result are 0 of the bitwise AND of the first source operand (first operand) and the second source operand (second operand).
    _("jnz      _NotEqual") ;xmm1 <> xmm2 because zero flag not set
    _("add esi, 16") ;get next 4 pixels from bitmap1
    _("add edi, 16") ;get next 4 pixels from bitmap2
    _("sub ecx, 4") ;decrease pixel count by 4 -> 4 pixel will be read at once
    _("ja _loop1") ;exit loop when all pixels were read
    _("jmp  _End")

    _("_NotEqual:")
    _("mov eax, 0") ;set return value to 0

    _("_End:")
    _("ret") ;return eax
EndFunc   ;==>_BitCompareMMX

 

Link to comment
Share on other sites

OK here are two screenshot. The first one shows the gui when the script is started. Everything is fine.

the second one shows the gui after i moved the window, now the gui ist resized (automatically) and only shows a small area of the screenshot.

This is caused by including

#include <AssembleIt.au3>

Using something like WinMove("TestGUI","",100,100,900,900) somewhere in the script has the same effect, the window is not moved an it is resized as show in the second screenshot...

 

1.jpg

2.jpg

Edited by Allow2010
Link to comment
Share on other sites

@Allow2010 your GDI+ code produces memory leaks!

Try this instead:

#include <ScreenCapture.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

$hGraphics = 0
$hBitmap = 0
$hBitmaplast = 0
$hHBmp = 0
$hHBmplast = 0

_GDIPlus_Startup()

Local $hGUI = GUICreate("TestGUI", 500, 500, @DesktopWidth - 550, -1, -1, $WS_EX_TOPMOST)
GUISetState()
$hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)

$hHBmp = _ScreenCapture_Capture("", 0, 0, 499, 499)
$hBitmaplast = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
_WinAPI_DeleteObject($hHBmp)

RefreshImage()
AdlibRegister(RefreshImage, 250)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

;cleanup resources
_WinAPI_DeleteObject($hHBmp)
_WinAPI_DeleteObject($hHBmplast)
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_BitmapDispose($hBitmaplast)
_GDIPlus_Shutdown()
GUIDelete($hGUI)

Func RefreshImage()
    If $hHBmp Then _WinAPI_DeleteObject($hHBmp)
    $hHBmp = _ScreenCapture_Capture("", 0, 0, 499, 499)
    If $hBitmap Then _GDIPlus_ImageDispose($hBitmap)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)
    $iCompare = _ASM_BitCompareBitmapsMMX($hBitmap, $hBitmaplast)
    Switch $iCompare
        Case 0
            If $hBitmaplast Then _GDIPlus_ImageDispose($hBitmaplast)
            $hBitmaplast = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, 500, 500, $GDIP_PXF24RGB)
            ConsoleWrite("change" & @CRLF)
        Case 1
            ConsoleWrite("no change" & @CRLF)
    EndSwitch
EndFunc   ;==>RefreshImage

Func _ASM_BitCompareBitmapsMMX($hBitmap1, $hBitmap2)
    Local $aDim1 = _GDIPlus_ImageGetDimension($hBitmap1)
    If @error Then Return SetError(1, 0, -1)
    Local $aDim2 = _GDIPlus_ImageGetDimension($hBitmap2)
    If @error Then Return SetError(2, 0, -1)
    If BitOR($aDim1[0] <> $aDim2[0], $aDim1[1] <> $aDim2[1]) Then Return 1

    Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $aDim1[0], $aDim1[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan1 = $tBitmapData1.Scan0
    Local $iStride1 = $tBitmapData1.Stride * 4
    Local $tPixelData1 = DllStructCreate("dword[" & Abs($iStride1 * $aDim1[1]) & "]", $pScan1)

    Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hBitmap2, 0, 0, $aDim2[0], $aDim2[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan2 = $tBitmapData2.Scan0
    Local $tPixelData2 = DllStructCreate("dword[" & Abs($iStride1 * $aDim1[1]) & "]", $pScan2)

    Local $tCodeBuffer = DllStructCreate("byte ASM[55]") ;reserve memory for ASM opcodes
    $tCodeBuffer.ASM = "0x8B7424048B7C24088B4C240CB801000000F30F6F0EF30F6F17660FEFCA660F3817C9750D83C61083C71083E90477E2EB05B800000000C3" ;write opcodes into memory (struct) / length: 55

    Local $aRet = DllCall("user32.dll", "boolean", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), _
                                        "struct*", $tPixelData1, _
                                        "struct*", $tPixelData2, _
                                        "uint", $aDim1[0] * $aDim1[1], _
                                        "int", Null)

    _GDIPlus_BitmapUnlockBits($hBitmap1, $tBitmapData1)
    _GDIPlus_BitmapUnlockBits($hBitmap2, $tBitmapData2)

    Return $aRet[0]
EndFunc   ;==>_ASM_BitCompareBitmapsMMX

 

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

  • 1 year later...

Thanks to everyone who replied in this thread

I was able to realize my long-awaited solution

Simplified snippet:

#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>

Global $g_hGUI = GUICreate("GDI+ test 2", 600, 600, -1, -1)
GUISetState(@SW_SHOW, $g_hGUI)

_GDIPlus_Startup()
Global $g_hGraphics = _GDIPlus_GraphicsCreateFromHWND($g_hGUI)
OnAutoItExitRegister("CleanupResources")

Local $tDelta = TimerInit()
Do
    If TimerDiff($tDelta) >= 67 Then ; => 30 FPS
        $tDelta = TimerInit()
        RefreshImage()
    EndIf
Until GUIGetMsg() == $GUI_EVENT_CLOSE

Func RefreshImage()
    Local $hHBmp = _ScreenCapture_Capture("", 0, 0, 500, 500)
    Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
    _GDIPlus_GraphicsDrawImage($g_hGraphics, $hBitmap, 50, 50)
    _WinAPI_DeleteObject($hHBmp)
    _GDIPlus_BitmapDispose($hBitmap)
EndFunc

Func CleanupResources()
    _GDIPlus_GraphicsDispose($g_hGraphics)
    _GDIPlus_Shutdown()
    GUIDelete($g_hGUI)
EndFunc

 

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