Что нового

скриншот в бинарный код без промежуточного файла

Arei

Скриптер
Сообщения
938
Репутация
115
клиент сервер не работает к сожалению.Интересно почему?
 
Автор
S

Sergey2210

Осваивающий
Сообщения
263
Репутация
31
не получается так отправлять,вылетает либо сервер,либо клиент и картинка на сервере с каждым разом смещяется в нижний правый угол на 40 пиксилей (примерно)...
 

VladUs

Скриптер
Сообщения
621
Репутация
181
клиент сервер не работает к сожалению.Интересно почему?
Все работает... И при том через интернет тоже. Единственную проблему вижу в том что данные имеют большой объем и если запускать через интернет приходится ждать долго обновления картинки. А по сему поводу вопрос можно ли как то сжать данные на выходе в клиенте ?
 

Arei

Скриптер
Сообщения
938
Репутация
115
VladUs у меня не работает вылетает.
 

Arei

Скриптер
Сообщения
938
Репутация
115
Yashied скажите как вы использовали свой скрипт.На какой сети и какое время задержки ставили?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Вам необходимо понять следующее:

  • Данные передаются частями, а не целиком.
  • При считывании данных, из буфера забирается все, что там есть на данный момент, но не больше указанного в функции TCPRecv() объема (в данном случае 16 КБ), поэтому необходимо аккумулировать все полученные порции данных до полного составления скриншота.
  • Если сервер не будет успевать считывать и обрабатывать полученные порции данные (слишком маленькая пауза в клиенте), то последняя порция очередного скриншота будет совмещаться с первой порцией следующего скриншота, и нужно точно знать, где разделить эти два скриншота. Можно либо организовать дуплексную связь (сервер дает команду готовности на принятие следующего скриншота), либо посылать между скриншотами какой-нибудь разделитель (сигнатуру).

В данном примере я использовал заголовок битмапа (40 байт) в качестве сигнатуры. Т.е. данные на сокет передаются в следующей последовательности:

| Заголовок (40 байт) | Данные битмапа (произвольный размер) | и т.д.

Таким образом, я сначала считываю заголовок и определяю размер данных битмапа (поле "biSizeImage" в структуре BITMAPINFOHEADER). Затем считываю и аккумулирую остальные порции данных до того, как общий размер полученных данных не будет больше или равен "biSizeImage" + 40. После этого отображаю готовый скриншот и считываю следующий заголовок, и т.д.

В нижеприведенном примере в клиенте вы можете поставить любую паузу или вообще ее убрать, но я рекомендую обновлять не чаще 0.5-1 сек. Естественно правильнее было бы посылать данные в сжатом виде, но это я оставлю сделать вам самим... Кстати, вот небольшая библиотека для этого, основанная на нативных API функциях.

Client.au3
Код:
#Include <WinAPIEx.au3>

TCPStartup()
$Socket = TCPConnect(@IPAddress1, 33891)
If @error Then
	Exit
EndIf

While 1
	TCPSend($Socket, _GetScreenshot(0, 0, 800, 600))
	If @error Then
		ExitLoop
	EndIf
	Sleep(1000)
WEnd

TCPShutdown()

