1

Тема: AHK: Возможно ли получить цвет пикселя неактивного окна

Окно не просто неактивное, оно или свёрнуто, или перекрыто другим окном. В нём происходит какая-то активность. Надо узнать цвет пикселей в некоторой области.
Есть команды PixelSearch и GetPixelColor, но они определяют цвет на экране вообще, без привязки к окну.
Возможно ли это в принципе?

2

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Avenger пишет:

Возможно ли это в принципе?

Тут не подскажу, а вот ежели попробовать обходной путь:

1. Запомнить текущее Foreground window.
2. Сделать нужное окно Foreground.
3. GetPixelColor.
4. Сделать запомненное окно Foreground'ом.

Или нужное окно на передний план выводить никак нельзя/невозможно/нежелательно?

3

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

alexii пишет:

Или нужное окно на передний план выводить никак нельзя/невозможно/нежелательно?

Угу, совсем никак нельзя

4

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Вообще-то, PixelGetColor...

А если через WinAPI GetPixelColor попробовать?

5

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Это как? Т.е не средствами AHK? Можно примерчик?

6

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Неа. Примерчик GetPixelColor смотри в MSDN. Из AHK вызывать через DllCall. Реально ли это сделать - я не подскажу, нужны более опытные товарищи, желательно С-шники; они проконсультируют.

7

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Не претендую на роль опытного товарища, но думаю, что это не сработает. Вот что пишет MS про GetPixel:

If the pixel is outside of the current clipping region, the return value is CLR_INVALID.

"Clipping region" - всегда в видимой части окна. Его координаты сообщаются приложению, чтобы оно могло уменьшить себе работу, ограничив вывод в окно только этой областью. Если оно этим не воспользуется, обрезку сделает Windows. Т.е. по-любому цвет в невидимой части не вычисляется и взять его негде.

Разве что вообразить себе какой-то сильно хитрый способ узнать "что тут было бы, если бы", т.е. что нарисовала бы здесь программа, если бы это место было видимым. Но это уже в саму программу влазить надо, я так понимаю.

8

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

YMP пишет:

Не претендую на роль опытного товарища

А я тем более , но вот здесь

YMP пишет:

по-любому цвет в невидимой части не вычисляется и взять его негде

по-моему неверно. Нужен DC, и от него плясать. Иначе как бы шла отрисовка в невидимых окнах? Впрочем, я только подавал идею, за реализацию не берусь. Но какой-то способ определённо существует. Другой вопрос, можно ли его привязать к AHK.

9

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

alexii пишет:

Но какой-то способ определённо существует.

Не-е, так я не играю.    Ты покажи этот способ, тогда я поверю, что он существует. Допустим, получили DC, а что дальше? Какой план действий?

10

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Знал бы - показал, а так могу только строить предположения. Не более.

11

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

2YMP: разбираясь с #2, вспомнил об этой теме. Получить цвет точки из неактивного окна, похоже, возможно (в том числе и со сдвинутым за видимые границы экрана — если потребуется как-то скрыть окно, либо перекрытым другим окном). Работа с минимизированным или скрытым окном — нет (во всяком случае, у меня с минимизированным окном срабатывало ~ 1/10 случаев, если не реже, так что я склонен считать это случайностью). На примере Paint'а и точки 300, 300; работать будет только под XP и выше; за качество кода не ручаюсь, тяжело мне AHK даётся — потратил вчетверо больше времени на перевод на AHK, нежели на написание первоначального варианта на AutoIt :

X := 300
Y := 300

SetFormat, Integer, Hex

WinGet, hWnd, ID, ahk_class MSPaintApp

