Что нового

[Интеракция] Аналог TeamViewer

JSman

Знающий
Сообщения
22
Репутация
5
Приветствую, форумчане. Для повышения опыта (ну и ради забавы) решил написать аналог TeamViewer. Реализация следующая: скриншотятся активные окна, разбиваются на квадраты, далее квадраты проходят через фильтр GrayScale (серый градиент), затем сохраняются в png файлы; при этом ведется подсчет контрольной суммы пикселей для выявления обновлений в регионах активного окна. То есть новые скриншоты (в виде квадратиков) будут появляться только тогда, когда канвас содержит новую информацию. Таким образом, я добился минимального трафика. При сохранении файлов также используются в их имени идентификационные данные, такие как хэндл окна, размер изображения, координаты (индекс) квадрата (X, Y). Идентификация нужна для декодирования (или обратной склейки картинок).
Единственное, что меня беспокоит - это повышение загрузки процессора.

В общем код ниже, буду рад вашим советам и предложения. Для удобства я сделал фильтр процессов, так проводник исключен от скриншотов.

Код:
#include <ScreenCapture.au3>

dim $PixSumLast[1]
$SquareSize = 200

$LastXSquare = 0
$LastYSquare = 0

While 1
	  MakeScreenShot()
	  Sleep(1000)
;	  Exit
WEnd