Func _GetScreenshot($iX = 0, $iY = 0, $iWidth = -1, $iHeight = -1)

	Local $tBD, $hBitmap, $hDesktop, $hSrcDC, $hDstDC, $hDstSv, $pBits

	If $iWidth = -1 Then
		$iWidth = @DesktopWidth
	EndIf
	If $iHeight = -1 Then
		$iHeight = @DesktopHeight
	EndIf
	$tBD = DllStructCreate($tagBITMAPINFOHEADER & 'byte RGB[' & ($iWidth * $iHeight * 3) & ']')
	If @error Then
		Return 0
	EndIf
	DllStructSetData($tBD, 'biSize', 40)
	DllStructSetData($tBD, 'biWidth', $iWidth)
	DllStructSetData($tBD, 'biHeight', -$iHeight)
	DllStructSetData($tBD, 'biPlanes', 1)
	DllStructSetData($tBD, 'biBitCount', 24)
	DllStructSetData($tBD, 'biCompression', $BI_RGB)
	DllStructSetData($tBD, 'biSizeImage', $iWidth * $iHeight * 3)
	$hBitmap = _WinAPI_CreateDIBSection(0, $tBD, $DIB_RGB_COLORS, $pBits)
	$hDesktop = _WinAPI_GetDesktopWindow()
	$hSrcDC = _WinAPI_GetDC($hDesktop)
	$hDstDC = _WinAPI_CreateCompatibleDC($hSrcDC)
	$hDstSv = _WinAPI_SelectObject($hDstDC, $hBitmap)
	_WinAPI_BitBlt($hDstDC, $iX, $iY, $iWidth, $iHeight, $hSrcDC, $iX, $iY, $SRCCOPY)
	_WinAPI_SelectObject($hDstDC, $hDstSv)
	_WinAPI_ReleaseDC($hDesktop, $hSrcDC)
	_WinAPI_DeleteDC($hDstDC)
	_WinAPI_GetBitmapBits($hBitmap, $iWidth * $iHeight * 3, DllStructGetPtr($tBD, 'RGB'))
	_WinAPI_DeleteObject($hBitmap)
	Return Binary(DllStructGetData(DllStructCreate('byte[' & DllStructGetSize($tBD) & ']', DllStructGetPtr($tBD)), 1))
EndFunc   ;==>_GetScreenshot


Server.au3
Код:
#Include <WinAPIEx.au3>

TCPStartup()
$Main = TCPListen(@IPAddress1, 33891)
If @error Then
    Exit
EndIf

GUICreate('MyGUI', 800, 600)
$Pic = GUICtrlCreatePic('', 0, 0, 800, 600)
GUISetState()

Do
    $Socket = TCPAccept($Main)
Until $Socket <> -1

Global $tHeader = DllStructCreate('byte[40]')
Global $pHeader = DllStructGetPtr($tHeader)
Global $bData = 0, $Count = 0

Do
	If Not IsBinary($bData) Then
		$bData = TCPRecv($Socket, 16384, 1)
		If @error Then
			ExitLoop
		EndIf
	EndIf
    If IsBinary($bData) Then
		If Not $Count Then
			DllStructSetData($tHeader, 1, $bData)
			$tBIHDR = DllStructCreate($tagBITMAPINFOHEADER, $pHeader)
			$Size = DllStructGetData($tBIHDR, 'biSizeImage') + 40
			$tData = DllStructCreate('byte[' & $Size & ']')
			$pData = DllStructGetPtr($tData)
		EndIf
        $Lenght = BinaryLen($bData)
		$Sum = $Count + $Lenght
		If $Sum > $Size Then
			$dL = $Size - $Count
			$tPart = DllStructCreate('byte[' & $dL & ']', $pData + $Count)
			DllStructSetData($tPart, 1, $bData)
			$tByte = DllStructCreate('byte[' & $Lenght & ']')
			$tRecv = DllStructCreate('byte[' & ($Lenght - $dL) & ']', DllStructGetPtr($tByte) + $dL)
			DllStructSetData($tByte, 1, $bData)
			$bData = DllStructGetData($tRecv, 1)
			$Sum = $Size
		Else
			$tPart = DllStructCreate('byte[' & $Lenght & ']', $pData + $Count)
			DllStructSetData($tPart, 1, $bData)
			$Count = $Sum
			$bData = 0
		EndIf
        If $Sum = $Size Then
            _SetScreenshot($Pic, $tData)
            $Count = 0
        EndIf
    EndIf
Until GUIGetMsg() = -3

TCPCloseSocket($Socket)
TCPShutdown()

Func _SetScreenshot($CtrlID, ByRef $tData, $fUpdate = 0)

    Local $tBD, $hBitmap, $pBits

    $hWnd = GUICtrlGetHandle($CtrlID)
    If Not $hWnd Then
        Return 0
    EndIf
    $hBitmap = _WinAPI_CreateDIBSection(0, $tData, $DIB_RGB_COLORS, $pBits)
    _WinAPI_SetBitmapBits($hBitmap, DllStructGetSize($tData) - 40, DllStructGetPtr($tData) + 40)
    _WinAPI_DeleteObject(_SendMessage($hWnd, 0x0172, 0, $hBitmap))
    $hPrev = _SendMessage($hWnd, 0x0173)
    If $hPrev <> $hBitmap Then
        _WinAPI_DeleteObject($hBitmap)
    EndIf
    If $fUpdate Then
        _WinAPI_UpdateWindow($hWnd)
    EndIf
    Return 1