hDC     := DllCall("GetDC", Int, hWnd)
hMemDC  := DllCall("CreateCompatibleDC", UInt, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", UInt, hDC, Int, Width, Int, Height)
DllCall("SelectObject", UInt, hMemDC, UInt, hBitmap)
DllCall("PrintWindow", UInt, hWnd, UInt, hMemDC, UInt, 0)
Color   := DllCall("GetPixel", UInt, hMemDC, UInt, X, UIint, Y)

DllCall("DeleteObject", UInt, hBitmap)
DllCall("DeleteDC", UInt, hMemDC)
DllCall("ReleaseDC", UInt, ahk_id %hWnd%, UInt, hDC)

Transform, Red,   BitAnd, Color, 0x0000FF

Transform, Green, BitAnd, Color, 0x00FF00
Transform, Green, BitShiftRight, Green, 8

Transform, Blue,  BitAnd, Color, 0xFF0000
Transform, Blue,  BitShiftRight, Blue, 16

SetFormat, Integer, D

MsgBox, Color %A_Tab% %Color%`n`nRed %A_Tab% %Red%`nGreen %A_Tab% %Green%`nBlue %A_Tab% %Blue%

Аналогичный код на AutoIt (собственно, на нём писал и затем переделывал на AHK):

#Include <WinAPI.au3>

#NoTrayIcon

AutoItSetOption("TrayIconDebug", 0)
AutoItSetOption("MustDeclareVars", 1)

AutoItSetOption("WinTitleMatchMode", 4)
AutoItSetOption("WinDetectHiddenText", 1)

Local $hWnd
Local $hDC
Local $hMemDC
Local $tRect
Local $dwWidth
Local $dwHeight
Local $hBitmap

Local $Color

Local $intX = 300
Local $intY = 300

$hWnd     = WinGetHandle("[CLASS:MSPaintApp]")

$hDC      = _WinAPI_GetDC($hWnd)
$hMemDC   = _WinAPI_CreateCompatibleDC($hDC)
$tRect    = _WinAPI_GetWindowRect($hWnd)

$dwWidth  = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left")
$dwHeight = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top")

$hBitmap  =_WinAPI_CreateCompatibleBitmap($hDC, $dwWidth, $dwHeight)
_WinAPI_SelectObject($hMemDC, $hBitmap)
DllCall("user32.dll", "int", "PrintWindow", "hwnd", $hWnd, "ptr", $hMemDC, "uint", 0)

$Color = DllCall("gdi32.dll", "dword", "GetPixel", "ptr", $hMemDC, "int", $intX, "int", $intY)

_WinAPI_DeleteObject($hBitmap)
_WinAPI_DeleteDC($hMemDC)
_WinAPI_ReleaseDC($hWnd, $hDC)

ConsoleWrite("The Color value is 0x" & Hex(BitOR( _
    BitShift(BitAND($Color[0], 0x000000FF),-16), _
    BitShift(BitAND($Color[0], 0x0000FF00),  0), _
    BitShift(BitAND($Color[0], 0x00FF0000), 16)), 6) _
    & @CRLF & @CRLF)

ConsoleWrite("The Red value is       0x" & Hex(BitShift(BitAND($Color[0], 0x000000FF),  0), 2) & @CRLF)
ConsoleWrite("The Green value is     0x" & Hex(BitShift(BitAND($Color[0], 0x0000FF00),  8), 2) & @CRLF)
ConsoleWrite("The Blue value is      0x" & Hex(BitShift(BitAND($Color[0], 0x00FF0000), 16), 2) & @CRLF)

Exit(0)

P.S. Я тут постфактум посмотрел — поиск на официальном форуме AutoHotKey по сочетанию «PrintWindow» за последние полгода даёт интересные результаты . Народ активно начал внедрять библиотеки функций.

12

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Да, работает, очень интересный способ. А откуда ограничение к ХР и выше? Вроде все функции доступны и в более ранних виндах.

Учитывая, что переменные в АНК хранятся как строки, можно и так извлечь отдельные цвета:

Red   := SubStr(Color, 7, 2)
Green := SubStr(Color, 5, 2)
Blue  := SubStr(Color, 3, 2)

13

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Кроме PrintWindow Function (Windows):

Requirements
Minimum supported client: Windows XP
Minimum supported server: Windows Server 2003
Header: Winuser.h (include Windows.h)
Library: User32.lib
DLL: User32.dll

Способ, конечно, весьма не скорострельный. Как думаете, можно ли извлечь из него какую-то практическую пользу?

Учитывая, что переменные в АНК хранятся как строки, можно и так извлечь отдельные цвета:

Спасибо, не знал.
OFF1: меня вначале удивил тот факт, что цвет возвращается в виде BGR.
OFF2: у меня любой скрипт будет похож на VBS .

14

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Да, я невнимательно читал. Но, кстати, есть там и вот что:

Remarks

This function is similar to WM_PRINT.

Т.е. если она просто посылает это сообщение, то можно послать его и через SendMessage, в более ранних виндах.

Насчёт WM_PRINT в MSDN так:

Minimum supported client Windows 2000 Professional
Minimum supported server Windows 2000 Server

в PSDK этак:

Requirements
  Windows NT/2000/XP: Included in Windows NT 4.0 and later.
  Windows 95/98/Me: Included in Windows 95 and later.

Но есть ещё старый Win32 Programmer's Reference, который согласен с PSDK:

WM_PRINT

Windows NT Yes
Win95 Yes

Практическая польза, наверно, возможна, но пока не знаю, какая.

15

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Я к сожалению 3/4 кода на AHK от alexii не понял, а комментариев в нём нет. Поясните где там что, хоть в общих чертах, пожалуйста!

16

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Не работает... Переменая Color пустая.... МБ кто подскажет почему ?

17

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Где и как именно «не работает»?

18

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Скопирывал код как он есть, открыл пеинт, запустил скрипт, переменая Color пустая, тоесть цвет не возвращает!

19

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Какой код из двух? Какая ОС? Какая версия AHK (если код — первый)?

20

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Первый код для AHK, Windows 7 x64, AutoHotkey_L 1.1.09.0.0 x64

21

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Всё. Теперь ждите специалистов, у которых есть и второе, и третье .

22

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Порылся в сети, нашол похожий код, но проблемма все таже!


WinGet WindowID, id, Безымянный - Paint
hdc_frame := DllCall( "GetDC", UInt, WindowID )
hdc_buffer := DllCall("gdi32.dll\CreateCompatibleDC", UInt,  hdc_frame)
hbm_buffer := DllCall("gdi32.dll\CreateCompatibleBitmap", UInt,hdc_frame, Int,A_ScreenWidth, Int,A_ScreenHeight)
DllCall( "gdi32.dll\SelectObject", UInt,hdc_buffer, UInt,hbm_buffer)
DllCall( "PrintWindow", UInt , tablelist_%a_index% , UInt , hdc_buffer , UInt , 0 ) 
getlength = 200
getheight = 100
x1 = 0
y1 = 0 
DllCall("gdi32.dll\BitBlt" , UInt,hdc_frame    , Int, 0, Int, 0, Int, getlength, Int, getheight, UInt,hdc_buffer, Int, x1, Int, y1 , UInt, 0xCC0020 )      
pixel_x = 20
pixel_y = 20
pix := DllCall("GetPixel", UInt, hdc_buffer, Int, pixel_x, Int, pixel_y)
DllCall( "gdi32.dll\DeleteObject", "uint", hbm_buffer )
DllCall( "gdi32.dll\DeleteDC" , "uint", hdc_frame )
DllCall( "gdi32.dll\DeleteDC" , "uint", hdc_buffer )
MsgBox, %pix%
ExitApp

23

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Современная версия такая:

X := 940
Y := 70

WinGet, hWnd, ID, ahk_class MSPaintApp

hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0)
ColorBGR := DllCall("GetPixel", Ptr, hMemDC, UInt, X, UInt, Y)