Func MakeScreenShot()
   $ActiveWindow = WinGetHandle("[active]")
   if $ActiveWindow=="" Then Return 0
   
   $Pos = WinGetClientSize("[active]")
   if $Pos==0 Then Return 0
 
   $proc = WinGetProcess("[active]")
   $ProcessName = ProcessGetName($proc)

   If $ProcessName=="explorer.exe" then Return 0

   $XSquare = Floor($Pos[0] / $SquareSize)
   $YSquare = Floor($Pos[1] / $SquareSize)
   
   if ($XSquare <> $LastXSquare) OR ($YSquare <> $LastYSquare) then
   ReDim $PixSumLast[$XSquare+1][$YSquare+1]
   endif
 
   For $x = 0 To $XSquare
   For $y = 0 To $YSquare
   
	  $PixSum = PixelChecksum($x*$SquareSize,$y*$SquareSize, ($x+1)*$SquareSize, ($y+1)*$SquareSize, 4, $ActiveWindow)

	  if $PixSumLast[$x][$y] == $PixSum then 
		 ContinueLoop
	  EndIf
		 
	  $PixSumLast[$x][$y] = $PixSum
	  
	  _GDIPlus_Startup ()

	  $HBITMAP = _ScreenCapture_CaptureWnd ( "", $ActiveWindow, $x*$SquareSize, $y*$SquareSize, ($x+1)*$SquareSize, ($y+1)*$SquareSize, False)
	  $fFreeBmp = True
	  $hBmp = _GDIPlus_BitmapCreateFromHBITMAP($HBITMAP)
	  $hContext = _GDIPlus_ImageGetGraphicsContext($hBmp)
	  _Greyscale($hBmp, $hContext)
	  _GDIPlus_ImageSaveToFile($hBmp, @ScriptDir & "\" & @YEAR & @MON & @MDAY & "-" & @HOUR & @MIN & @SEC & "-" & $ProcessName & "-" & $x & "-" & $y & "-" & $XSquare & "-" & $YSquare & "-" & $Pos[0] & "-" & $Pos[1] & "-" & $ActiveWindow & ".png")
	  _GDIPlus_GraphicsDispose($hContext)
	  _WinAPI_DeleteObject($HBITMAP)
	  _GDIPlus_BitmapDispose ($hBmp)
	  _GDIPlus_Shutdown()
   Next
   Next
 
EndFunc

Func ProcessGetName($PId)
    If IsNumber($PId) = 0 Then
        SetError(2)
    ElseIf $PId > 9999 Then
        SetError(1)
    Else
        Local $PList = ProcessList()
        Local $i = 1
        Local $ProcessName = ""

        While $i <= $PList[0][0] And $ProcessName = ""
            If $PList[$i][1] = $PId Then
                $ProcessName = $PList[$i][0]
            Else
                $i = $i + 1
            EndIf
        WEnd
        Return $ProcessName
    EndIf
EndFunc ;==>ProcessGetName

Func _Greyscale($hImage, $hImageContext)
    Local $tNegMatrix, $pNegMatrix, $hIA
    $hIA = _GDIPlus_ImageAttributesCreate()
    $aImageSize = _GDIPlus_ImageGetDimension($hImage)
    If $hImage Then
        $tNegMatrix = _GDIPlus_ColorMatrixCreateGrayScale()
        $pNegMatrix = DllStructGetPtr($tNegMatrix)
        _GDIPlus_ImageAttributesSetColorMatrix($hIA, 0, True, $pNegMatrix)
        _GDIPlus_GraphicsDrawImageRectRectIA($hImageContext, $hImage, 0, 0, $aImageSize[0], $aImageSize[1], 0, 0, $aImageSize[0], $aImageSize[1], $hIA)
        _GDIPlus_ImageAttributesDispose($hIA)
    EndIf
EndFunc

Func _GDIPlus_ImageGetDimension($hImage)
    Local $aSize[2], $aResult
    $aResult = DllCall($ghGDIPDll, "uint", "GdipGetImageDimension", "hwnd", $hImage, "float*", 0, "float*", 0)
    If @error Then Return SetError(@error, @extended, -1)
    $GDIP_STATUS = $aResult[0]
    If $GDIP_STATUS Then Return -1
    $aSize[0] = $aResult[2]
    $aSize[1] = $aResult[3]
    Return $aSize
EndFunc   ;==>_GDIPlus_ImageGetDimension

Func _GDIPlus_ImageAttributesCreate()
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateImageAttributes", "int*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aResult[1]
EndFunc   ;==>_GDIPlus_ImageAttributesCreate

Func _GDIPlus_ColorMatrixCreateGrayScale()
    Local Const $GDIP_RLUM = 0.3086
    Local Const $GDIP_GLUM = 0.6094
    Local Const $GDIP_BLUM = 0.0820
    Local Const $tagGDIPCOLORMATRIX = "float m[25];"
    Local $iI, $iJ, $tCM, $aLums[4] = [$GDIP_RLUM, $GDIP_GLUM, $GDIP_BLUM, 0]
    $tCM = DllStructCreate($tagGDIPCOLORMATRIX)
    For $iI = 0 To 3
        For $iJ = 1 To 3
            DllStructSetData($tCM, "m", $aLums[$iI], $iI * 5 + $iJ)
        Next
    Next
    DllStructSetData($tCM, "m", 1, 19)
    DllStructSetData($tCM, "m", 1, 25)
    Return $tCM
EndFunc   ;==>_GDIPlus_ColorMatrixCreateGrayScale

Func _GDIPlus_ImageAttributesSetColorMatrix($hImageAttributes, $iColorAdjustType = 0, $fEnable = False, $pClrMatrix = 0, $pGrayMatrix = 0, $iColorMatrixFlags = 0)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipSetImageAttributesColorMatrix", "hwnd", $hImageAttributes, "int", $iColorAdjustType, "int", $fEnable, "ptr", $pClrMatrix, "ptr", $pGrayMatrix, "int", $iColorMatrixFlags)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_ImageAttributesSetColorMatrix

Func _GDIPlus_GraphicsDrawImageRectRectIA($hGraphics, $hImage, $nSrcX, $nSrcY, $nSrcWidth, $nSrcHeight, $nDstX, $nDstY, $nDstWidth, $nDstHeight, $hImageAttributes = 0, $iUnit = 2)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDrawImageRectRect", "hwnd", $hGraphics, "hwnd", $hImage, "float", $nDstX, "float", _
            $nDstY, "float", $nDstWidth, "float", $nDstHeight, "float", $nSrcX, "float", $nSrcY, "float", $nSrcWidth, "float", _
            $nSrcHeight, "int", $iUnit, "hwnd", $hImageAttributes, "int", 0, "int", 0)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_GraphicsDrawImageRectRectIA

Func _GDIPlus_ImageAttributesDispose($hImageAttributes)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipDisposeImageAttributes", "hwnd", $hImageAttributes)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_ImageAttributesDispose
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
я точно не уверен, но разве TeamViewer делает скриншоты? он вроде перехватывает сигнал от видеокарты. и кстати при работе TV процессор тоже нагружается будь здоров.
 
Автор
J

JSman