EndFunc   ;==>_SetScreenshot
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied [?]
Кстати, вот небольшая библиотека для этого, основанная на нативных API функциях.
Это очень интересная и, ИМХО, полезная библиотека.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles сказал(а):
Это очень интересная и, ИМХО, полезная библиотека.

Эти две функции будут включены в WinAPEx при следующем обновлении.
 

VladUs

Скриптер
Сообщения
621
Репутация
181
Да... Здорово. Файл весом 6076 кб в формате .bmp сжимается до 847 кб, т.е более чем в 7 раз.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Вот предыдущий пример, но уже со сжатием данных (хороший пример на тему DllStruct... :smile:).

Client.au3
Код:
#Include <WinAPIEx.au3>

TCPStartup()
$Socket = TCPConnect(@IPAddress1, 33891)
If @error Then
	Exit
EndIf

While 1
	TCPSend($Socket, _GetScreenshot(0, 0, 800, 600))
	If @error Then
		ExitLoop
	EndIf
	Sleep(1000)
WEnd

TCPShutdown()

Func _GetScreenshot($iX = 0, $iY = 0, $iWidth = -1, $iHeight = -1)

	Local $tBD, $tData, $tOut, $hBitmap, $hDesktop, $hSrcDC, $hDstDC, $hDstSv, $pBits, $Lenght

	If $iWidth = -1 Then
		$iWidth = @DesktopWidth
	EndIf
	If $iHeight = -1 Then
		$iHeight = @DesktopHeight
	EndIf
	$tBD = DllStructCreate($tagBITMAPINFOHEADER & 'byte[' & ($iWidth * $iHeight * 3) & ']')
	If @error Then
		Return 0
	EndIf
	DllStructSetData($tBD, 'biSize', 40)
	DllStructSetData($tBD, 'biWidth', $iWidth)
	DllStructSetData($tBD, 'biHeight', -$iHeight)
	DllStructSetData($tBD, 'biPlanes', 1)
	DllStructSetData($tBD, 'biBitCount', 24)
	DllStructSetData($tBD, 'biCompression', $BI_RGB)
	$hBitmap = _WinAPI_CreateDIBSection(0, $tBD, $DIB_RGB_COLORS, $pBits)
	$hDesktop = _WinAPI_GetDesktopWindow()
	$hSrcDC = _WinAPI_GetDC($hDesktop)
	$hDstDC = _WinAPI_CreateCompatibleDC($hSrcDC)
	$hDstSv = _WinAPI_SelectObject($hDstDC, $hBitmap)
	_WinAPI_BitBlt($hDstDC, $iX, $iY, $iWidth, $iHeight, $hSrcDC, $iX, $iY, $SRCCOPY)
	_WinAPI_SelectObject($hDstDC, $hDstSv)
	_WinAPI_ReleaseDC($hDesktop, $hSrcDC)
	_WinAPI_DeleteDC($hDstDC)
	_WinAPI_GetBitmapBits($hBitmap, $iWidth * $iHeight * 3, DllStructGetPtr($tBD) + 40)
	_WinAPI_DeleteObject($hBitmap)
	$Lenght = _WinAPI_LZNTCompress($tBD, $tData)
	$tOut = DllStructCreate('dword;dword;byte[' & ($Lenght - Mod($Lenght, 4) + 4) & ']')
	DllStructSetData($tOut, 1, DllStructGetSize($tOut))
	DllStructSetData($tOut, 2, $Lenght)
	DllStructSetData($tOut, 3, DllStructGetData($tData, 1))
	Return Binary(DllStructGetData(DllStructCreate('byte[' & DllStructGetSize($tOut) & ']', DllStructGetPtr($tOut)), 1))