DllCall("DeleteObject", Ptr, hBitmap)
DllCall("DeleteDC", Ptr, hMemDC)
DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)

SetFormat, IntegerFast, Hex
MsgBox, % ColorRGB := RegExReplace(ColorBGR, "(..)(..)(..)(..)", "$1$4$3$2")

Но у меня работает и вариант от alexii, если ошибки исправить:
1. в строке

Color   := DllCall("GetPixel", UInt, hMemDC, UInt, X, UIint, Y)

заменить UIint на UInt
2. в строке

DllCall("ReleaseDC", UInt, ahk_id %hWnd%, UInt, hDC)

ahk_id %hWnd% на hWnd.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

24

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Спасибо огромное! Все работает! В который раз выручаете!

25

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

teadrinker пишет:

заменить UIint на UInt

Как же оно работало-то? У меня разве что одно предположение: в оригинале было «Uint, Y», скопировав код на форум, я увидел «некрасивость», решил поправить на «UInt, Y», но поправил так, что вышло «UIint, Y» .

P.S. Красота требует жертв .

26

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Ой, ошибочка . На самом деле правильно так:

X := 940
Y := 70

WinGet, hWnd, ID, ahk_class MSPaintApp

hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0)
ColorBGR := DllCall("GetPixel", Ptr, hMemDC, UInt, X, UInt, Y)

DllCall("DeleteObject", Ptr, hBitmap)
DllCall("DeleteDC", Ptr, hMemDC)
DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)

SetFormat, IntegerFast, Hex   ; не обязательно, нужно только для демонстрации
MsgBox, % ColorRGB := DllCall("Ws2_32\ntohl", UInt, ColorBGR, Ptr) >> 8
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

27 (изменено: stealzy, 2014-03-25 18:42:31)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Кхм, а цвет пикселя под полноэкранным окном, не делая его прозрачным получить возможно?
(т.е. под ним может быть любое окно, если бы определенное, то да)

28

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

А что, в этом случае у вас код не работает?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

29

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Или как узнать окно под координатами X,Y, не перемещая туда мышь?
(MouseGetPos,,, id_under_mouse)

30 (изменено: stealzy, 2014-03-27 15:34:18)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

В смысле, если переместить туда мышь и щелкнуть, оно станет активным
В том то и дело, что нет

31

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

А что, заранее неизвестно, какое окно там должно быть?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

32

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Всем привет, столкнулся с такой проблемой, скрипт из этой темы работал прекрасно на старой системе под Windows 7, но при переезде на W8 появилась ошибка. Цвет в правой и нижней части окна (примерно за 80% от его ширины) равняется нулю. Для проверки сделал следующий скрипт, тестирую на окне скайпа, ошибка все та же. Уже не знаю куда копать, помогите пожалуйста!