Знающий
Сообщения
22
Репутация
5
я точно не уверен, но разве TeamViewer делает скриншоты? он вроде перехватывает сигнал от видеокарты.
Да понятное дело, что TV работает на базе других технологий, но я подумал, почему бы не попробовать это дело реализовать фрагментами скриншотов. Сейчас дописываю склейку изображений. Вроде бы интересно получается.
 

Zaramot

I ♥ AutoIt
Сообщения
1,160
Репутация
660
Я давненько так "баловался" :smile:

Клиент:
Код:
#include <FileTCP.au3>
#include <Misc.au3>
#include <WindowsConstants.au3>

Global $Screen = @ScriptDir & '\main.jpg'
Global $Title = 'Autoit Remote Control'

$GUI = GUICreate($Title, 380, 300, 0, 336, $WS_TILEDWINDOW, $WS_EX_TOPMOST + $WS_EX_COMPOSITED)
$PIC = GUICtrlCreatePic('', 0, 0, 380, 300)
GUISetState()

AdlibRegister('_Resize', 1)
AdlibRegister('_Redraw', 1000)

TCPStartUp()
$socket = TCPConnect(@IPAddress1, 1000)
If $socket = -1 Then Exit

While 1
	$b = _FileRecieve($Screen, $socket)
	If $b = 0 Then MsgBox(0, $Title, 'Error!')
	GUICtrlSetImage($PIC, $Screen)
	FileDelete($Screen)
WEnd

TCPShutdown()

Func _Resize()
	$WinPos = WinGetPos($GUI)
	GUICtrlSetPos($PIC, 0, 0, $WinPos[2], $WinPos[3])
	If GUIGetMsg() = -3 Then Exit FileDelete($Screen)
EndFunc

Func _Redraw()
	If Not _IsPressed(01) Then
		If Not WinActive($GUI) Then WinActivate($GUI)
	EndIf
EndFunc

Сервер:
Код:
#include <FileTCP.au3>
#include <ScreenCapture.au3>

Global $Screen = @TempDir & '\main.jpg'
Global $Title = 'Autoit Remote Control'
Global $var = 150
Global $Ip = @IPAddress1

HotKeySet('{ESC}', '_Exit')

FileWrite($Screen, '')

TCPStartUp()

$MainSocket = TCPListen($Ip, 1000)
If $MainSocket = -1 Then
	If @error = 10048 Then Exit MsgBox(48, $Title, 'Программа уже запущенна!', 1)
EndIf

While 1
	$ConnectedSocket = -1
    Do
        $ConnectedSocket = TCPAccept($MainSocket)
    Until $ConnectedSocket <> -1

	While 1
		$MousePos = MouseGetPos()
		_ScreenCapture_Capture($Screen, $MousePos[0] - $var, $MousePos[1] - $var, $MousePos[0] + $var, $MousePos[1] + $var)
		$a = _FileSend($Screen, $ConnectedSocket)
		Switch $a
			Case 0
				Exit
			Case 1
;~ 				Sleep(100)
				FileDelete($Screen)
		EndSwitch
	WEnd
Wend

If $ConnectedSocket <> -1 Then TCPCloseSocket($ConnectedSocket)
TCPShutdown()

Func _Exit()
	Exit
EndFunc

FileTCP.au3:
http://autoit-script.ru/autoit_rv_ua/files/Automation/FileTCP.au3
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
JSman
А что если, сделать такие квадратики, выводить на сайт(php в этом поможет), и через телефон. Допустим через телефонную java оперу нажимать на квадратики, тем самым управляя компьютером удаленно через простой телефон. :smile:
 
Автор
J

JSman

Знающий
Сообщения
22
Репутация
5
да Вы читаете мои мысли, сэр:smile:
 
Автор
J

JSman

Знающий
Сообщения
22
Репутация
5
Viktor1703 сказал(а):
Или ещё один пример от Yashied'a
Благодарю. Но, к сожалению, пока этот вариант мне не подходит.

Zaramot сказал(а):
Я давненько так "баловался" :smile:
Прикольно, мне очень понравилось:smile:

Ganibal95 сказал(а):
Попробую сделать...
Самый элементарный вариант организации кода такой:
Кроме создания картинок, целесообразно изготовить информацию о фрейме (снимке) в виде веб-страницы, где указываются ссылки (адреса) на используемые в снимке квадратики. После чего отправляем в веб (сокетами или пост-запросом, каждый сам для себя выберет).
Клиентская (веб) часть также просто реализуется. Сервак принимает данные, получаем код последней страницы с квадратиками.

Давным давно бы уже решение опубликовал, пока в разъездах.



Добавлено:
Сообщение автоматически объединено:

Вот такой вариант. Пока только отображение.

Код:
#include <ScreenCapture.au3>

dim $PixSumLast[1]
dim $PicsNames[1]

$SquareSize = 200

$LastXSquare = 0
$LastYSquare = 0

While 1
      MakeScreenShot()
      Sleep(3000)
;     Exit
WEnd

Func MakeScreenShot()
   $ActiveWindow = WinGetHandle("[active]")
   if $ActiveWindow=="" Then Return 0
   
   $Pos = WinGetClientSize("[active]")
   if $Pos==0 Then Return 0
 
   $proc = WinGetProcess("[active]")
   $ProcessName = ProcessGetName($proc)

   If $ProcessName=="explorer.exe" then Return 0

   $XSquare = Floor($Pos[0] / $SquareSize)
   $YSquare = Floor($Pos[1] / $SquareSize)
   
   if ($XSquare <> $LastXSquare) OR ($YSquare <> $LastYSquare) then
   ReDim $PixSumLast[$XSquare+1][$YSquare+1]
   ReDim $PicsNames[$XSquare+1][$YSquare+1]
   endif
 
   $filename = @YEAR & @MON & @MDAY & "-" & @HOUR & @MIN & @SEC & "-" & $ProcessName 
   $file = FileOpen(@ScriptDir & "\" & $filename & ".html", 1)

   ;If $file = -1 Then 
   FileWrite($file, "<html><head><title>" & $filename & "</title></head><body style=""margin:0px""><table border=0 cellspacing=0 cellpadding=0>" & @CRLF)

   For $y = 0 To $YSquare
	  
   FileWrite($file, "<tr>" & @CRLF)
   
   For $x = 0 To $XSquare
      $PixSum = PixelChecksum($x*$SquareSize,$y*$SquareSize, ($x+1)*$SquareSize, ($y+1)*$SquareSize, 4, $ActiveWindow)

      if $PixSumLast[$x][$y] == $PixSum then 
		 FileWrite($file, "<td><img src=""" & $PicsNames[$x][$y] & """ ></td>")
         ContinueLoop
      EndIf
         
      $PixSumLast[$x][$y] = $PixSum
      $PicsNames[$x][$y] = $filename & "-" & $x & "-" & $y & "-" & $Pos[0] & "-" & $Pos[1] & ".png"
	  FileWrite($file, "<td><img src=""" & $PicsNames[$x][$y] & """ ></td>")
      
      _GDIPlus_Startup()

      $HBITMAP = _ScreenCapture_CaptureWnd ("", $ActiveWindow, $x*$SquareSize, $y*$SquareSize, ($x+1)*$SquareSize, ($y+1)*$SquareSize, False)
      $fFreeBmp = True
      $hBmp = _GDIPlus_BitmapCreateFromHBITMAP($HBITMAP)
      $hContext = _GDIPlus_ImageGetGraphicsContext($hBmp)
      _Greyscale($hBmp, $hContext)
      _GDIPlus_ImageSaveToFile($hBmp, @ScriptDir & "\" & $filename & "-" & $x & "-" & $y & "-" & $Pos[0] & "-" & $Pos[1] & ".png")
        
	  _GDIPlus_GraphicsDispose($hContext)
      _WinAPI_DeleteObject($HBITMAP)
      _GDIPlus_BitmapDispose ($hBmp)
      _GDIPlus_Shutdown()
   Next
   
   FileWrite($file, "</tr>" & @CRLF)
Next

FileWrite($file, "</table></body></html>")
FileClose($file)

EndFunc

Func ProcessGetName($PId)
    If IsNumber($PId) = 0 Then
        SetError(2)
    ElseIf $PId > 9999 Then
        SetError(1)
    Else
        Local $PList = ProcessList()
        Local $i = 1
        Local $ProcessName = ""

        While $i <= $PList[0][0] And $ProcessName = ""
            If $PList[$i][1] = $PId Then
                $ProcessName = $PList[$i][0]
            Else
                $i = $i + 1
            EndIf
        WEnd
        Return $ProcessName
    EndIf
EndFunc ;==>ProcessGetName

Func _Greyscale($hImage, $hImageContext)
    Local $tNegMatrix, $pNegMatrix, $hIA
    $hIA = _GDIPlus_ImageAttributesCreate()
    $aImageSize = _GDIPlus_ImageGetDimension($hImage)
    If $hImage Then
        $tNegMatrix = _GDIPlus_ColorMatrixCreateGrayScale()
        $pNegMatrix = DllStructGetPtr($tNegMatrix)
        _GDIPlus_ImageAttributesSetColorMatrix($hIA, 0, True, $pNegMatrix)
        _GDIPlus_GraphicsDrawImageRectRectIA($hImageContext, $hImage, 0, 0, $aImageSize[0], $aImageSize[1], 0, 0, $aImageSize[0], $aImageSize[1], $hIA)
        _GDIPlus_ImageAttributesDispose($hIA)
    EndIf
EndFunc

Func _GDIPlus_ImageGetDimension($hImage)
    Local $aSize[2], $aResult
    $aResult = DllCall($ghGDIPDll, "uint", "GdipGetImageDimension", "hwnd", $hImage, "float*", 0, "float*", 0)
    If @error Then Return SetError(@error, @extended, -1)
    $GDIP_STATUS = $aResult[0]
    If $GDIP_STATUS Then Return -1
    $aSize[0] = $aResult[2]
    $aSize[1] = $aResult[3]
    Return $aSize
EndFunc   ;==>_GDIPlus_ImageGetDimension

Func _GDIPlus_ImageAttributesCreate()
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateImageAttributes", "int*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aResult[1]
EndFunc   ;==>_GDIPlus_ImageAttributesCreate

Func _GDIPlus_ColorMatrixCreateGrayScale()
    Local Const $GDIP_RLUM = 0.3086
    Local Const $GDIP_GLUM = 0.6094
    Local Const $GDIP_BLUM = 0.0820
    Local Const $tagGDIPCOLORMATRIX = "float m[25];"
    Local $iI, $iJ, $tCM, $aLums[4] = [$GDIP_RLUM, $GDIP_GLUM, $GDIP_BLUM, 0]
    $tCM = DllStructCreate($tagGDIPCOLORMATRIX)
    For $iI = 0 To 3
        For $iJ = 1 To 3
            DllStructSetData($tCM, "m", $aLums[$iI], $iI * 5 + $iJ)
        Next
    Next
    DllStructSetData($tCM, "m", 1, 19)
    DllStructSetData($tCM, "m", 1, 25)
    Return $tCM
EndFunc   ;==>_GDIPlus_ColorMatrixCreateGrayScale

Func _GDIPlus_ImageAttributesSetColorMatrix($hImageAttributes, $iColorAdjustType = 0, $fEnable = False, $pClrMatrix = 0, $pGrayMatrix = 0, $iColorMatrixFlags = 0)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipSetImageAttributesColorMatrix", "hwnd", $hImageAttributes, "int", $iColorAdjustType, "int", $fEnable, "ptr", $pClrMatrix, "ptr", $pGrayMatrix, "int", $iColorMatrixFlags)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_ImageAttributesSetColorMatrix

Func _GDIPlus_GraphicsDrawImageRectRectIA($hGraphics, $hImage, $nSrcX, $nSrcY, $nSrcWidth, $nSrcHeight, $nDstX, $nDstY, $nDstWidth, $nDstHeight, $hImageAttributes = 0, $iUnit = 2)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDrawImageRectRect", "hwnd", $hGraphics, "hwnd", $hImage, "float", $nDstX, "float", _
            $nDstY, "float", $nDstWidth, "float", $nDstHeight, "float", $nSrcX, "float", $nSrcY, "float", $nSrcWidth, "float", _
            $nSrcHeight, "int", $iUnit, "hwnd", $hImageAttributes, "int", 0, "int", 0)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_GraphicsDrawImageRectRectIA

Func _GDIPlus_ImageAttributesDispose($hImageAttributes)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipDisposeImageAttributes", "hwnd", $hImageAttributes)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_ImageAttributesDispose
 
Верх