EndFunc   ;==>_GetScreenshot

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_LZNTCompress
; Description....: Compresses an input data.
; Syntax.........: _WinAPI_LZNTCompress ( ByRef $tInput, ByRef $tOutput [, $fMaximum] )
; Parameters.....: $tInput   - "byte[n]" or any other structure that contains the data to be compressed.
;                  $tOutput  - "byte[n]" structure that receives the compressed data.
;                  $fMaximum - Specifies whether use a maximum data compression, valid values:
;                  |TRUE     - Uses an algorithm which provides maximum data compression but with relatively slower performance.
;                  |FALSE    - Uses an algorithm which provides a balance between data compression and performance. (Default)
; Return values..: Success   - The size of the compressed data, in bytes.
;                  Failure   - 0 and sets the @error flag to non-zero, @extended flag may contain the NTSTATUS code.
; Author.........: Trancexx
; Modified.......: Yashied
; Remarks........: The input and output buffers must be different, otherwise, the function fails.
; Related........:
; Link...........: @@MsdnLink@@ RtlCompressBuffer
; Example........: Yes
; ===============================================================================================================================

Func _WinAPI_LZNTCompress(ByRef $tInput, ByRef $tOutput, $fMaximum = 0)

	Local $tBuffer, $tWorkSpace, $Ret, $Format = 0x0002

	If $fMaximum Then
		$Format = BitOR($Format, 0x0102)
	EndIf
	$tOutput = 0
	$Ret = DllCall('ntdll.dll', 'uint', 'RtlGetCompressionWorkSpaceSize', 'ushort', $Format, 'ulong*', 0, 'ulong*', 0)
	If @error Then
		Return SetError(1, 0, 0)
	Else
		If $Ret[0] Then
			Return SetError(1, $Ret[0], 0)
		EndIf
	EndIf
	$tWorkSpace = DllStructCreate('byte[' & $Ret[2] & ']')
	$tBuffer = DllStructCreate('byte[' & (DllStructGetSize($tInput) + 32) & ']')
	$Ret = DllCall('ntdll.dll', 'uint', 'RtlCompressBuffer', 'ushort', $Format, 'ptr', DllStructGetPtr($tInput), 'ulong', DllStructGetSize($tInput), 'ptr', DllStructGetPtr($tBuffer), 'ulong', DllStructGetSize($tBuffer), 'ulong', 4096, 'ulong*', 0, 'ptr', DllStructGetPtr($tWorkSpace))
	If @error Then
		Return SetError(1, 0, 0)
	Else
		If $Ret[0] Then
			Return SetError(1, $Ret[0], 0)
		EndIf
	EndIf
	$tOutput = DllStructCreate('byte[' & $Ret[7] & ']')
	DllCall('ntdll.dll', 'none', 'RtlMoveMemory', 'ptr', DllStructGetPtr($tOutput), 'ptr', DllStructGetPtr($tBuffer), 'ulong_ptr', $Ret[7])
	If @error Then
		$tOutput = 0
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[7]
EndFunc   ;==>_WinAPI_LZNTCompress


Server.au3
Код:
#Include <Constants.au3>
#Include <GDIPlus.au3>
#Include <WinAPIEx.au3>

Global Const $STM_SETIMAGE = 0x0172
Global Const $STM_GETIMAGE = 0x0173

TCPStartup()
$Main = TCPListen(@IPAddress1, 33891)
If @error Then
	Exit
EndIf

GUICreate('MyGUI', 800, 600, @DesktopWidth - 819, @DesktopHeight - 671)
$Pic = GUICtrlCreatePic('', 0, 0, 800, 600)
GUISetState()

Do
	$Socket = TCPAccept($Main)
Until $Socket <> -1

Global $tHeader = DllStructCreate('byte[4]')
Global $pHeader = DllStructGetPtr($tHeader)
Global $bData = 0, $Count = 0

_GDIPlus_Startup()