F1::
SetTimer, WatchCursor, 100
return

WatchCursor:
MouseGetPos, X, Y


WinGet, hWnd, ID, ahk_class tSkMainForm

hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0)
ColorBGR := DllCall("GetPixel", Ptr, hMemDC, UInt, X, UInt, Y)

DllCall("DeleteObject", Ptr, hBitmap)
DllCall("DeleteDC", Ptr, hMemDC)
DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)

;SetFormat, IntegerFast, Hex
ColorRGB5 := RegExReplace(ColorBGR, "(..)(..)(..)(..)", "$1$4$3$2")

ToolTip, %X% %Y% %ColorRGB5%
return

33 (изменено: stealzy, 2015-09-21 22:04:27)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Функция для получения цвета пикселя в клиентской области (перекрытого?) окна:


; Цвет возвращается в BGR, если вам нужен RGB, установите последний опц. параметр в отличное от нуля значение.
; hWnd - ID окна
; x и y могут быть представлены относительно ширины и высоты клиентской области:
; для этого замените их массивами типа [a, b], в результате x := a*clientWidth + b; y := a*clientHeight + b
; Точка в центре клиентской области: PixelGetColorBackgroundWinClientArea(hWnd, [0.5,0], [0.5,0])
; Точка на 100 пикселей левее правого края и 50 ниже верхнего: PixelGetColorBackgroundWinClientArea(hWnd, [1,-100], 50)
; Если пытаться взять цвет пикселя за пределами окна, возвращает -1

PixelGetColorBackgroundWinClientArea(hWnd, x, y, RGB:=0) {
    VarSetCapacity(pt, 16)
    NumPut(x, pt, 0)
    NumPut(y, pt, 4)
    NumPut(w, pt, 8)
    NumPut(h, pt, 12)
    if (!DllCall("GetClientRect", "uint", hWnd, "uint", &pt))
        Return
    if (!DllCall("ClientToScreen", "uint", hWnd, "uint", &pt))
        Return
    clientX := NumGet(pt, 0, "int")
    clientY := NumGet(pt, 4, "int")
    clientWidth := NumGet(pt, 8, "int")
    clientHeight := NumGet(pt, 12, "int")
    WinGetPos, winX, winY, Width, Height, ahk_id %hWnd%
    
    if IsObject(x)
        x:=Round(x[1]*clientWidth)+x[2]
    if IsObject(y)
        y:=Round(y[1]*clientHeight)+y[2]
    
    x+=(clientX - winX), y+=(clientY - winY)
    
    hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
    hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
    hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
    DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)

    DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0) ; 50-100 ms
    ColorBGR := DllCall("GetPixel", Ptr, hMemDC, UInt, x, UInt, y)
    
    DllCall("DeleteObject", Ptr, hBitmap)
    DllCall("DeleteDC", Ptr, hMemDC)
    DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)
    
    if RGB {
        fmtI := A_FormatInteger
        SetFormat, IntegerFast, Hex
        ColorRGB := ColorBGR >> 16 & 0xff | ColorBGR & 0xff00 | (ColorBGR & 0xff) << 16
        ColorRGB .= ""
        SetFormat, IntegerFast, %fmtI%
        Return ColorRGB
    } else
        Return ColorBGR
}

34 (изменено: stealzy, 2017-04-01 11:45:44)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

GetDCEx предпочтительна по скорости для взятия <100 пикселей из битмапа.

hwnd := WinActive("A"), WinPos := WinGetP(hwnd), x := WinPos.Client2Win.w//2, y := 100

hDC := Window_CreateCapture(hwnd)
colorBGR := Client_GetPixel(hDC, x, y, WinPos) ; client x y
; colorBGR2 := Client_GetPixel(hDC, 700, 400, WinPos)
; colorBGR := GetPixel(hDC, x, y) ; window x y
Window_DeleteWindowCapture(hwnd, hDC)

CoordMode Mouse, Client
MouseMove x, y
MsgBox % "Pixel (" x ", " y ") from window client area: " Format("{:#08x}",colorBGR)
Return