Do
	If Not IsBinary($bData) Then
		$bData = TCPRecv($Socket, 16384, 1)
		If @error Then
			ExitLoop
		EndIf
	EndIf
	If IsBinary($bData) Then
		If Not $Count Then
			DllStructSetData($tHeader, 1, $bData)
			$tData = DllStructCreate('dword', $pHeader)
			$Size = DllStructGetData($tData, 1)
			$tData = DllStructCreate('byte[' & $Size & ']')
			$pData = DllStructGetPtr($tData)
		EndIf
		$Lenght = BinaryLen($bData)
		$Sum = $Count + $Lenght
		If $Sum > $Size Then
			$dL = $Size - $Count
			$tPart = DllStructCreate('byte[' & $dL & ']', $pData + $Count)
			DllStructSetData($tPart, 1, $bData)
			$tByte = DllStructCreate('byte[' & $Lenght & ']')
			$tRecv = DllStructCreate('byte[' & ($Lenght - $dL) & ']', DllStructGetPtr($tByte) + $dL)
			DllStructSetData($tByte, 1, $bData)
			$bData = DllStructGetData($tRecv, 1)
			$Sum = $Size
		Else
			$tPart = DllStructCreate('byte[' & $Lenght & ']', $pData + $Count)
			DllStructSetData($tPart, 1, $bData)
			$Count = $Sum
			$bData = 0
		EndIf
		If $Sum = $Size Then
			_SetScreenshot($Pic, $tData)
			$Count = 0
		EndIf
	EndIf
Until GUIGetMsg() = -3

TCPCloseSocket($Socket)
TCPShutdown()

Func _SetScreenshot($CtrlID, ByRef $tData, $fUpdate = 0)

	Local $tBD, $tIn, $hDC, $hBitmap, $hImage, $pBits, $Lenght

	$hWnd = GUICtrlGetHandle($CtrlID)
	If Not $hWnd Then
		Return 0
	EndIf
	$tIn = DllStructCreate('byte[' & (DllStructGetData(DllStructCreate('dword', DllStructGetPtr($tData) + 4), 1)) & ']', DllStructGetPtr($tData) + 8)
	$Lenght = _WinAPI_LZNTDecompress($tIn, $tBD, 16777216)
	$hDC = _WinAPI_GetDC($hWnd)
	$hBitmap = _WinAPI_CreateDIBitmap($hDC, $tBD, $DIB_RGB_COLORS, DllStructGetPtr($tBD) + 40)
	_WinAPI_ReleaseDC($hWnd, $hDC)
	$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
	_WinAPI_DeleteObject($hBitmap)
	$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
	_GDIPlus_ImageDispose($hImage)
	_WinAPI_DeleteObject(_SendMessage($hWnd, $STM_SETIMAGE, $IMAGE_BITMAP, $hBitmap))
	$hPrev = _SendMessage($hWnd, $STM_GETIMAGE)
	If $hPrev <> $hBitmap Then
		_WinAPI_DeleteObject($hBitmap)
	EndIf
	If $fUpdate Then
		_WinAPI_UpdateWindow($hWnd)
	EndIf
	Return 1
EndFunc   ;==>_SetScreenshot

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_LZNTDecompress
; Description....: Decompresses an input data.
; Syntax.........: _WinAPI_LZNTDecompress ( ByRef $tInput, ByRef $tOutput [, $iBufferSize] )
; Parameters.....: $tInput      - "byte[n]" or any other structure that contains the data to be decompressed.
;                  $tOutput     - "byte[n]" structure that receives the decompressed data.
;                  $iBufferSize - The size of the buffer which are used for decompressing, in bytes. Default is 8388608 (8 MB).
; Return values..: Success      - The size of the decompressed data, in bytes.
;                  Failure      - 0 and sets the @error flag to non-zero, @extended flag may contain the NTSTATUS code.
; Author.........: Trancexx
; Modified.......: Yashied
; Remarks........: The input and output buffers must be different, otherwise, the function fails.
; Related........:
; Link...........: @@MsdnLink@@ RtlDecompressBuffer
; Example........: Yes
; ===============================================================================================================================

Func _WinAPI_LZNTDecompress(ByRef $tInput, ByRef $tOutput, $iBufferSize = 8388608)

	Local $tBuffer, $Ret

	$tOutput = 0
	$tBuffer = DllStructCreate('byte[' & $iBufferSize & ']')
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	$Ret = DllCall('ntdll.dll', 'uint', 'RtlDecompressBuffer', 'ushort', 0x0002, 'ptr', DllStructGetPtr($tBuffer), 'ulong', $iBufferSize, 'ptr', DllStructGetPtr($tInput), 'ulong', DllStructGetSize($tInput), 'ulong*', 0)
	If @error Then
		Return SetError(1, 0, 0)
	Else
		If $Ret[0] Then
			Return SetError(1, $Ret[0], 0)
		EndIf
	EndIf
	$tOutput = DllStructCreate('byte[' & $Ret[6] & ']')
	DllCall('ntdll.dll', 'none', 'RtlMoveMemory', 'ptr', DllStructGetPtr($tOutput), 'ptr', DllStructGetPtr($tBuffer), 'ulong_ptr', $Ret[6])
	If @error Then
		$tOutput = 0
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[6]
EndFunc   ;==>_WinAPI_LZNTDecompress
 
Автор
S

Sergey2210

Осваивающий
Сообщения
263
Репутация
31
Спасибо,работает,а почему когда я ставлю в клиенте TCPSend($Socket, _GetScreenshot(0, 0, -1, -1)) ,то получается вот такое:

 

Arei

Скриптер
Сообщения
938
Репутация
115
Скажите Yashied, а можно как то качество ухудшить что бы быстрее передавалось?
 

VladUs

Скриптер
Сообщения
621
Репутация
181
Arei [?]
Скажите Yashied, а можно как то качество ухудшить что бы быстрее передавалось?
Вообще - то в в последней версии кода Yashiedа проблема с быстродействием была на мой взгляд решена, не ухудшеним качества картинки, а ее сжатием. Через интернет у меня задержка составляет 2-4 секунды, по локалке 1-2 секунды. Это без использования Sleep() в коде.
 

Arei

Скриптер
Сообщения
938
Репутация
115
нужно ещё, помимо сжатия ухудшить качество.
 

VladUs

Скриптер
Сообщения
621
Репутация
181
Я сделал так:
Клиент :
Код:
#Include <WinAPIEx.au3>

TCPStartup()
$Socket = TCPConnect("192.168.100.2", 33891)
If @error Then
    Exit
EndIf

While 1
    TCPSend($Socket, _GetScreenshot(0, 0, 1280, 1024))
    If @error Then
        ExitLoop
    EndIf
   ; Sleep(1000)
WEnd

TCPShutdown()

Func _GetScreenshot($iX = 0, $iY = 0, $iWidth = -1, $iHeight = -1)

    Local $tBD, $tData, $tOut, $hBitmap, $hDesktop, $hSrcDC, $hDstDC, $hDstSv, $pBits, $Lenght

    If $iWidth = -1 Then
        $iWidth = @DesktopWidth
    EndIf
    If $iHeight = -1 Then
        $iHeight = @DesktopHeight
    EndIf
    $tBD = DllStructCreate($tagBITMAPINFOHEADER & 'byte[' & ($iWidth * $iHeight * 3) & ']')
    If @error Then
        Return 0
    EndIf
    DllStructSetData($tBD, 'biSize', 40)
    DllStructSetData($tBD, 'biWidth', $iWidth)
    DllStructSetData($tBD, 'biHeight', -$iHeight)
    DllStructSetData($tBD, 'biPlanes', 1)
    DllStructSetData($tBD, 'biBitCount', 24)
    DllStructSetData($tBD, 'biCompression', $BI_RGB)
    $hBitmap = _WinAPI_CreateDIBSection(0, $tBD, $DIB_RGB_COLORS, $pBits)
    $hDesktop = _WinAPI_GetDesktopWindow()
    $hSrcDC = _WinAPI_GetDC($hDesktop)
    $hDstDC = _WinAPI_CreateCompatibleDC($hSrcDC)
    $hDstSv = _WinAPI_SelectObject($hDstDC, $hBitmap)
    _WinAPI_StretchBlt ( $hDstDC, $iX, $iY, 800, 600, $hSrcDC, $iX, $iY, 1280, 1024,$SRCCOPY)
   ; _WinAPI_BitBlt($hDstDC, $iX, $iY, $iWidth, $iHeight, $hSrcDC, $iX, $iY, $SRCCOPY)
    _WinAPI_SelectObject($hDstDC, $hDstSv)
    _WinAPI_ReleaseDC($hDesktop, $hSrcDC)
    _WinAPI_DeleteDC($hDstDC)
    _WinAPI_GetBitmapBits($hBitmap, $iWidth * $iHeight * 3, DllStructGetPtr($tBD) + 40)
    _WinAPI_DeleteObject($hBitmap)
    $Lenght = _WinAPI_LZNTCompress($tBD, $tData)
    $tOut = DllStructCreate('dword;dword;byte[' & ($Lenght - Mod($Lenght, 4) + 4) & ']')
    DllStructSetData($tOut, 1, DllStructGetSize($tOut))
    DllStructSetData($tOut, 2, $Lenght)
    DllStructSetData($tOut, 3, DllStructGetData($tData, 1))
    Return Binary(DllStructGetData(DllStructCreate('byte[' & DllStructGetSize($tOut) & ']', DllStructGetPtr($tOut)), 1))