Window_CreateCapture(hwnd) {
	Return DllCall("user32.dll\GetDCEx", "UInt", hwnd, "UInt", 0, "UInt", 1|2)
}
GetPixel(hDC, x, y) {
	Return DllCall("gdi32.dll\GetPixel", "UInt", hDC, "Int", x, "Int", y, "UInt") ; colorBGR
}
Client_GetPixel(hDC, x, y, WinPos) {
	Return DllCall("gdi32.dll\GetPixel", "UInt", hDC, "Int", x+WinPos.Client2Win.x, "Int", y+WinPos.Client2Win.y, "UInt")
}
Window_DeleteWindowCapture(hwnd, hDC) {
	DllCall("user32.dll\ReleaseDC", "UInt", hwnd, "UInt", hDC)
}
WinGetP(hwnd) {
	WinGetPos, x, y, w, h, ahk_id %hWnd%
	WinP := {x:x, y:y, w:w, h:h}
	VarSetCapacity(pt, 16)
	NumPut(x, pt, 0) || NumPut(y, pt, 4) || NumPut(w, pt, 8) || NumPut(h, pt, 12)
	if (!DllCall("GetClientRect", "uint", hwnd, "uint", &pt))
		Return
	if (!DllCall("ClientToScreen", "uint", hwnd, "uint", &pt))
		Return
	x := NumGet(pt, 0, "int"), y := NumGet(pt, 4, "int")
	w := NumGet(pt, 8, "int"), h := NumGet(pt, 12, "int")
	Client := {x:x, y:y, w:w, h:h}
	Client2Win := {x:x-WinP.x, y:y-WinP.y, w:w, h:h}
	Return WinP := {x:WinP.x, y:WinP.y, w:WinP.w, h:WinP.h, Client2Win:Client2Win, Client:Client}
}

При использовании GetDCEx взятие битмапа происходит быстро, но каждый вызов GetPixel стоит 0.3 мс.

Если интересует только один пиксель, можно объединить все в ф-ию:

GetPixel_(x, y, hwnd) {
	WinPos := WinGetP(hwnd)
	hDC := Window_CreateCapture(hwnd)
	colorBGR := Client_GetPixel(hDC, x, y, WinPos)
	Window_DeleteWindowCapture(hwnd, hDC)
	Return colorBGR
}

35

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Здравствуйте.
Я так полагаю для того чтобы найти пиксель в неактивном окне, существует способ - использование библиотеки.
Я нашел 3 библиотеки, в которых это возможно исполнить, одна постилась в этой теме.

Правда как это использовать я не понимаю. У меня всегда выводит белый цвет (0xFFFFFF).

Также есть Gdip.ahk.

Лучший вариант, как мне кажется Display.ahk с функцией

Display_PixelSearch(x, y, w, h, color, variation [, id])

Буду признателен, если кто-нибудь объяснит как это использовать, если нужно найти, например 0x241CED (красный).

36 (изменено: stealzy, 2017-04-05 18:20:46)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

У меня всегда выводит белый цвет

Кто выводит, что выводит? Где код?
Поиск пикселя должен возращать 1, если найден или 0, если нет.

как это использовать

Найдите hwnd (ahk_id) целевого окна (можно сделать это через класс окна, либо через pid запускаемого процесса) - это id; определите область поиска внутри окна в оконных координатах - это x,y,w,h; color - без комментариев, variation - перевести сможете сами, надеюсь.

Дополнение к примеру выше для поиска по небольшой области.
Также для ускорения, если ваш объект одноцветный и имеет неточечные размеры, то можно перебирать пиксели по диагоналям/линиям, ведя поиск через несколько линий. Допустим объект имеет размер 10 пикселей, значит мы можем ускорить поиск в 10 раз, ища в одной из 10 линий.

Pos := WinGetP(hwnd)
hDC := Window_CreateCapture(hwnd)
If SearchPixel(hDC, 100, 200, 150, 250, Pos)
	MsgBox Found red pixel.
Window_DeleteWindowCapture(hwnd, hDC)
Return

SearchPixel(hDC, x1, y1, x2, y2, WinPos) {
	; поиск ведем по клиентским координатам, а битмап охватывает все окно, поэтому приводим клиентские кооординаты к оконным
	x1+=WinPos.Client2Win.x, x2+=WinPos.Client2Win.x, y1+=WinPos.Client2Win.y, y2+=WinPos.Client2Win.y

	x:=x1, y:=y1, red:=false
	While (x<=x2)
	{
		While (y<=y2)
		{
			colorBGR := DllCall("GetPixel", "UInt", hDC, "Int", x, "Int", y, "UInt") ; 0.3 ms
			; OutputDebug % Format("{:#08x}",colorBGR)
			if (!red && colorBGR=0x241CED) {
				red:=true
			}
			y+=1
		}
		x+=1
	}
	Return red
}

Поиск же по большой области, допустим 1000х1000 у этого метода займет 1000*1000*0,0003сек =300сек=5мин. В этом случае предпочтительнее использовать CreateCompatibleDC, но само взятие битмапа будет занимать около 60мс.

37

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

stealzy пишет:

Кто выводит, что выводит? Где код?

Недоразумение вышло.

X := 940
Y := 70

WinGet, hWnd, ID, ahk_class MSPaintApp

hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0)
ColorBGR := DllCall("GetPixel", Ptr, hMemDC, UInt, X, UInt, Y)

DllCall("DeleteObject", Ptr, hBitmap)
DllCall("DeleteDC", Ptr, hMemDC)
DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)

SetFormat, IntegerFast, Hex   ; не обязательно, нужно только для демонстрации
MsgBox, % ColorRGB := DllCall("Ws2_32\ntohl", UInt, ColorBGR, Ptr) >> 8

Область поиска пикселя будет от курсора. Сначала +-10 пикселей x1y1x2y2, если не находит еще +-10. Т.е. область будет расширяться если нужно. Это циклическое действие и при находке пикселя, область поиска будет возвращаться в исходную позицию от курсора.

38

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Т.е. целевое окно будет перекрыто другими окнами, но искать вы собираетесь от курсора, так?

CoordMode Mouse, Screen

classApp := "ahk_class MSPaintApp"
exeApp := "mspaint.exe"
IfWinExist % classApp
	WinActivate % classApp
Else
	Run % exeApp
WinWaitActive % classApp
hwnd := WinActive(classApp)
sleep 200

MouseGetPos x, y
WinGetPos px, py,,, ahk_id %hwnd%

SetTitleMatchMode RegEx
IfWinNotExist ahk_class MozillaWindowClass
	WinExist("ahk_class Chrome")
WinActivate

hMemDC := CreateBitmap(hwnd, hDC, hBitmap)
col := PixelGetColorBackGround(hMemDC, x-px, y-py)
MsgBox % Format("{:#08x}",col) " | " timelapse "ms"
; здесь вы можете организовать поиск пикселя, последовательно находя цвета и сравнивая с искомым.
DeleteBitmap(hWnd, hDC, hBitmap)

Return

CreateBitmap(hWnd, ByRef hDC, ByRef hBitmap) {
	WinGetPos,,, Width, Height, ahk_id %hWnd%
	hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
	hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
	hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
	DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
	DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0) ; 50-100 ms
	Return hMemDC
}
PixelGetColorBackGround(hMemDC, x, y) {
	Return DllCall("GetPixel", Ptr, hMemDC, UInt, x, UInt, y)
}
DeleteBitmap(hWnd, ByRef hDC, ByRef hBitmap) {
	DllCall("DeleteObject", Ptr, hBitmap)
	DllCall("DeleteDC", Ptr, hMemDC)
	DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)
}

39

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

stealzy
Курсор, либо точка со своей координатой, которая будет меняться. В принципе это не так важно, не самое трудное в реализации.
Ваш крайний скрипт, я так понял, выдает именно какой цвет под курсором?

40 (изменено: SeaVodikendu, 2017-04-06 12:58:27)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Пытаюсь использовать функцию из этой библиотеки

#Include Display.ahk


home::

Display_PixelSearch(60, 400, 50, 50, 0x241CED, coors [, 0x6071e])

msgbox, %coors%

return

в окне Paint`а - выдает пустое значение...

41 (изменено: stealzy, 2017-04-06 17:07:10)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Да, в моем последнем сообщении пиксель берется под курсором, потому что вы упомянули курсор.
Но мне неясно, каким боком тут курсор, если окно неактивно и перекрыто другими окнами? Курсор мыши может быть в одном углу экрана, или в другом углу. Поскольку вы сами не можете определилиться с областью поиска, будем полагать, что вы ищите пиксель по всей площади окна.
Касательно предыдущего вашего сообщения: зачем вы написали кв.скобки [] в вызове функции? Ф-ия в параметрах может принимать только цифры, строки и переменные, разделенные запятыми. Скобки не могут быть числом и не могут быть переменной, а строки надо обрамлять кавычками. Что означает число 0x6071e?

Вам нужны координаты всех красных пикселей, или первого попавшегося?
Или вам не нужны координаты, а всего лишь знать есть такой пиксель в окне или нет?
От этого будет зависеть вид ф-ии поиска.

42 (изменено: SeaVodikendu, 2017-04-06 20:44:52)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

stealzy пишет:

Но мне неясно, каким боком тут курсор, если окно неактивно и перекрыто другими окнами?

В первый раз координаты идут от курсора, а дальше уже от координат где найдется пиксель с нужным цветом.
Я с этим сам попробую разобраться.

stealzy пишет:

зачем вы написали кв.скобки [] в вызове функции?

Я с копипастил с форума и только сейчас понял, что это обычный шаблон, как из документации.

stealzy пишет:

Что означает число 0x6071e?

Id или HWND Paint`а, выяснил при помощи ControlGetPos.
Id с этого кода:

Display_PixelSearch(x, y, w, h, color, variation [, id])

Нужны координаты первого попавшего пикселя.