EndFunc   ;==>_GetScreenshot



Func _WinAPI_LZNTCompress(ByRef $tInput, ByRef $tOutput, $fMaximum = 0)

    Local $tBuffer, $tWorkSpace, $Ret, $Format = 0x0002

    If $fMaximum Then
        $Format = BitOR($Format, 0x0102)
    EndIf
    $tOutput = 0
    $Ret = DllCall('ntdll.dll', 'uint', 'RtlGetCompressionWorkSpaceSize', 'ushort', $Format, 'ulong*', 0, 'ulong*', 0)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        If $Ret[0] Then
            Return SetError(1, $Ret[0], 0)
        EndIf
    EndIf
    $tWorkSpace = DllStructCreate('byte[' & $Ret[2] & ']')
    $tBuffer = DllStructCreate('byte[' & (DllStructGetSize($tInput) + 32) & ']')
    $Ret = DllCall('ntdll.dll', 'uint', 'RtlCompressBuffer', 'ushort', $Format, 'ptr', DllStructGetPtr($tInput), 'ulong', DllStructGetSize($tInput), 'ptr', DllStructGetPtr($tBuffer), 'ulong', DllStructGetSize($tBuffer), 'ulong', 4096, 'ulong*', 0, 'ptr', DllStructGetPtr($tWorkSpace))
    If @error Then
        Return SetError(1, 0, 0)
    Else
        If $Ret[0] Then
            Return SetError(1, $Ret[0], 0)
        EndIf
    EndIf
    $tOutput = DllStructCreate('byte[' & $Ret[7] & ']')
    DllCall('ntdll.dll', 'none', 'RtlMoveMemory', 'ptr', DllStructGetPtr($tOutput), 'ptr', DllStructGetPtr($tBuffer), 'ulong_ptr', $Ret[7])
    If @error Then
        $tOutput = 0
        Return SetError(1, 0, 0)
    EndIf
    Return $Ret[7]
EndFunc   ;==>_WinAPI_LZNTCompress

Т.е вместо функции _WinAPI_BitBlt() использую функцию _WinAPI_StretchBlt(). Она позволяет сжимать или растягивать рисунок в зависимости от размеров принимающего Device context, тем самым теряется качество картинки (если размеры формы и рабочего стола совпадают тогда потери не будет. Но так как на стороне сервера форма имеет размер 800х600 , а разрешения экрана на стороне клиента больше размеров формы сервера тогда будет происходить сжатие, и соответственно и потеря качества.)
Конечно идеально бы было, чтобы результат работы функции _WinAPI_BitBlt() сначало конвертировался из .bmp в .png (для примера), а потом сжимался и отправлялся по сети.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
VladUs сказал(а):
Конечно идеально бы было, чтобы результат работы функции _WinAPI_BitBlt() сначало конвертировался из .bmp в .png (для примера), а потом сжимался и отправлялся по сети.

Это бессмысленно, т.к. картинка после PNG компрессии будет примерно такого же размера, как и после LZNT компрессии. А двойное зжатие ничего не даст. Если нужно еще уменьшить размер картинки, то нужно использовать JPEG, но это потеря качества. Кроме того, в GDI не предусмотренна работа с PNG и JPEG.
 
Верх