43

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Display_PixelSearch в библиотеки Display.ahk не возвращает координаты, а лишь значение "1" или "0", если есть такой цвет или нет. Так что Display.ahk в этом плане не помощник.

44 (изменено: stealzy, 2017-04-09 20:28:29)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Запускает, если не запущен, Paint и находит координаты первого коричневого пикселя (в палитре Paint), после чего поиск прекращается.
Поиск идет слева-направо, сверху вниз. По умолчанию, поиск ведется по всей клиентской части окна, если будете ограничивать область, координаты x1 x2 y1 y2 задавайте тоже клиентские.
Координаты найденного пикселя будут оконные.

SetBatchLines -1
classApp := "ahk_class MSPaintApp", exeApp := "mspaint.exe"
classApp := "ahk_class MSPaintApp", exeApp := "mspaint.exe"
IfWinNotExist % classApp
{
	Run % exeApp
	Sleep 1000
}
hwnd := WinExist(classApp)

; делаем снимок
hMemDC := WindowBitmap_Capture(hwnd, hDC, hBitmap)
; находим пиксели
WinP := WinGetP(hwnd)
start:=A_TickCount
Brown:=0x577AB9
pix := WindowBitmap_SearchFirstPixel(hMemDC, Brown, WinP)
; col := WindowBitmap_PixelGetColor(hMemDC, x, y)
; MsgBox % (col = -1) ? "Error" : Format("{:#08x}",col)
period:=A_TickCount-start
; очищаем память
WindowBitmap_Delete(hWnd, hDC, hBitmap)

MsgBox % "Pixel " Brown (IsObject(pix) ? " found on " pix.x "x " pix.y "y" : " not found") " | " period "ms "
WinActivate ahk_id %hwnd%
MouseMove pix.x, pix.y
Return

WindowBitmap_PixelGetColor(hMemDC, x, y) {
	Return DllCall("GetPixel", Ptr, hMemDC, UInt, x, UInt, y)
}
WindowBitmap_Capture(hWnd, ByRef hDC, ByRef hBitmap) {
	WinGetPos,,, Width, Height, ahk_id %hWnd%
	hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
	hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
	hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
	DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
	DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0) ; 0-50 ms depend on window size; GetPixel - 0.004 ms on each ( > 8sec on FullHD display capture)
	Return hMemDC
}
WindowBitmap_Delete(hWnd, ByRef hDC, ByRef hBitmap) {
	DllCall("DeleteObject", Ptr, hBitmap)
	DllCall("DeleteDC", Ptr, hMemDC)
	DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)
}
WindowBitmap_SearchFirstPixel(hDC, searchColorBGR, WinP, x1:=0, y1:=0, x2:="", y2:="") {
	x1+=WinP.Client2Win.x, y1+=WinP.Client2Win.y
	x2 := x2 ? x2 : WinP.Client2Win.x + WinP.Client.w
	y2 := y2 ? y2 : WinP.Client2Win.y + WinP.Client.h

	y:=y1
	While (++y<y2)
	{
		x:=x1
		While (++x<x2)
		{
			colorBGR := DllCall("GetPixel", "UInt", hDC, "Int", x, "Int", y, "UInt")
			; OutputDebug % "[" Format("{:03}",x) "," Format("{:03}",y) "]: " Format("{:#08x}",colorBGR)
			if (colorBGR = searchColorBGR) {
				Return {x:x, y:y}
			}
		}
	}
	Return false
}
WinGetP(hwnd) {
	WinGetPos, xWin, yWin, wWin, hWin, ahk_id %hWnd%
	VarSetCapacity(pt, 16)
	NumPut(x, pt, 0) || NumPut(y, pt, 4) || NumPut(w, pt, 8) || NumPut(h, pt, 12)
	if (!DllCall("GetClientRect", "uint", hwnd, "uint", &pt))
	|| (!DllCall("ClientToScreen", "uint", hwnd, "uint", &pt))
		Return
	x := NumGet(pt, 0, "int"), y := NumGet(pt, 4, "int")
	w := NumGet(pt, 8, "int"), h := NumGet(pt, 12, "int")
	Client := {x:x, y:y, w:w, h:h}, Client2Win := {x:x-xWin, y:y-yWin, w:w, h:h}
	Return {x:xWin, y:yWin, w:wWin, h:hWin, Client2Win:Client2Win, Client:Client}
}

У меня 8 пикселей сверху не соответсвуют реальным, а также все неклиентские пиксели (поэтому и ограничил поиск).
Также к недостаткам отнесу время работы вызываемой из Dll ф-ии GetPixel - 0.004 мс, что для FullHD дисплея выливается в 8 секунд, если окно развернуто на весь экран, и ф-ия поиска проходит до конца, не найдя пикселя.
Забавно, что в некоторых случаях белый холст Painta сей метод видит черным (что можно увидеть также в AhkSpy от serzh42saratov).
Если сделать ассемблерную вставку, то прошерстить экран можно за доли секунды, просто пока никто не заморочился сделать это.

45 (изменено: SeaVodikendu, 2017-04-09 03:35:00)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Скрипт отлично работает, довольно быстро. Спасибо.

46 (изменено: SeaVodikendu, 2017-04-09 18:16:02)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

stealzy
Можно ли в ваш скрипт прибавить вариаций к цвету? И сколько их вообще в данном варианте?

47

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

А вы загляните внутрь ф-ии поиска WindowBitmap_SearchFirstPixel().
После получения пикселя, используется сравнение if (colorBGR = searchColorBGR). Надеюсь вам очевидно, сколько вариаций тут может быть.
Для добавления вариации вместо = сравнения используйте ф-ию Display_CompareColors() из Display.ahk.
Разумеется переменную вариации надо будет добавить параметром и в ф-ию, которая будет вызывать Display_CompareColors().

48

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

stealzy
Спасибо, будем думать.

49

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

While (++x<x2)
		{
			colorBGR := DllCall("GetPixel", "UInt", hDC, "Int", x, "Int", y, "UInt")
			; OutputDebug % "[" Format("{:03}",x) "," Format("{:03}",y) "]: " Format("{:#08x}",colorBGR)
			ColVar := Display_CompareColors(bgr1:="", bgr2:="", variat:="")
			{
			bgr1 := colorBGR
			bgr2 := searchColorBGR
			variat := 5
			}
			if (ColVar = 1)
			{
				Return {x:x, y:y}
			}
		}

На большее ума не хватило.
Я так полагаю Display_CompareColors() возвращает "1" - подходит под сравнение, "0" - не подходит?
Вот так сравниваются colorBGR и searchColorBGR: "16777215 = 0x577AB9". Получается белый и коричневый. Причем colorBGR не в формате BGR.

50 (изменено: stealzy, 2017-04-11 21:20:21)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

ColVar := Display_CompareColors(bgr1:="", bgr2:="", variat:="")

- параметры вызываемой ф-ии равны ""?.

{
bgr1 := colorBGR
bgr2 := searchColorBGR
variat := 5
}

- сначала вызываете ф-ию с пустыми параметрами, а потом присваиваете переменным, которые больше не используете, новое значение?

Поиграйтесь:

MsgBox % f1(5, 2)
MsgBox % f2(3, 7, 2) " c вариацией 2"
MsgBox % f2(3, 5, 3) " c вариацией 3"
MsgBox % f2(2+3, 5)
qwert:=7, asdf:=8
MsgBox % f2(qwert, asdf:=101)
Return

f1(a, b) {
	if (a > b) {
		Return % a ">" b
	}
	Return % a "<" b
}

f2(a, b, c:=0) {
	if Compare(a, b, c) {
		Return a "~" b
	}
	Return a " даже близко !=" b
}

Compare(haha, hoho, вариация) {
	If (Abs(haha - hoho) <= вариация)
		Return true ; true синоним 1
	Return false ; синоним 0
}

51

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

stealzy пишет:

Также к недостаткам отнесу время работы вызываемой из Dll ф-ии GetPixel - 0.004 мс, что для FullHD дисплея выливается в 8 секунд

А заменить на lockbits не пробовали?

52 (изменено: stealzy, 2017-12-13 18:10:53)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Нет, видимо гораздо быстрее.

53

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Скажите, пожалуйста, предложенные методы поиска пикселя в неактивном окне работают при условии активности полноэкранной игры?

54

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

А кто вам мешает это проверить самому?

55

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Malcev, сложность редактирования и определения нужного мне примера. Возникло подозрение, что такое невозможно.

56 (изменено: Wraith, 2021-05-03 22:43:00)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Можно ли http://forum.script-coding.com/viewtopi … 77#p114477 использовать как PixelSearch? И как это сделать?

57

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

teadrinker Пытался сделать в любой другой программе кроме пеинта выдаёт 0x0 на всех цветах

58

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Achkosnik, если хотите получать ответы на этом форуме, выполняйте правила, исправьте свои сообщения.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

59 (изменено: svoboden, 2021-05-30 10:52:31)

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Eще пример для определения/смены текущего цвета в Paint в свернутом окне: https://reverseengineering.stackexchang … s-beginner. Можно перевести на ахк.

60

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

А это как связано с темой вопроса?

61

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Так вроде связанно. Это способ поиска цвета в программах, не только в Paint.

62

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

А как им можно найти цвет пикселя в заданных координатах?

63

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Этот вариант не определяет цвет пикселя в заданных координатах, но находит текущий цвет. Может, кому полезна будет такая информация.