1 (изменено: Vicoriyan, 2017-10-23 19:40:56)

Тема: AHK: ImageSearch без файла картинки

Может кто-то подумает, что ерундой страдаю, но вот мне интересно, можно ли осуществить такой алгоритм.

Скрипт делает скрин, сохраняет в виде картинки, выполняет действия и ждет, когда эта картинки исчезнет.

hwnd := WinExist("А")
SetBatchLines, -1
CoordMode, Pixel, Window
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromHWND(hwnd)
Gdip_GetDimensions(pBitmap, w, h)
pBitmap2 := Gdip_CropImage(pBitmap, 50, 110, 25, 30)
Gdip_SaveBitmapToFile(pBitmap2, "outScreen.png")
Sleep, 1000
CoordMode, Mouse, Window
ControlClick, x105 y305, ahk_class Qt5QWindowIcon,, Left, 1,  NA
Sleep, 1000
Loop
{
   ImageSearch, FoundX, FoundY, 0, 0, A_ScreenWidth, A_ScreenHeight, *15 outScreen.png
   If ErrorLevel
   {
      MsgBox картинка исчезла
      Break
   }
}
Gdip_CropImage(pBitmap, x, y, w, h)
{
   pBitmap2 := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmap2)
   Gdip_DrawImage(G2, pBitmap, 0, 0, w, h, x, y, w, h)
   Gdip_DeleteGraphics(G2)
   return pBitmap2
}
Gdip_DisposeImage(pBitmap), Gdip_DisposeImage(pBitmap2)
Gdip_Shutdown(pToken)

Может как-то по другому можно реализовать, но и так работает. У меня вопрос в другом, можно ли избавиться от физического сохранения картинки? Ведь скрин сохраняется в памяти и можно ведь как-то использовать это при поиске?
Или для этой цели ImageSearch не подходит?

2

Re: AHK: ImageSearch без файла картинки

ImageSearch не подходит.

3

Re: AHK: ImageSearch без файла картинки

Malcev А как тогда реализовать? Каким способом?

4 (изменено: Malcev, 2017-10-23 21:22:40)

Re: AHK: ImageSearch без файла картинки

Мы же с вами эту тему вдоль и поперек обсудили.
Если вы беретесь за довольно сложные коды с GDI+, то стоит почитать о том как он работает, а не просто спрашивать-копировать-вставлять.
Кстати, протестировал - из всех найденных мною Gdip Imagesearch, этот пока самый быстрый:

SetBatchLines -1
If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}
a:=a_tickcount
loop 20
   ImageSearch, FoundX, FoundY, 0,0, 1920, 1080, find.png
msgbox % a_tickcount - a


a:=a_tickcount
bmpHaystack := Gdip_BitmapFromScreen()
bmpNeedle := Gdip_CreateBitmapFromFile("find.png")
loop 20
   Gdip_ImageSearch(bmpHaystack, bmpNeedle, x, y)
msgbox % a_tickcount - a
Gdip_DisposeImage(bmpHaystack), Gdip_DisposeImage(bmpNeedle)
Gdip_Shutdown(pToken)




Gdip_ImageSearch(pBitmapHayStack, pBitmapNeedle, ByRef x, ByRef y, Variation=0, sx="", sy="", w="", h="")
{
	static _ImageSearch1, _ImageSearch2
	if !_ImageSearch1
	{
		MCode_ImageSearch1 := "83EC108B44242C9983E20303C28BC88B4424309983E20303C253C1F80255894424148B44244056C1F9023B44244C578944244"
		. "80F8DCA0000008B7C24348D148D000000000FAFC88B442444895424148B54242403C88D1C8A8B4C244C895C24183BC1894424407D7A895C24108D6424"
		. "008B6C2428C744243C000000008D6424008B44243C3B4424380F8D9400000033C985FF7E178BD58BF38B063B02752283C10183C20483C6043BCF7CED8"
		. "B44241C035C24148344243C0103C003C003E8EBC08B4424408B5C24108B4C244C83C00183C3043BC189442440895C24107C928B4424448B5424488B5C"
		. "2418035C241483C2013B54245089542448895C24180F8C5DFFFFFF8B5424548B4424585F5EC702FFFFFFFF5DC700FFFFFFFF83C8FF5B83C410C38B4C2"
		. "4548B5424408B4424585F89118B4C24445E5D890833C05B83C410C3"

		VarSetCapacity(_ImageSearch1, StrLen(MCode_ImageSearch1)//2)
		Loop % StrLen(MCode_ImageSearch1)//2		;%
			NumPut("0x" SubStr(MCode_ImageSearch1, (2*A_Index)-1, 2), _ImageSearch1, A_Index-1, "char")
	}

	if !_ImageSearch2
	{
		MCode_ImageSearch2 :="83EC1C8B4424443B44244C535556578944241C0F8D760100008B4C24488B5424580FAFC88B4424608B742440894C24188B4C24"
		. "503BCA894C24140F8D320100008B54241833FF897C24108B5C24103B5C2444897C2428895424240F8D4E01000085F6C7442420000000000F8ECD00000"
		. "08B7424348D148A8B4C243003F7897424548D1C0AEB0A8DA424000000008D49008B6C2454B9030000000FB60C19BE030000000FB6342E8D2C013BF50F"
		. "8FA20000002BC83BF10F8C980000008B4C24300FB64C0A028B7424340FB67437028D2C013BF57F7F2BC83BF17C798B4C24300FB64C0A018B7424340FB"
		. "67437018D2C013BF57F602BC83BF17C5A0FB60B8B7424540FB6368D2C013BF57F492BC83BF17C438B4C24208B742440834424540483C10183C20483C3"
		. "0483C7043BCE894C24200F8C5BFFFFFF8B4C24148B7C24288B542424035424488344241001037C244CE9F7FEFFFF8B4C24148B5424588B74244083C10"
		. "13BCA894C24140F8CD2FEFFFF8B4C24508B7C241C8B5C2448015C241883C7013B7C245C897C241C0F8CA5FEFFFF8B5424648B4424685F5EC702FFFFFF"
		. "FF5DC700FFFFFFFF83C8FF5B83C41CC38B5424648B4424685F890A8B4C24185E5D890833C05B83C41CC3"

		VarSetCapacity(_ImageSearch2, StrLen(MCode_ImageSearch2)//2)
		Loop % StrLen(MCode_ImageSearch2)//2		;%
			NumPut("0x" SubStr(MCode_ImageSearch2, (2*A_Index)-1, 2), _ImageSearch2, A_Index-1, "char")
	}
	
	if (Variation > 255 || Variation < 0)
		return -2

	Gdip_GetImageDimensions(pBitmapHayStack, hWidth, hHeight), Gdip_GetImageDimensions(pBitmapNeedle, nWidth, nHeight)
	
	if !(hWidth && hHeight && nWidth && nHeight)
		return -3
	if (nWidth > hWidth || nHeight > hHeight)
		return -4
	
	sx := (sx = "") ? 0 : sx
	sy := (sy = "") ? 0 : sy
	w := (w = "") ? hWidth-sx : w
	h := (h = "") ? hHeight-sy : h
	
	if (sx+w > hWidth-nWidth)
		w := hWidth-sx-nWidth+1
	
	if (sy+h > hHeight-nHeight)
		h := hHeight-sy-nHeight+1
		
	E1 := Gdip_LockBits(pBitmapHayStack, 0, 0, hWidth, hHeight, Stride1, Scan01, BitmapData1)
	E2 := Gdip_LockBits(pBitmapNeedle, 0, 0, nWidth, nHeight, Stride2, Scan02, BitmapData2)
	if (E1 || E2)
		return -5

	x := y := 0
	if (Variation = 0)
	{
		E := DllCall(&_ImageSearch1, "uint", Scan01, "uint", Scan02, "int", hWidth, "int", hHeight, "int", nWidth, "int", nHeight, "int", Stride1
		, "int", Stride2, "int", sx, "int", sy, "int", w, "int", h, "int*", x, "int*", y)
	}
	else
	{
		E := DllCall(&_ImageSearch2, "uint", Scan01, "uint", Scan02, "int", hWidth, "int", hHeight, "int", nWidth, "int", nHeight, "int", Stride1
		, "int", Stride2, "int", sx, "int", sy, "int", w, "int", h, "int", Variation, "int*", x, "int*", y)
	}
	Gdip_UnlockBits(pBitmapHayStack, BitmapData1), Gdip_UnlockBits(pBitmapNeedle, BitmapData2)
	return E ? E : -6
}

5

Re: AHK: ImageSearch без файла картинки

Malcev Все на английском и сложно понимать. Разбираюсь на примерах, на экспериментах и бывает на методах тыка.

6 (изменено: Malcev, 2017-10-24 00:56:25)

Re: AHK: ImageSearch без файла картинки

Нашел функции, быстрее чем подобная функция от Tic, более чем в полтора раза быстрее, чем ImageSearch.
И в несколько раз быстрее, чем финальная функция автора - (https://github.com/MasterFocus/AutoHotk … mageSearch)
Только для 32 бит.
https://github.com/MasterFocus/AutoHotk … mageSearch

SetBatchLines -1
pToken := Gdip_Startup()

pBitmapHayStack := Gdip_BitmapFromScreen()
pBitmapNeedle := Gdip_CreateBitmapFromFile("find.png")

start := A_TickCount
Gdip_FastImageSearch(pBitmapHayStack, pBitmapNeedle, x, y)
msgbox % x ", " y "`nвремя: " A_TickCount - start

start := A_TickCount
list := Gdip_ImageSearchList(pBitmapHayStack, pBitmapNeedle)
msgbox % list "`nвремя: " A_TickCount - start

Gdip_DisposeImage(pBitmapHayStack)
Gdip_DisposeImage(pBitmapNeedle)
Gdip_Shutdown(pToken)
return


;**********************************************************************************
;
; Gdip_FastImageSearch() - 08/MARCH/2013 21:00h BRT
; by MasterFocus, based on previous work by tic and Rseding91
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition exclusively for these users:
; - tic , Rseding91 , guest3456
;
;**********************************************************************************

;==================================================================================
;
; pBitmapHayStack
;   Use "Screen" or an already existing pBitmap
;   Default: "" (returns -1)
;
; pBitmapNeedle
;   A filename or an already existing pBitmap
;  Default: "" (returns -1)
;
; x and y
;   Variables to store the X and Y coordinates of the image if it's found
;   Default: "" for both
;
; sx1, sy1, sx2 and sy2
;   These can be used to crop the search area within the haystack
;   Default: "" for all (does not crop)
;
; Variation and Trans
;   Same as the builtin ImageSearch command (I guess we all know that)
;   Default: 0 for both
;
; w and h
;   Parameters used to resize the needle (-1 for one of those will mantain aspect ratio)
;   Default: 0 for both
;
; sd
;   Search direction:
;   0 = auto detect best direction [default]
;   1 = left->right, top->bottom ;; 2 = left->right, bottom->top
;   3 = right->left, bottom->top ;; 4 = right->left, top->bottom
;
; UseLastData
;   Tells the function to keep same haystack and/or needle data for future use
;   - If this is set and there is no previous data, the current data is used and saved
;   - If this is not set, any saved data is deleted/released/unlocked
;   0 or 0x00 = not set for the haystack and not set for the needle
;   1 or 0x01 = set for the haystack and not set for the needle
;   2 or 0x10 = not set for the haystack and set for the needle
;   3 or 0x11 = set for the haystack and set for the needle
;   (specially useful for multiple searches with the same haystack and/or needle)
;   Default: 0
;
; nWidth and nHeight
;   These can be used to store, out of the function, the width and height of the needle internally used
;   (retrieved from the resized needle, if w or h is set)
;   (specially useful for multiple searches with the same haystack and/or needle)
;==================================================================================

Gdip_FastImageSearch(pBitmapHayStack="",pBitmapNeedle="",ByRef x="",ByRef y="",sx1="",sy1="",sx2="",sy2=""
,Variation=0,Trans=0,w=0,h=0,sd=0,UseLastData=0,ByRef byref_nWidth="",ByRef byref_nHeight="")
{
    static _ImageSearch1, _ImageSearch2, _PixelAverage, Ptr, PtrA
    ; {MF} added some static stuff
	, hWidth, hHeight, Stride1, Scan01, BitmapData1, lastHaystack
    , Stride2, Scan02, BitmapData2, lastNeedle, nWidth, nHeight

    ; {MF} verify if we should use/keep data for the haystack and/or the needle
    UseLastHaystackData := !!(UseLastData & 0x01)
    UseLastNeedleData := !!(UseLastData & 0x10)

    ; {MF} delete/unlock/release all previous haystack data if it should not be used
	if !UseLastHaystackData
    {
	    Gdip_UnlockBits(lastHaystack, BitmapData1)
        hWidth := hHeight := Stride1 := Scan01 := BitmapData1 := ""
		Gdip_DisposeImage(lastHaystack)
        lastHaystack := ""
    }

    ; {MF} store the previous needle dimensions in the ByRef variables before possibly deleting the values
    byref_nWidth := nWidth, byref_nHeight := nHeight
    ; {MF} delete/unlock/release all previous needle data if it should not be used
	if !UseLastNeedleData
    {
	    Gdip_UnlockBits(lastNeedle, BitmapData2)
        nWidth := nHeight := Stride2 := Scan02 := BitmapData2 := ""
		Gdip_DisposeImage(lastNeedle)
        lastNeedle := ""
    }
    
    if !_ImageSearch1
    {
        Ptr := A_PtrSize ? "UPtr" : "UInt"
        , PtrA := A_PtrSize ? "UPtr*" : "UInt*"
        
        MCode_ImageSearch1 := "8B4C243483EC10803900538B5C2434555657750C80790100750680790200744B8B54243885D27E478B7C2430478BEA908B7424"
        . "3485F67E2C8BC78D9B000000008A50013A510275128A103A5101750B8A50FF3A117504C640020083C0044E75E08B54243803FB4D75C7EB048B5424388B"
        . "4424488944241C3B4424500F8D800200008B4C243C8BF90FAFF88D4402FF0FAFC1897C2418894424148DA424000000008B742444897424543B74244C0F"
        . "8D300200008B74245C83FE0175648B6C243033D2453B5424380F8D5402000033F6397424347E428B4C24548B5C242C8D0C8F8BC58D4C19018A58013A59"
        . "01750E8A183A1975088A58FF3A59FF740A807802000F85B60100004683C10483C0043B7424347CD38B5C2440037C243C4203EBEBA383FE020F85860000"
        . "008BF88BC14A8BCBF7D8F7D98BF20FAFF38B5C243089442410894C24488D6C1E01EB068D9B0000000083FAFF0F8EC701000033F6397424347E468B4C24"
        . "548B5C242C8D0C8F8BC58D4C19018A58013A5901750E8A183A1975088A58FF3A59FF740A807802000F85290100004683C10483C0043B7424347CD38B44"
        . "24108B4C244803F84A03E9EBA283FE030F85840000004A8BFAF7D90FAFFB8BF3F7DE8BE8894C2410897424488D490083FAFF0F8E470100008B44243448"
        . "83F8FF7E518B7424308B5C242C8D0C878D4C31018B74245403F08D74B5008D741E018A59013A5E01750E8A193A1E75088A59FF3A5EFF740A807902000F"
        . "859B0000004883EE0483E90483F8FF7FD48B7424488B4C241003E94A03FEEB9583FE040F85DC00000033ED896C24488D9B00000000395424480F8DC600"
        . "00008B4424344883F8FF7E4D8B4C24308B74242C8D5485008D4C0A018B54245403D08D14978D7432018A51013A5601750E8A113A1675088A51FF3A56FF"
        . "74068079020075224883EE0483E90483F8FF7FD88B5424388B4C243CFF44244803F903EBEB958B5C24408B4424548B7C24188B5424388B4C243C403B44"
        . "244C894424548B4424140F8CD0FDFFFF8B74241C4603C103F98974241C89442414897C24183B7424500F8C9FFDFFFF8B4C24248B5424285F5E5DC701FF"
        . "FFFFFFC702FFFFFFFF83C8FF5B83C410C38B4424248B4C24548B5424285F89088B4424185E5D890233C05B83C410C3"
        
        MCode_ImageSearch2 := "8B4C24348B54241883EC2C803900538B5C2450555657750C80790100750680790200744E8B6C244C85D27E4A8D7D0189542470"
        . "8B74245085F67E298BC78D49008A50013A510275128A103A5101750B8A50FF3A117504C640020083C0044E75E08B6C244C03FBFF4C247075C78B542454"
        . "EB048B6C244C8B442464894424183B44246C0F8D0C0400008B7C24588B74247C8BCF0FAFC8894C24148B8C248000000003C88D4402FF0FAFCF0FAFC789"
        . "4424108B442474894C2430EB068D9B000000008B4C2460894C24643B4C24680F8DA40300008BD30FAF94248000000003D58D0CB20FB611894C24348B4C"
        . "246003CE8B7424308D0C8E034C244889542438894C242CEB048B4C242C0FB6098D34013BD67F062BC83BD17D0E8B4C2434807903000F85350300008B4C"
        . "247883F9010F85AD0000008B742414C7442470000000008D4D018B542470894C2424897424283B5424540F8D5C03000033ED396C24507E698B5424648D"
        . "14968B7424488D7432018BFF0FB656010FB679018D1C023BFB7F2E2BD03BFA7C280FB6160FB6398D1C023BFB7F1B2BD03BFA7C150FB656FF0FB679FF8D"
        . "1C023BFB7F062BD03BFA7D0A807902000F85930200004583C60483C1043B6C24507CAC8B5C245C8B7424288B4C242403742458FF44247003CBE962FFFF"
        . "FF83F9020F85C60000008B5424108B4C2454498954241C8BD78BF3F7DAF7DE8BF90FAFFB8D7C2F018954242889742424897C2420894C247083F9FF0F8E"
        . "9402000033ED396C24507E798B74241C8B5424648B4C24208D14968B7424488D7432018BFF0FB656010FB679018D1C023BFB7F2E2BD03BFA7C280FB616"
        . "0FB6398D1C023BFB7F1B2BD03BFA7C150FB656FF0FB679FF8D1C023BFB7F062BD03BFA7D0A807902000F85C30100004583C60483C1043B6C24507CAC8B"
        . "7424248B5424288B4C24700154241C4901742420E964FFFFFF83F9030F85D80000008B5424548B4C24104A894C24208BF78BCAF7DE0FAFCB8BFBF7DF89"
        . "742428897C2424894C241C8954247083FAFF0F8EC90100008B6C24504D83FDFF0F8E8B0000008B7424208D14A98B4C244C8D4C0A018B54246403D58D14"
        . "968B7424488D543201EB068D9B000000000FB672010FB679018D1C063BFB7F2E2BF03BFE7C280FB6320FB6398D1C063BFB7F1B2BF03BFE7C150FB672FF"
        . "0FB679FF8D1C063BFB7F062BF03BFE7D0A807902000F85E30000004D83EA0483E90483FDFF7FAD8B7C24248B7424288B4C241C8B542470017424204A03"
        . "CFE94AFFFFFF83F9040F851B0100008B74241433C9894C2470894C24288B4C2470897424243B4C24540F8DFB0000008B6C24504D83FDFF7E738B542428"
        . "8D0CAA8B54244C8D4C11018B54246403D58D14968B7424488D5432010FB672010FB679018D1C063BFB7F2E2BF03BFE7C280FB6320FB6398D1C063BFB7F"
        . "1B2BF03BFE7C150FB672FF0FB679FF8D1C063BFB7F062BF03BFE7D068079020075254D83EA0483E90483FDFF7FB18B5C245C8B74242403742458FF4424"
        . "70015C2428E95CFFFFFF8B5C245C8B6C244C8B7C24588B5424388B4C24648344242C0441894C24643B4C24680F8C91FCFFFF8B74247CFF4424188B4C24"
        . "18017C2410017C2414017C24303B4C246C0F8C2CFCFFFF8B4424408B4C24445F5EC700FFFFFFFF5DC701FFFFFFFF83C8FF5B83C42CC38B5424408B4424"
        . "648B4C24445F89028B5424145E5D891133C05B83C42CC3"
        
        MCode_PixelAverage := "83EC488B4C24608B54246433C0890189028944243C894424388B44245453992BC2558B6C246456578BF88B442468992BC28B54"
        . "24688D5D148D73148D4E14D1FF897E04D1F8894104894308897E088951088B542464897D0C89430C89560C8B54246889510C8B542464897D1089561089"
        . "41108BC52BD92BC18BFE8D51042BF9C74424340100000089542410895C24408944242C897C2430EB178DA424000000008B5424108B5C24408B44242C8B"
        . "7C24308B328B0C1333ED896C2468896C2464896C246C897424443BCE0F8D030100008B0410894424148B0417894424188BC10FAF4424602BF189442438"
        . "8974243C8BFF8B7424148B4C241833DB33FF896C241C896C2420896C2424896C24283BF10F8DA00000002BCE83F9027C538B54245C8D0CB08D4C11018B"
        . "5424182BD683EA02D1EA428D34560FB6410103F80FB60103D80FB641FF0144241C0FB64105014424280FB64104014424240FB641030144242083C1084A"
        . "75CF8B4424388B54241033ED3B7424187D1E8D0CB0034C245C0FB67102017424680FB671010FB60901742464014C246C8B4C24248B7424200374241C03"
        . "CB014C24648B4C24280174246C03CF014C246803442460FF4C243C894424380F852AFFFFFF8B5C24408B44242C8B7C24308B34138B3C172B3C108B0A8B"
        . "4424682BCE0FAFCF33D2F7F133D2896C24688BF88B442464F7F133D28BD88B44246CF7F18D57198954246C8D4B1983C7E783C3E7897C243C894C243889"
        . "5C24288D50198954242483C0E733D2894424203B7424440F8DAE0000008B4424108B4C242C8B0C01894C24148B4C24308B1C018BC60FAF442460895C24"
        . "1C894424648D49008B7C24143BFB7D6B8B4C245C8D04B88D4C080280790100744A0FB6018BDA3B44246C7D063B44243C7F01420FB641FF3B4424387D06"
        . "3B4424287F01420FB641FE3B4424247D063B4424207F01428BC22BC33B4424687E0C897C245089742454894424688B5C241C4783C1043BFB7CA48B4424"
        . "640344246046894424643B7424440F8C7AFFFFFF3B5424487E208B4424708B4C2450895424488B54243489088B4424548954244C8B54247489028B4424"
        . "348344241004408944243483F8050F8C7DFDFFFF8B44244C5F5E5D5B83C448C3"
        
        VarSetCapacity(_ImageSearch1, StrLen(MCode_ImageSearch1)//2, 0)
        Loop % StrLen(MCode_ImageSearch1)//2      ;%
            NumPut("0x" . SubStr(MCode_ImageSearch1, (2*A_Index)-1, 2), _ImageSearch1, A_Index-1, "uchar")
        MCode_ImageSearch1 := ""
        
        VarSetCapacity(_ImageSearch2, 1233, 0)
        Loop % StrLen(MCode_ImageSearch2)//2      ;%
            NumPut("0x" . SubStr(MCode_ImageSearch2, (2*A_Index)-1, 2), _ImageSearch2, A_Index-1, "uchar")
        MCode_ImageSearch2 := ""
        
        VarSetCapacity(_PixelAverage, StrLen(MCode_PixelAverage)//2, 0)
        Loop % StrLen(MCode_PixelAverage)//2      ;%
            NumPut("0x" . SubStr(MCode_PixelAverage, (2*A_Index)-1, 2), _PixelAverage, A_Index-1, "uchar")
        MCode_PixelAverage := ""
        
        , DllCall("VirtualProtect", Ptr, &_ImageSearch1, Ptr, VarSetCapacity(_ImageSearch1), "uint", 0x40, PtrA, 0)
        , DllCall("VirtualProtect", Ptr, &_ImageSearch2, Ptr, VarSetCapacity(_ImageSearch2), "uint", 0x40, PtrA, 0)
        , DllCall("VirtualProtect", Ptr, &_PixelAverage, Ptr, VarSetCapacity(_PixelAverage), "uint", 0x40, PtrA, 0)
    }
    
    If ( UseLastHaystackData && lastHaystack ) ; {MF] if there IS a previous haystack, it's ok to use it
        pBitmapHayStack := lastHaystack
    Else {
        ;Alows the MCode to be setup before imagesearch is really needed
        if (pBitmapHayStack = "")
            return -1
        if (pBitmapHayStack = "Screen") {
            Dump_Haystack := !UseLastHaystackData ; {MF} also, only dump if we're not saving/reusing it
            pBitmapHayStack := Gdip_BitmapFromScreen()
        }
    }
    lastHaystack := pBitmapHayStack ; {MF] save the current haystack (even if it's the same, won't hurt)
    
    If ( UseLastNeedleData && lastNeedle ) ; {MF] if there IS a previous needle, it's ok to use it
        pBitmapNeedle := lastNeedle
    Else {
        if (pBitmapNeedle = "")
            return -1
        if (FileExist(pBitmapNeedle)) {
            ;Load the image from the HD
            Dump_Needle := !UseLastNeedleData ; {MF} also, only dump if we're not saving/reusing it
            pBitmapNeedle := Gdip_CreateBitmapFromFile(pBitmapNeedle)
        }
    }
    lastNeedle := pBitmapNeedle ; {MF] save the current needle (even if it's the same, won't hurt)
    
    if (Variation > 255 || Variation < 0)
        return -2
    
    ; {MF} retrieve the haystack dimensions if we don't wanna use the saved data OR this information is not saved yet
    ; {MF} (this if-statement may not be necessary, I still have to test it)
	if ( !UseLastHaystackData || !hWidth )
        Gdip_GetImageDimensions(pBitmapHayStack, hWidth, hHeight)
    ; {MF} retrieve the needle dimensions if we don't wanna use the saved data OR this information is not saved yet
    ; {MF} (this if-statement may not be necessary, I still have to test it)
	if ( !UseLastNeedleData || !nWidth )
    {
        Gdip_GetImageDimensions(pBitmapNeedle, nWidth, nHeight)
        byref_nWidth := nWidth, byref_nHeight := nHeight ; {MF} replicate the dimensions to the ByRef parameters
    }
    
    if !(hWidth && hHeight && nWidth && nHeight)
        return -3
    if (nWidth > hWidth || nHeight > hHeight)
        return -4
    
    ;Sets/corrects resize variables
    w := (w < -1) ? 0 : w
    , h := (h < -1) ? 0 : h
    
    ;Resizes the needle image if w/h are set
    ;What a pain...
    if (w || h){
        ;Creates a resized needle image and set pBitmapNeedle to the bitmap
        if (w = -1)
            sH := h, sW := nWidth / nHeight, sW := Round(sH * sW)
        else if (h = -1)
            sW := w, sH := nHeight / nWidth, sH := Round(sW * sH)
        else
            sW := w, sH := h
        
        pTempBitmap := Gdip_CreateBitmap(sW, sH)
        , pG := Gdip_GraphicsFromImage(pTempBitmap)

        , Gdip_SetInterpolationMode(pG, 7)
        , Gdip_DrawImage(pG, pBitmapNeedle, 0, 0, sW, sH, 0, 0, nWidth, nHeight)
        , Gdip_DeleteGraphics(pG)
        
        , pBitmapNeedle := pTempBitmap
        , Gdip_GetImageDimensions(pBitmapNeedle, nWidth, nHeight)
        , byref_nWidth := nWidth, byref_nHeight := nHeight ; ADICIONADO (adicinada) esta linha
        
        if !(nWidth && nHeight){
            Gdip_DisposeImage(pBitmapNeedle)
            if (Dump_HayStack)
                Gdip_DisposeImage(pBitmapHayStack)
            return -5
        }
        if (nWidth > hWidth || nHeight > hHeight){
            Gdip_DisposeImage(pBitmapNeedle)
            if (Dump_HayStack)
                Gdip_DisposeImage(pBitmapHayStack)
            return -6
        }
    }
    
    ;Sets/corrects search box and needle scan direction
    sx1 := (sx1 = "") ? 0 : sx1
    , sy1 := (sy1 = "") ? 0 : sy1
    , sx2 := (sx2 = "") ? hWidth : (sx2 - nWidth + 1)
    , sy2 := (sy2 = "") ? hHeight : (sy2 - nHeight + 1)
    , sd := (sd < 0 || sd > 4) ? 1 : sd
    
    if (sx1 < 0 || sy1 < 0){
        if (w || h || Dump_Needle)
            Gdip_DisposeImage(pBitmapNeedle)
        if (Dump_HayStack)
            Gdip_DisposeImage(pBitmapHayStack)
        return -7
    }
    
    ;Detects too small search boxes
    if ((sx2 - sx1) < 1 || (sy2 - sy1) < 1){
        if (w || h || Dump_Needle)
            Gdip_DisposeImage(pBitmapNeedle)
        if (Dump_HayStack)
            Gdip_DisposeImage(pBitmapHayStack)
        return -8
    }
    
    ;Prevents searching to close to the edges: it can't match 20 pixels in a 19 pixel search area
    if (sx2 > (hWidth - nWidth + 1))
        sx2 := (hWidth - nWidth) + 1
    if (sy2 > (hHeight - nHeight + 1))
        sy2 := (hHeight - nHeight) + 1
    
    ;Detects invalid search boxes
    if (sx2 < sx1 || sy2 < sy1){
        if (w || h || Dump_Needle)
            Gdip_DisposeImage(pBitmapNeedle)
        if (Dump_HayStack)
            Gdip_DisposeImage(pBitmapHayStack)
        return -9
    }
    
    ; {MF} the following should be faster than 2 if-statements
    sx2 += !sx2
    sy2 += !sy2
    
    ;If Trans is used and the needle hasen't already been copied through scaling or loading
    ;create a copy because it might be modified by the imagesearch code
    ; {MF} we can only do that if we're not using saved data!
    if ( (!w && !h && Trans && !Dump_Needle) && !UseLastNeedleData )
        pBitmapNeedle := Gdip_CloneBitmapArea(pBitmapNeedle, 0, 0, nWidth, nHeight)        
    
    ;Stride2/Scan02/BitmapData2 are used because the needle is the second image eventhough it's used first
    ; {MF} lock the bits if we don't wanna use the saved data OR the bits are not locked yet
	if (!UseLastNeedleData || !BitmapData2)
    {
        if Gdip_LockBits(pBitmapNeedle, 0, 0, nWidth, nHeight, Stride2, Scan02, BitmapData2) {
            if (w || h || Trans || Dump_Needle)
                Gdip_DisposeImage(pBitmapNeedle)
            if (Dump_HayStack)
                Gdip_DisposeImage(pBitmapHayStack)
            return -12
        }
    }
    
    ;Averages the needle in 4 chunks counting the number of pixels(R, G & B) that arn't +- 25 of the average color
    ;and sets the search code to scan that corner first when matching the image
    ;Also sets a "Check this pixel first" location for the haystack instead of always starting at the corner of the image (0/0, w/h, ...)
    if (sd = 0 And nWidth >= 20 And nHeight >= 20){
        VarSetCapacity(TempData, 5*4*4, 0) ;5 entires at 4 entires each at 4 bytes each
        , sd := DllCall(&_PixelAverage, Ptr, Scan02, "Int", Stride2, "Int", nWidth, "Int", nHeight, Ptr, &TempData
        , "UInt*", suX, "UInt*", suY, "cdecl int")
        , VarSetCapacity(TempData, 0)
    } else
        sd += !sd ; {MF} this should be faster than an if-statement
    
    ;Sets the default search-first location for variation searches if none was set yet
    suX := (suX = "" || suX = -1) ? 0 : suX
    , suY := (suY = "" || suY = -1) ? 0 : suY
    
    ; {MF} lock the bits if we don't wanna use the saved data OR the bits are not locked yet
	if (!UseLastHaystackData || !BitmapData1)
        if (Gdip_LockBits(pBitmapHayStack, 0, 0, hWidth, hHeight, Stride1, Scan01, BitmapData1)){
            if (w || h || Trans || Dump_Needle)
                Gdip_DisposeImage(pBitmapNeedle)
            if (Dump_HayStack)
                Gdip_DisposeImage(pBitmapHayStack)
            return -12
        }
    
    ;The dllcall parameters are the same for easier C code modification even though they arn't all used on the _ImageSearch1 version
    x := 0, y := 0
    , E := DllCall((Variation = 0 ? &_ImageSearch1 : &_ImageSearch2), "int*", x, "int*", y, Ptr, Scan01, Ptr, Scan02, "int", nWidth
    , "int", nHeight, "int", Stride1, "int", Stride2, "int", sx1, "int", sy1, "int", sx2, "int", sy2, Ptr, &Trans, "int", Variation
    , "int", sd, "int", suX, "int", suY, "cdecl int")

    ; {MF} delete/unlock/release all current haystack data (except the bitmap itself) if it should not be saved
    if !UseLastHaystackData
    {
        Gdip_UnlockBits(pBitmapHayStack, BitmapData1)
        hWidth := hHeight := Stride1 := Scan01 := BitmapData1 := ""
        lastHaystack := ""
    }
    ; {MF} delete/unlock/release all current needle data (except the bitmap itself) if it should not be saved
    if !UseLastNeedleData
    {
        Gdip_UnlockBits(pBitmapNeedle, BitmapData2)
        Stride2 := Scan02 := BitmapData2 := nWidth := nHeight := ""
        lastNeedle := ""
    }
    
    if ( w || h || Trans || Dump_Needle )
        Gdip_DisposeImage(pBitmapNeedle)
    
    if ( Dump_HayStack )
        Gdip_DisposeImage(pBitmapHayStack)
    
    return (E = "") ? -13 : E
}

;**********************************************************************************
;
; Gdip_ImageSearchList() by MasterFocus - 08/MARCH/2013 18:45h BRT
; Requires Gdip_FastImageSearch() by MasterFocus
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition exclusively for these users:
; - tic , Rseding91 , guest3456
;
;**********************************************************************************



Gdip_ImageSearchList(Haystack="Screen",Needle="",KEEP=0x11) {
;-----------------------------------------
    OuterX1 := OuterY1 := 0
    OuterX2 := A_ScreenWidth
    OuterY2 := A_ScreenHeight
    VARI := TRANS := W := H := 0
    DIR := 1
    LineDelim := "`n"
    CoordDelim := ","
;-----------------------------------------
    InnerX1 := OuterX1
    InnerY1 := OuterY1
    InnerX2 := OuterX2
    InnerY2 := OuterY2
    While !Gdip_FastImageSearch(Haystack,Needle,FoundX,FoundY,OuterX1,OuterY1,OuterX2,OuterY2,VARI,TRANS,W,H,DIR,KEEP,NeedleWidth,NeedleHeight)
    {
        OuterY1 := FoundY+1
        OutputList .= LineDelim FoundX CoordDelim FoundY
        InnerX1 := FoundX+1
        InnerY1 := FoundY
        InnerY2 := InnerY1+NeedleHeight
        While !Gdip_FastImageSearch(Haystack,Needle,FoundX,FoundY,InnerX1,InnerY1,InnerX2,InnerY2,VARI,TRANS,W,H,DIR,KEEP)
        {
            OutputList .= LineDelim FoundX CoordDelim FoundY
            InnerX1 := FoundX+1
        }
    }
    Gdip_FastImageSearch()
    Return SubStr(OutputList,1+StrLen(LineDelim))
}

7

Re: AHK: ImageSearch без файла картинки

Кстати, поделка от Rseding91, упомянутого в примере выше, позволяет сделать каталог файлов заранее вписанных в код, который можно оформить как подключаемая через "#Include" библиотека и производить сканирование по дескрипторам вписанных таким образом файлов. Это может делать как стандартный способ:


ImageSearch,xx,yy,x,y,w,h,% "*10 *Trans000000 HBITMAP:*" file_desc
if (ErrorLevel == 0) {
	...	; Выполнить код
}

Так и посредством "Gdip_ImageSearch()":


needlePointer := Gdip_CreateBitmapFromHBITMAP(file_desc)

И передавать его в функцию вторым параметром.

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

8

Re: AHK: ImageSearch без файла картинки

О, а я пропустил это нововведение , что можно в ImageSearch искать HBITMAP.
Vicoriyan, тогда можно:

SetBatchLines, -1
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen()
Gdip_GetDimensions(pBitmap, w, h)
pBitmap2 := Gdip_CropImage(pBitmap, 50, 110, 25, 30)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap2)
Loop
{
   ImageSearch, FoundX, FoundY, 0, 0, A_ScreenWidth, A_ScreenHeight, HBITMAP:*%hBitmap%
   If ErrorLevel
   {
      MsgBox картинка исчезла
      Break
   }
   msgbox % foundx
}
Gdip_DisposeImage(pBitmap), Gdip_DisposeImage(pBitmap2)
DeleteObject(hBitmap)
Gdip_Shutdown(pToken)
return

Gdip_CropImage(pBitmap, x, y, w, h)
{
   pBitmap2 := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmap2)
   Gdip_DrawImage(G2, pBitmap, 0, 0, w, h, x, y, w, h)
   Gdip_DeleteGraphics(G2)
   return pBitmap2
}

9 (изменено: Vicoriyan, 2018-04-14 21:57:54)

Re: AHK: ImageSearch без файла картинки

А можно избавиться от физического файла в этом коде? Например зашифровать в BASE64.
Как шифровать и создавать переменные я знаю, но как это применить в данном случаи?

Сам код:

#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk

LIST := ""
SetBatchLines, -1
CoordMode, Pixel, Window
hwnd := WinExist("A")
lock := ["1", "2", "3", "4", "5", "6"]
gdipToken := Gdip_Startup()
bmpHaystack := Gdip_BitmapFromHWND(hwnd)
loop % lock.Length()
{
   bmpNeedle := Gdip_CreateBitmapFromFile(lock[A_Index]".png")
   RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,LIST,0,0,0,0,0,0xFFFFFF,1,1)
   Gdip_DisposeImage(bmpNeedle)
   CoordMode, Mouse, Window
   Loop, Parse, LIST, `n
   {
      StringSplit, Coord, A_LoopField, `,
      MouseClick, , %Coord1%, %Coord2%, 1 , 0.5
        break 2
   }
}
Gdip_DisposeImage(bmpHaystack)
Gdip_Shutdown(gdipToken)
Return

10

Re: AHK: ImageSearch без файла картинки

Передайте хендл на загруженный в память файл:

bmpNeedle := Gdip_CreateBitmapFromHBITMAP(HWND)

11

Re: AHK: ImageSearch без файла картинки

KusochekDobra Спасибо, что ответили по моему вопросу. Но как мне вставить сами картинки зашифрованных в BASE64?

12

Re: AHK: ImageSearch без файла картинки

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

13

Re: AHK: ImageSearch без файла картинки

Пробовал, но не получается. Все делал по инструкции.

14

Re: AHK: ImageSearch без файла картинки

Я сейчас в огород, потом по делам. Если никто не поможет за это время, то отвечу самое позднее завтра, примерно в это же время.

15 (изменено: KusochekDobra, 2018-04-16 03:28:29)

Re: AHK: ImageSearch без файла картинки

Небольшая солянка из забугорных поделок, с которыми можно ознакомиться по ссылкам из секции "Credits":


; ======================================================================================================================
; Credits:			Bitmap creation is based on "How to convert Image data (JPEG/PNG/GIF) to hBITMAP?" by SKAN ->
;					http://www.autohotkey.com/board/topic/21213-how-to-convert-image-data-jpegpnggif-to-hbitmap/?p=139257
;					Подробный пример получения RCData при упаковке 'FileInstall' от Just Me
;					https://autohotkey.com/boards/viewtopic.php?f=11&t=2101&hilit=RCDATA
;					Image2Include - запись изображения строкой от Just Me
;					https://autohotkey.com/board/topic/93292-image2include-include-images-in-your-scripts/
;					Include virtually any file in a script (exe/zip/dll/etc....) от Rseding91
;					https://autohotkey.com/board/topic/64481-include-virtually-any-file-in-a-script-exezipdlletc/
; ======================================================================================================================
; This software is provided 'as-is', without any express or implied warranty.
; In no event will the authors be held liable for any damages arising from the use of this software.
; ======================================================================================================================
SetBatchLines -1
#NoEnv
#SingleInstance, Force

	GoSub, Start
; ----------------------------------------------------------------------------------------------------------------------
	Global insertedItems
	bttn_w := 120, bttn_h := 45
; ======================================================================================================================
; нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн
; ======================================================================================================================
Menu Tray, Icon, shell32.dll, 190
Gui,+OwnDialogs +HWNDmain_h
Gui,1: Margin, 10, 10
Gui,1: Add, CheckBox,vtoMemory +Checked,Для загрузки в память и получения указателя
Gui,1: Add, CheckBox,xm y+5 vtoRestore,С возможностью восстановления
Gui,1: Add, Button, gConvert xm y+10 w%bttn_w% h%bttn_h%,В файл
Gui,1: Add, Button, gCopy_Clip x+30 w%bttn_w% h%bttn_h%,В буфер

Gui,1: Font, s42 w600 
Gui,1: Add, Text, x+30 yp-5 w170 h105 +0x801000 +0x200 vfileCounter Center,0
Gui,1: Font

Gui,1: Add, Button, gRestartWork xm yp+55 w%bttn_w% h%bttn_h%,Новый
Gui,1: Add, Button, gShow x+30 w%bttn_w% h%bttn_h%,Посмотреть код
Gui,1: Add, StatusBar
Gui,1: Show,,File-Converter/Lib-Creator

Gui, Script: +Owner1
Gui, Script: Margin, 5, 5
Gui, Script: Font, , Courier New
Gui, Script: Add, Edit, x0 y0 w0 h0
Gui, Script: Add, Edit, % "x0 y0 w" . Round(A_ScreenWidth * 0.8) . " h" . Round(A_ScreenHeight * 0.8)
                      . " vScriptEdit +hwndHEdit +HScroll"
Gui, Script: Add, StatusBar
; ======================================================================================================================
	Gosub, RestartWork
; ======================================================================================================================
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiClose:
	ExitApp
; ----------------------------------------------------------------------------------------------------------------------
ScriptGuiEscape:
	Gui,Script: Show, Hide
return
RestartWork:
		GuiControl,Enable,toMemory
		GuiControl,Enable,toRestore
	outFileName := "", insertedItems := []
	memTmp := "", resTmp := ""
	textFile := "", varInitText := "", ttlFile := 0
	GuiControl,Text,fileCounter,0
	SB_SetText("Перетащите файлы на это окно.")
return
; ----------------------------------------------------------------------------------------------------------------------
Begin:
	; -------------------------------------------------------------------------------------------------------------------
	;  Чтение изображения
	; -------------------------------------------------------------------------------------------------------------------
	File := FileOpen(ImgFile, "r")
	BinLen := File.Length
	File.RawRead(Bin, BinLen)
	File.Close()
	; -------------------------------------------------------------------------------------------------------------------
	;  Размер файла
	; -------------------------------------------------------------------------------------------------------------------
	Ptr := A_IsUnicode ? "Ptr" : "UInt"
	, H := DllCall("CreateFile", Ptr, &ImgFile, "UInt", 0x80000000, "UInt", 3, "UInt", 0, "UInt", 3, "UInt", 0, "UInt", 0)
	, VarSetCapacity(FileSize, 8, 0)
	, DllCall("GetFileSizeEx", Ptr, H, "Int64*", FileSize)
	, DllCall("CloseHandle", Ptr, H)
	; -------------------------------------------------------------------------------------------------------------------
	; Преобразование в текст
	; -------------------------------------------------------------------------------------------------------------------
	DllCall("Crypt32.dll\CryptBinaryToString", "Ptr", &Bin, "UInt", BinLen, "UInt", 0x01, "Ptr", 0, "UIntP", B64Len)
	VarSetCapacity(B64, B64Len << !!A_IsUnicode, 0)
	DllCall("Crypt32.dll\CryptBinaryToString", "Ptr", &Bin, "UInt", BinLen, "UInt", 0x01, "Ptr", &B64, "UIntP", B64Len)
	Bin := ""
	VarSetCapacity(Bin, 0)
	VarSetCapacity(B64, -1)
	B64 := RegExReplace(B64, "\r\n")
	B64Len := StrLen(B64)
	; -------------------------------------------------------------------------------------------------------------------
	;  Запись в скрипт
	; -------------------------------------------------------------------------------------------------------------------
	PartLength := 16000
	CharsRead  := 1, Part := "`tB64 := """
	if (!toRestore)
		varInitText.= Format("; -> {1}_{2} := Retrieve_{1}_{2}()`r`n",name,ext)
	else
		varInitText.= Format("; -> {1}_{2} := Retrieve_{1}_{2}(""{1}.{2}"")`r`n",name,ext)
	
	textFile.="Retrieve_" name "_" ext "(_Filename := 0, _DumpData := 0, NewHandle := False) {`r`n"
	textFile.="`tStatic hBitmap := 0, HasData := 1, Out_Data, Ptr, ExtractedData`r`n"
	if (toMemory)
		textFile.= Header "`r`n"
	textFile.="`tVarSetCapacity(B64, " StrLen(B64) " << !!A_IsUnicode)`r`n"
	While (CharsRead < B64Len) {
		textFile.=Part SubStr(B64, CharsRead, PartLength) """`r`n"
		CharsRead += PartLength
		If (CharsRead < B64Len)
			Part := "`tB64 .= """
	}
	if (toRestore)
		textFile .= Format(restoreBody, Ceil(FileSize * 1.37), FileSize)
	
	if (toMemory) {
		textFile .= "`tif !(hBitmap)`r`n"
		If (ext == "ico")
			textFile.="`t`thBitmap := H_Func(B64,1) `r`n"
		Else
			textFile.="`t`thBitmap := H_Func(B64) `r`n"
		textFile .= "`treturn hBitmap`r`n}`r`n"
	} else
		textFile .="}`r`n"
	
	SB_SetText(" >>> " name "." ext " >>> добавлен в сценарий.")
return
Convert:
	if (varInitText) {
		resultStr:= Format("{1}`r`n`r`n{2}`r`n{3}", varInitText, textFile, toMemory ? H_Func : "")
		File := FileOpen(outFileName, "w", "UTF-8")
		File.Write(resultStr)
		File.Close()
		SB_SetText("Файл -> " . outFileName . " >>> Создан")
	} else
		SB_SetText("Преобразование невозможно. Начальные компоненты сценария не заданы.")
Return
Copy_Clip:
	if (varInitText) {
		ClipBoard := Format("{1}`r`n{2}{3}", varInitText, textFile, toMemory ? H_Func : "")
		SB_SetText("Сценарий ->  >>> Скопирован в буфер")
	} else
		SB_SetText("Копирование невозможно. Начальные компоненты сценария не заданы.")
return
; ======================================================================================================================
;  Демонстрация сгенерированного кода
; ======================================================================================================================
Show:
	if (varInitText) {
		Gui,1: Submit, Nohide
		tmpText := textFile
		resultStr := Format("{1}`r`n{2}{3}",varInitText,tmpText, toMemory ? H_Func : "")
		If (resultStr) {
			Size := StrLen(resultStr)
			Gui, Script: Default
			GuiControl, Text, ScriptEdit,% resultStr
			ControlGet, Lines, LineCount, , , ahk_id %HEDIT%
			SB_SetText("  Длина: " . Size . " символов. Строк: " . Lines)
			Gui,Script: Show,,%outFileName%
		}
	} else
		SB_SetText("Не на что смотреть. Начальные компоненты сценария не заданы.")
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiDropFiles:
	Gui,1: Submit, Nohide
	if (!toMemory && !toRestore) {
		MsgBox,,Отмена,Преобразование не имеет смысла, поскольку производится без цели.`nОтметьте хотя бы один чекбокс.
		return
	} if (!varInitText) {
		GuiControl,Disable,toMemory
		GuiControl,Disable,toRestore
	}
	SplitPath, A_GuiEvent, fullName, OutDir, ext, name
	forWrite := []
	if (A_EventInfo > 1) {					;  Если дропнуло больше одного файла/папки
		allItems := []
		allItems := StrSplit(A_GuiEvent,"`n")
		Loop,% allItems.Length() {
			nextItem := allItems[A_Index]
			SplitPath, nextItem, fullName, OutDir, ext, name
			if (ext == "") {					; Папка
				Loop,% nextItem "\*.*",,1
					if (CheckItem(A_LoopFileFullPath))
						forWrite.Push(A_LoopFileFullPath)
			} else if (CheckItem(nextItem))
				forWrite.Push(nextItem)
		}
	} else {
		if (ext == "") {						; Папка
			Loop,% A_GuiEvent "\*.*",,1
				if (CheckItem(A_LoopFileFullPath))
					forWrite.Push(A_LoopFileFullPath)
		} else if (CheckItem(A_GuiEvent))
			forWrite.Push(A_GuiEvent)
	} if (forWrite.Length()) {
		GoSub, DoInsert
		SB_SetText("Запись завершена.")
	} else
		SB_SetText("Элементы на запись не поступали.")
return
DoInsert:
	Loop,% forWrite.Length() {
		ImgFile := forWrite[A_Index]
		SplitPath,ImgFile,fullName,OutDir,ext,name
		name := StrReplace(name, A_Space, "_")
		
		if (!outFileName)
			outFileName :=% A_ScriptDir "\Retrieve_" name "_" ext ".ahk"
		ttlFile++
		GoSub, Begin
		GuiControl,Text,fileCounter,% ttlFile
	}
return
CheckItem(item) {
	Loop,% insertedItems.Length() {
		inserted := insertedItems[A_Index]
		SplitPath,item,fullItemName
		SplitPath,inserted,fullInsertedName
		if (fullInsertedName == fullItemName)
			return false
	} insertedItems.Push(item)
	return true
}
Start:
; ----------------------------------------------------------------------------------------------------------------------
Header := "
(Join`r`n
	If (NewHandle)
		hBitmap := 0
	If (hBitmap && !_Filename)
		Return hBitmap
)"
; ----------------------------------------------------------------------------------------------------------------------
H_Func := "
(Join`r`n
H_Func(B64,ico:=0) {
	If !DllCall(""Crypt32.dll\CryptStringToBinary"", ""Ptr"", &B64, ""UInt"", 0, ""UInt"", 0x01, ""Ptr"", 0, ""UIntP"", DecLen, ""Ptr"", 0, ""Ptr"", 0)
		Return False
	VarSetCapacity(Dec, DecLen, 0)
	If !DllCall(""Crypt32.dll\CryptStringToBinary"", ""Ptr"", &B64, ""UInt"", 0, ""UInt"", 0x01, ""Ptr"", &Dec, ""UIntP"", DecLen, ""Ptr"", 0, ""Ptr"", 0)
		Return False
	hData := DllCall(""Kernel32.dll\GlobalAlloc"", ""UInt"", 2, ""UPtr"", DecLen, ""UPtr"")
	pData := DllCall(""Kernel32.dll\GlobalLock"", ""Ptr"", hData, ""UPtr"")
	DllCall(""Kernel32.dll\RtlMoveMemory"", ""Ptr"", pData, ""Ptr"", &Dec, ""UPtr"", DecLen)
	DllCall(""Kernel32.dll\GlobalUnlock"", ""Ptr"", hData)
	DllCall(""Ole32.dll\CreateStreamOnHGlobal"", ""Ptr"", hData, ""Int"", True, ""PtrP"", pStream)
	hGdip := DllCall(""Kernel32.dll\LoadLibrary"", ""Str"", ""Gdiplus.dll"", ""UPtr"")
	VarSetCapacity(SI, 16, 0), NumPut(1, SI, 0, ""UChar"")
	DllCall(""Gdiplus.dll\GdiplusStartup"", ""PtrP"", pToken, ""Ptr"", &SI, ""Ptr"", 0)
	DllCall(""Gdiplus.dll\GdipCreateBitmapFromStream"",  ""Ptr"", pStream, ""PtrP"", pBitmap)
	if (ico)
		DllCall(""Gdiplus.dll\GdipCreateHICONFromBitmap"", ""Ptr"", pBitmap, ""PtrP"", hBitmap, ""UInt"", 0)
	else
		DllCall(""Gdiplus.dll\GdipCreateHBITMAPFromBitmap"", ""Ptr"", pBitmap, ""PtrP"", hBitmap, ""UInt"", 0)
	DllCall(""Gdiplus.dll\GdipDisposeImage"", ""Ptr"", pBitmap)
	DllCall(""Gdiplus.dll\GdiplusShutdown"", ""Ptr"", pToken)
	DllCall(""Kernel32.dll\FreeLibrary"", ""Ptr"", hGdip)
	DllCall(NumGet(NumGet(pStream + 0, 0, ""UPtr"") + (A_PtrSize * 2), 0, ""UPtr""), ""Ptr"", pStream)
	Return hBitmap
}
)"
restoreBody := "
(Join`r`n
	if (_Filename) {
		If (!HasData)
			Return -1
		If (!ExtractedData) {
			ExtractedData := True
			, Ptr := A_IsUnicode ? ""Ptr"" : ""UInt""
			, VarSetCapacity(TD, {1} * (A_IsUnicode ? 2 : 1))
			TD := B64
			VarSetCapacity(Out_Data, Bytes := {2}, 0)
			, DllCall(""Crypt32.dll\CryptStringToBinary"" (A_IsUnicode ? ""W"" : ""A""), Ptr, &TD, ""UInt"", 0, ""UInt"", 1, Ptr, &Out_Data, A_IsUnicode ? ""UIntP"" : ""UInt*"", Bytes, ""Int"", 0, ""Int"", 0, ""CDECL Int"")
			, TD := """"
		}
		IfExist,% _Filename
			FileDelete,% _Filename
		SplitPath,_Filename,,OutDir
		IfNotExist,% OutDir
			FileCreateDir,% OutDir
		h := DllCall(""CreateFile"", Ptr, &_Filename, ""Uint"", 0x40000000, ""Uint"", 0, ""UInt"", 0, ""UInt"", 4, ""Uint"", 0, ""UInt"", 0)
		, DllCall(""WriteFile"", Ptr, h, Ptr, &Out_Data, ""UInt"", {2}, ""UInt"", 0, ""UInt"", 0)
		, DllCall(""CloseHandle"", Ptr, h)
		If (_DumpData)
			VarSetCapacity(Out_Data, {2}, 0)
			, VarSetCapacity(Out_Data, 0)
			, HasData := 0
	}

)"
return

Обработка выполняется над файлами и файлами в папках, перемещённых в окно сценария.
Конвертирует файлы в base64 и генерирует для них код обёрнутый функциями для каждого файла, позволяющий загружать их в память и возвращая указатель.
За это отвечает первый чекбокс. Второй, добавляет возможность восстанавливать файл к исходному состоянию, если передать вызову его функции имя и расширение файла, которые он получит в результате.
Процесс обработки генерирует файл "*.ahk" в UTF-8, который можно запросто подключить через "#Include". Имя, которое получит результирующий файл зависит от имени первого файла, который был обработан и в первых строках будет содержать закомментированные шаблоны вызовов, перечисленных ниже функций, вида:

; -> Converted_file_name_ext := Retrieve_Converted_file_name_ext()

Vicoriyan, Вам достаточно покидать нужные картинки на ГУЙ этого скрипта, сохранить в файл и подключить его, или скопипастить из редактируемого поля, в котором его можно предварительно оценить и изменить. Переместите тогда этот текст куда-нибудь к Вашим функциям, я пример шаблона, в раскомментированном виде, куда-нибудь в секцию инициализации. Переменная "Converted_file_name_ext" будет содержать указатель на файл, загруженный в память. Его Вам и следует передать Gdip_CreateBitmapFromHBITMAP(HWND).

16 (изменено: Vicoriyan, 2018-04-16 13:45:10)

Re: AHK: ImageSearch без файла картинки

Спасибо что ответили. Много полезной инфы. Я тоже находил на этом форумы примеры, но все они нацелены на Gui через Bitmap_SetImage. Но я так и не понял, как мне передать сравнительный файл? Вы мне прописали функцию bmpNeedle := Gdip_CreateBitmapFromHBITMAP(HWND), но  я так и не понял, как ее использовать.

Я конвертировал 6 картинок и получил списоки подставил в код:

#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include Retrieve.ahk

1_png := Retrieve_1_png()
2_png := Retrieve_2_png()
3_png := Retrieve_3_png()
4_png := Retrieve_4_png()
5_png := Retrieve_5_png()
6_png := Retrieve_6_png()

LIST := ""
SetBatchLines, -1
CoordMode, Pixel, Window
hwnd := WinExist("A")
lock := ["1", "2", "3", "4", "5", "6"]
gdipToken := Gdip_Startup()
bmpHaystack := Gdip_BitmapFromHWND(hwnd)
loop % lock.Length()
{
   bmpNeedle := Gdip_CreateBitmapFromFile(lock[A_Index]".png")
   RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,LIST,0,0,0,0,0,0xFFFFFF,1,1)
   Gdip_DisposeImage(bmpNeedle)
   CoordMode, Mouse, Window
   Loop, Parse, LIST, `n
   {
      StringSplit, Coord, A_LoopField, `,
      MouseClick, , %Coord1%, %Coord2%, 1 , 0.5
        break 2
   }
}
Gdip_DisposeImage(bmpHaystack)
Gdip_Shutdown(gdipToken)
Return

17

Re: AHK: ImageSearch без файла картинки

Прошу прощения, я так наверное больше запутал, чем помог.
Можно обернуть набор функций Gdip_ в одну. Например:


G_Search(needle,haystack,ByRef outResult,x:=0,y:=0,w:=0,h:=0,vari:=0,trans:="",direction:=1,count:=1) {
    token := Gdip_Startup()
	if needle is number
		needlePointer := Gdip_CreateBitmapFromHBITMAP(needle)
	else
		needlePointer := Gdip_CreateBitmapFromFile(needle)
		
	if haystack is number
		haystackPointer := Gdip_BitmapFromHWND(haystack)
	else if (haystack == "screen")
		haystackPointer := Gdip_Bitmapfromscreen(Format("{1}|{2}|{3}|{4}",x,y,w,h))
	else
		haystackPointer := Gdip_CreateBitmapFromFile(haystack)
	
	found := Gdip_ImageSearch(haystackPointer,needlePointer, outResult,0,0,0,0,vari,trans,direction,count,x,y)
   
    Gdip_DisposeImage(haystackPointer)
    Gdip_DisposeImage(needlePointer)
    Gdip_Shutdown(token)
    return found
}

Таким образом, это будет более универсально:
1. Параметр "needle" может принять и указатель и имя файла.
2. "haystack"
а. Хендл окна - передайте HWND окна.
б. Область сканирования - передайте "screen" и опишите область в x, y, w и h параметрах.
в. Сканирование файла - передайте имя файла.
В остальном, всё то же самое, что справедливо и для вызова Gdip_ImageSearch(). Возвращает количество найденных элементов, а третий параметр, по ссылке возвращает их координаты.
Правда, у меня ещё немного изменена и сама Gdip_ImageSearch(), где в процессе поиска, координаты найденных элементов помещаются в массив, а не конканенируются в строку, которую всё равно потом парсить.

18 (изменено: KusochekDobra, 2018-04-16 19:22:45)

Re: AHK: ImageSearch без файла картинки


;**********************************************************************************
;
; Gdip_ImageSearch()
; by MasterFocus - 02/APRIL/2013 00:30h BRT
; Thanks to guest3456 for helping me ponder some ideas
; Requires GDIP, Gdip_SetBitmapTransColor() and Gdip_MultiLockedBitsSearch()
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition of the license EXCLUSIVELY
; for these users: tic , Rseding91 , guest3456
;
;==================================================================================
;
; This function searches for pBitmapNeedle within pBitmapHaystack
; The returned value is the number of instances found (negative = error)
;
; ++ PARAMETERS ++
;
; pBitmapHaystack and pBitmapNeedle
;   Self-explanatory bitmap pointers, are the only required parameters
;
; OutputList
;   ByRef variable to store the list of coordinates where a match was found
;
; OuterX1, OuterY1, OuterX2, OuterY2
;   Equivalent to ImageSearch's X1,Y1,X2,Y2
;   Default: 0 for all (which searches the whole haystack area)
;
; Variation
;   Just like ImageSearch, a value from 0 to 255
;   Default: 0
;
; Trans
;   Needle RGB transparent color, should be a numerical value from 0 to 0xFFFFFF
;   Default: blank (does not use transparency)
;
; SearchDirection
;   Haystack search direction
;     Vertical preference:
;       1 = top->left->right->bottom [default]
;       2 = bottom->left->right->top
;       3 = bottom->right->left->top
;       4 = top->right->left->bottom
;     Horizontal preference:
;       5 = left->top->bottom->right
;       6 = left->bottom->top->right
;       7 = right->bottom->top->left
;       8 = right->top->bottom->left
;
; Instances
;   Maximum number of instances to find when searching (0 = find all)
;   Default: 1 (stops after one match is found)
;
; LineDelim and CoordDelim
;   Outer and inner delimiters for the list of coordinates (OutputList)
;   Defaults: "`n" and ","
;
; ++ RETURN VALUES ++
;
; -1001 ==> invalid haystack and/or needle bitmap pointer
; -1002 ==> invalid variation value
; -1003 ==> X1 and Y1 cannot be negative
; -1004 ==> unable to lock haystack bitmap bits
; -1005 ==> unable to lock needle bitmap bits
; any non-negative value ==> the number of instances found
;
;==================================================================================
;
;**********************************************************************************

Gdip_ImageSearch(pBitmapHaystack,pBitmapNeedle,ByRef OutputList
,OuterX1=0,OuterY1=0,OuterX2=0,OuterY2=0,Variation=0,Trans=""
,SearchDirection=1,Instances=1,shift_x:=0,shift_y:=0) {
	
	OutputList := []
    ; Some validations that can be done before proceeding any further
    If !( pBitmapHaystack && pBitmapNeedle )
        Return -1001
    If Variation not between 0 and 255
        return -1002
    If ( ( OuterX1 < 0 ) || ( OuterY1 < 0 ) )
        return -1003
    If SearchDirection not between 1 and 8
        SearchDirection := 1
    If ( Instances < 0 )
        Instances := 0

    ; Getting the dimensions and locking the bits [haystack]
    Gdip_GetImageDimensions(pBitmapHaystack,hWidth,hHeight)
    ; Last parameter being 1 says the LockMode flag is "READ only"
    If Gdip_LockBits(pBitmapHaystack,0,0,hWidth,hHeight,hStride,hScan,hBitmapData,1)
    OR !(hWidth := NumGet(hBitmapData,0))
    OR !(hHeight := NumGet(hBitmapData,4))
        Return -1004

    ; Careful! From this point on, we must do the following before returning:
    ; - unlock haystack bits

    ; Getting the dimensions and locking the bits [needle]
    Gdip_GetImageDimensions(pBitmapNeedle,nWidth,nHeight)
    ; If Trans is correctly specified, create a backup of the original needle bitmap
    ; and modify the current one, setting the desired color as transparent.
    ; Also, since a copy is created, we must remember to dispose the new bitmap later.
    ; This whole thing has to be done before locking the bits.
    If Trans between 0 and 0xFFFFFF
    {
        pOriginalBmpNeedle := pBitmapNeedle
        pBitmapNeedle := Gdip_CloneBitmapArea(pOriginalBmpNeedle,0,0,nWidth,nHeight)
        Gdip_SetBitmapTransColor(pBitmapNeedle,Trans)
        DumpCurrentNeedle := true
    }

    ; Careful! From this point on, we must do the following before returning:
    ; - unlock haystack bits
    ; - dispose current needle bitmap (if necessary)

    If Gdip_LockBits(pBitmapNeedle,0,0,nWidth,nHeight,nStride,nScan,nBitmapData)
    OR !(nWidth := NumGet(nBitmapData,0))
    OR !(nHeight := NumGet(nBitmapData,4))
    {
        If ( DumpCurrentNeedle )
            Gdip_DisposeImage(pBitmapNeedle)
        Gdip_UnlockBits(pBitmapHaystack,hBitmapData)
        Return -1005
    }
    
    ; Careful! From this point on, we must do the following before returning:
    ; - unlock haystack bits
    ; - unlock needle bits
    ; - dispose current needle bitmap (if necessary)

    ; Adjust the search box. "OuterX2,OuterY2" will be the last pixel evaluated
    ; as possibly matching with the needle's first pixel. So, we must avoid going
    ; beyond this maximum final coordinate.
    OuterX2 := ( !OuterX2 ? hWidth-nWidth+1 : OuterX2-nWidth+1 )
    OuterY2 := ( !OuterY2 ? hHeight-nHeight+1 : OuterY2-nHeight+1 )

    OutputCount := Gdip_MultiLockedBitsSearch(hStride,hScan,hWidth,hHeight
    ,nStride,nScan,nWidth,nHeight,OutputList,OuterX1,OuterY1,OuterX2,OuterY2
    ,Variation,SearchDirection,Instances,shift_x,shift_y)

    Gdip_UnlockBits(pBitmapHaystack,hBitmapData)
    Gdip_UnlockBits(pBitmapNeedle,nBitmapData)
    If ( DumpCurrentNeedle )
        Gdip_DisposeImage(pBitmapNeedle)

    Return OutputCount
}

;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

;**********************************************************************************
;
; Gdip_SetBitmapTransColor()
; by MasterFocus - 02/APRIL/2013 00:30h BRT
; Requires GDIP
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition of the license EXCLUSIVELY
; for these users: tic , Rseding91 , guest3456
;
;**********************************************************************************

;==================================================================================
;
; This function modifies the Alpha component for all pixels of a certain color to 0
; The returned value is 0 in case of success, or a negative number otherwise
;
; ++ PARAMETERS ++
;
; pBitmap
;   A valid pointer to the bitmap that will be modified
;
; TransColor
;   The color to become transparent
;   Should range from 0 (black) to 0xFFFFFF (white)
;
; ++ RETURN VALUES ++
;
; -2001 ==> invalid bitmap pointer
; -2002 ==> invalid TransColor
; -2003 ==> unable to retrieve bitmap positive dimensions
; -2004 ==> unable to lock bitmap bits
; -2005 ==> DllCall failed (see ErrorLevel)
; any non-negative value ==> the number of pixels modified by this function
;
;==================================================================================

Gdip_SetBitmapTransColor(pBitmap,TransColor) {
    static _SetBmpTrans, Ptr, PtrA
    if !( _SetBmpTrans ) {
        Ptr := A_PtrSize ? "UPtr" : "UInt"
        PtrA := Ptr . "*"
        MCode_SetBmpTrans := "
            (LTrim Join
            8b44240c558b6c241cc745000000000085c07e77538b5c2410568b74242033c9578b7c2414894c24288da424000000
            0085db7e458bc18d1439b9020000008bff8a0c113a4e0275178a4c38013a4e01750e8a0a3a0e7508c644380300ff450083c0
            0483c204b9020000004b75d38b4c24288b44241c8b5c2418034c242048894c24288944241c75a85f5e5b33c05dc3,405
            34c8b5424388bda41c702000000004585c07e6448897c2410458bd84c8b4424304963f94c8d49010f1f800000000085db7e3
            8498bc1488bd3660f1f440000410fb648023848017519410fb6480138087510410fb6083848ff7507c640020041ff024883c
            00448ffca75d44c03cf49ffcb75bc488b7c241033c05bc3
            )"
        if ( A_PtrSize == 8 ) ; x64, after comma
            MCode_SetBmpTrans := SubStr(MCode_SetBmpTrans,InStr(MCode_SetBmpTrans,",")+1)
        else ; x86, before comma
            MCode_SetBmpTrans := SubStr(MCode_SetBmpTrans,1,InStr(MCode_SetBmpTrans,",")-1)
        VarSetCapacity(_SetBmpTrans, LEN := StrLen(MCode_SetBmpTrans)//2, 0)
        Loop, %LEN%
            NumPut("0x" . SubStr(MCode_SetBmpTrans,(2*A_Index)-1,2), _SetBmpTrans, A_Index-1, "uchar")
        MCode_SetBmpTrans := ""
        DllCall("VirtualProtect", Ptr,&_SetBmpTrans, Ptr,VarSetCapacity(_SetBmpTrans), "uint",0x40, PtrA,0)
    }
    If !pBitmap
        Return -2001
    If TransColor not between 0 and 0xFFFFFF
        Return -2002
    Gdip_GetImageDimensions(pBitmap,W,H)
    If !(W && H)
        Return -2003
    If Gdip_LockBits(pBitmap,0,0,W,H,Stride,Scan,BitmapData)
        Return -2004
    ; The following code should be slower than using the MCode approach,
    ; but will the kept here for now, just for reference.
    /*
    Count := 0
    Loop, %H% {
        Y := A_Index-1
        Loop, %W% {
            X := A_Index-1
            CurrentColor := Gdip_GetLockBitPixel(Scan,X,Y,Stride)
            If ( (CurrentColor & 0xFFFFFF) == TransColor )
                Gdip_SetLockBitPixel(TransColor,Scan,X,Y,Stride), Count++
        }
    }
    */
    ; Thanks guest3456 for helping with the initial solution involving NumPut
    Gdip_FromARGB(TransColor,A,R,G,B), VarSetCapacity(TransColor,0), VarSetCapacity(TransColor,3,255)
    NumPut(B,TransColor,0,"UChar"), NumPut(G,TransColor,1,"UChar"), NumPut(R,TransColor,2,"UChar")
    MCount := 0
    E := DllCall(&_SetBmpTrans, Ptr,Scan, "int",W, "int",H, "int",Stride, Ptr,&TransColor, "int*",MCount, "cdecl int")
    Gdip_UnlockBits(pBitmap,BitmapData)
    If ( E != 0 ) {
        ErrorLevel := E
        Return -2005
    }
    Return MCount
}

;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

;**********************************************************************************
;
; Gdip_MultiLockedBitsSearch()
; by MasterFocus - 24/MARCH/2013 06:20h BRT
; Requires GDIP and Gdip_LockedBitsSearch()
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition of the license EXCLUSIVELY
; for these users: tic , Rseding91 , guest3456
;
;**********************************************************************************

;==================================================================================
;
; This function returns the number of instances found
; The 8 first parameters are the same as in Gdip_LockedBitsSearch()
; The other 10 parameters are the same as in Gdip_ImageSearch()
; Note: the default for the Intances parameter here is 0 (find all matches)
;
;==================================================================================

Gdip_MultiLockedBitsSearch(hStride,hScan,hWidth,hHeight,nStride,nScan,nWidth,nHeight
,ByRef OutputList,OuterX1=0,OuterY1=0,OuterX2=0,OuterY2=0,Variation=0
,SearchDirection=1,Instances=0,shift_x:=0,shift_y:=0)
{
    
    OutputCount := !Instances
    InnerX1 := OuterX1 , InnerY1 := OuterY1
    InnerX2 := OuterX2 , InnerY2 := OuterY2

    ; The following part is a rather ugly but working hack that I
    ; came up with to adjust the variables and their increments
    ; according to the specified Haystack Search Direction
    /*
    Mod(SD,4) = 0 --> iX = 2 , stepX = +0 , iY = 1 , stepY = +1
    Mod(SD,4) = 1 --> iX = 1 , stepX = +1 , iY = 1 , stepY = +1
    Mod(SD,4) = 2 --> iX = 1 , stepX = +1 , iY = 2 , stepY = +0
    Mod(SD,4) = 3 --> iX = 2 , stepX = +0 , iY = 2 , stepY = +0
    SD <= 4   ------> Vertical preference
    SD > 4    ------> Horizontal preference
    */
    ; Set the index and the step (for both X and Y) to +1
    iX := 1, stepX := 1, iY := 1, stepY := 1
    ; Adjust Y variables if SD is 2, 3, 6 or 7
    Modulo := Mod(SearchDirection,4)
    If ( Modulo > 1 )
        iY := 2, stepY := 0
    ; adjust X variables if SD is 3, 4, 7 or 8
    If !Mod(Modulo,3)
        iX := 2, stepX := 0
    ; Set default Preference to vertical and Nonpreference to horizontal
    P := "Y", N := "X"
    ; adjust Preference and Nonpreference if SD is 5, 6, 7 or 8
    If ( SearchDirection > 4 )
        P := "X", N := "Y"
    ; Set the Preference Index and the Nonpreference Index
    iP := i%P%, iN := i%N%

    While (!(OutputCount == Instances) && (0 == Gdip_LockedBitsSearch(hStride,hScan,hWidth,hHeight,nStride
    ,nScan,nWidth,nHeight,FoundX,FoundY,OuterX1,OuterY1,OuterX2,OuterY2,Variation,SearchDirection)))
    {
        OutputCount++
        OutputList.Push(FoundX+shift_x,FoundY+shift_y)
        Outer%P%%iP% := Found%P%+step%P%
        Inner%N%%iN% := Found%N%+step%N%
        Inner%P%1 := Found%P%
        Inner%P%2 := Found%P%+1
        While (!(OutputCount == Instances) && (0 == Gdip_LockedBitsSearch(hStride,hScan,hWidth,hHeight,nStride
        ,nScan,nWidth,nHeight,FoundX,FoundY,InnerX1,InnerY1,InnerX2,InnerY2,Variation,SearchDirection)))
        {
            OutputCount++
            OutputList.Push(FoundX+shift_x,FoundY+shift_y)
            Inner%N%%iN% := Found%N%+step%N%
        }
    }
    OutputCount -= !Instances
    Return OutputCount
}

;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

;**********************************************************************************
;
; Gdip_LockedBitsSearch()
; by MasterFocus - 24/MARCH/2013 06:20h BRT
; Mostly adapted from previous work by tic and Rseding91
;
; Requires GDIP
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition of the license EXCLUSIVELY
; for these users: tic , Rseding91 , guest3456
;
;**********************************************************************************

;==================================================================================
;
; This function searches for a single match of nScan within hScan
;
; ++ PARAMETERS ++
;
; hStride, hScan, hWidth and hHeight
;   Haystack stuff, extracted from a BitmapData, extracted from a Bitmap
;
; nStride, nScan, nWidth and nHeight
;   Needle stuff, extracted from a BitmapData, extracted from a Bitmap
;
; x and y
;   ByRef variables to store the X and Y coordinates of the image if it's found
;   Default: "" for both
;
; sx1, sy1, sx2 and sy2
;   These can be used to crop the search area within the haystack
;   Default: "" for all (does not crop)
;
; Variation
;   Same as the builtin ImageSearch command
;   Default: 0
;
; sd
;   Haystack search direction
;     Vertical preference:
;       1 = top->left->right->bottom [default]
;       2 = bottom->left->right->top
;       3 = bottom->right->left->top
;       4 = top->right->left->bottom
;     Horizontal preference:
;       5 = left->top->bottom->right
;       6 = left->bottom->top->right
;       7 = right->bottom->top->left
;       8 = right->top->bottom->left
;   This value is passed to the internal MCoded function
;
; ++ RETURN VALUES ++
;
; -3001 to -3006 ==> search area incorrectly defined
; -3007 ==> DllCall returned blank
; 0 ==> DllCall succeeded and a match was found
; -4001 ==> DllCall succeeded but a match was not found
; anything else ==> the error value returned by the unsuccessful DllCall
;
;==================================================================================

Gdip_LockedBitsSearch(hStride,hScan,hWidth,hHeight,nStride,nScan,nWidth,nHeight
,ByRef x="",ByRef y="",sx1=0,sy1=0,sx2=0,sy2=0,Variation=0,sd=1)
{
    static _ImageSearch, Ptr, PtrA

    ; Initialize all MCode stuff, if necessary
    if !( _ImageSearch ) {
        Ptr := A_PtrSize ? "UPtr" : "UInt"
        PtrA := Ptr . "*"

        MCode_ImageSearch := "
            (LTrim Join
            8b44243883ec205355565783f8010f857a0100008b7c2458897c24143b7c24600f8db50b00008b44244c8b5c245c8b
            4c24448b7424548be80fafef896c242490897424683bf30f8d0a0100008d64240033c033db8bf5896c241c895c2420894424
            183b4424480f8d0401000033c08944241085c90f8e9d0000008b5424688b7c24408beb8d34968b54246403df8d4900b80300
            0000803c18008b442410745e8b44243c0fb67c2f020fb64c06028d04113bf87f792bca3bf97c738b44243c0fb64c06018b44
            24400fb67c28018d04113bf87f5a2bca3bf97c548b44243c0fb63b0fb60c068d04113bf87f422bca3bf97c3c8b4424108b7c
            24408b4c24444083c50483c30483c604894424103bc17c818b5c24208b74241c0374244c8b44241840035c24508974241ce9
            2dffffff8b6c24688b5c245c8b4c244445896c24683beb8b6c24240f8c06ffffff8b44244c8b7c24148b7424544703e8897c
            2414896c24243b7c24600f8cd5feffffe96b0a00008b4424348b4c246889088b4424388b4c24145f5e5d890833c05b83c420
            c383f8020f85870100008b7c24604f897c24103b7c24580f8c310a00008b44244c8b5c245c8b4c24448bef0fafe8f7d88944
            24188b4424548b742418896c24288d4900894424683bc30f8d0a0100008d64240033c033db8bf5896c2420895c241c894424
            243b4424480f8d0401000033c08944241485c90f8e9d0000008b5424688b7c24408beb8d34968b54246403df8d4900b80300
            0000803c03008b442414745e8b44243c0fb67c2f020fb64c06028d04113bf87f792bca3bf97c738b44243c0fb64c06018b44
            24400fb67c28018d04113bf87f5a2bca3bf97c548b44243c0fb63b0fb60c068d04113bf87f422bca3bf97c3c8b4424148b7c
            24408b4c24444083c50483c30483c604894424143bc17c818b5c241c8b7424200374244c8b44242440035c245089742420e9
            2dffffff8b6c24688b5c245c8b4c244445896c24683beb8b6c24280f8c06ffffff8b7c24108b4424548b7424184f03ee897c
            2410896c24283b7c24580f8dd5feffffe9db0800008b4424348b4c246889088b4424388b4c24105f5e5d890833c05b83c420
            c383f8030f85650100008b7c24604f897c24103b7c24580f8ca10800008b44244c8b6c245c8b5c24548b4c24448bf70faff0
            4df7d8896c242c897424188944241c8bff896c24683beb0f8c020100008d64240033c033db89742424895c2420894424283b
            4424480f8d76ffffff33c08944241485c90f8e9f0000008b5424688b7c24408beb8d34968b54246403dfeb038d4900b80300
            0000803c03008b442414745e8b44243c0fb67c2f020fb64c06028d04113bf87f752bca3bf97c6f8b44243c0fb64c06018b44
            24400fb67c28018d04113bf87f562bca3bf97c508b44243c0fb63b0fb60c068d04113bf87f3e2bca3bf97c388b4424148b7c
            24408b4c24444083c50483c30483c604894424143bc17c818b5c24208b7424248b4424280374244c40035c2450e92bffffff
            8b6c24688b5c24548b4c24448b7424184d896c24683beb0f8d0affffff8b7c24108b44241c4f03f0897c2410897424183b7c
            24580f8c580700008b6c242ce9d4feffff83f8040f85670100008b7c2458897c24103b7c24600f8d340700008b44244c8b6c
            245c8b5c24548b4c24444d8bf00faff7896c242c8974241ceb098da424000000008bff896c24683beb0f8c020100008d6424
            0033c033db89742424895c2420894424283b4424480f8d06feffff33c08944241485c90f8e9f0000008b5424688b7c24408b
            eb8d34968b54246403dfeb038d4900b803000000803c03008b442414745e8b44243c0fb67c2f020fb64c06028d04113bf87f
            752bca3bf97c6f8b44243c0fb64c06018b4424400fb67c28018d04113bf87f562bca3bf97c508b44243c0fb63b0fb60c068d
            04113bf87f3e2bca3bf97c388b4424148b7c24408b4c24444083c50483c30483c604894424143bc17c818b5c24208b742424
            8b4424280374244c40035c2450e92bffffff8b6c24688b5c24548b4c24448b74241c4d896c24683beb0f8d0affffff8b4424
            4c8b7c24104703f0897c24108974241c3b7c24600f8de80500008b6c242ce9d4feffff83f8050f85890100008b7c2454897c
            24683b7c245c0f8dc40500008b5c24608b6c24588b44244c8b4c2444eb078da42400000000896c24103beb0f8d200100008b
            e80faf6c2458896c241c33c033db8bf5896c2424895c2420894424283b4424480f8d0d01000033c08944241485c90f8ea600
            00008b5424688b7c24408beb8d34968b54246403dfeb0a8da424000000008d4900b803000000803c03008b442414745e8b44
            243c0fb67c2f020fb64c06028d04113bf87f792bca3bf97c738b44243c0fb64c06018b4424400fb67c28018d04113bf87f5a
            2bca3bf97c548b44243c0fb63b0fb60c068d04113bf87f422bca3bf97c3c8b4424148b7c24408b4c24444083c50483c30483
            c604894424143bc17c818b5c24208b7424240374244c8b44242840035c245089742424e924ffffff8b7c24108b6c241c8b44
            244c8b5c24608b4c24444703e8897c2410896c241c3bfb0f8cf3feffff8b7c24688b6c245847897c24683b7c245c0f8cc5fe
            ffffe96b0400008b4424348b4c24688b74241089088b4424385f89305e5d33c05b83c420c383f8060f85670100008b7c2454
            897c24683b7c245c0f8d320400008b6c24608b5c24588b44244c8b4c24444d896c24188bff896c24103beb0f8c1a0100008b
            f50faff0f7d88974241c8944242ceb038d490033c033db89742424895c2420894424283b4424480f8d06fbffff33c0894424
            1485c90f8e9f0000008b5424688b7c24408beb8d34968b54246403dfeb038d4900b803000000803c03008b442414745e8b44
            243c0fb67c2f020fb64c06028d04113bf87f752bca3bf97c6f8b44243c0fb64c06018b4424400fb67c28018d04113bf87f56
            2bca3bf97c508b44243c0fb63b0fb60c068d04113bf87f3e2bca3bf97c388b4424148b7c24408b4c24444083c50483c30483
            c604894424143bc17c818b5c24208b7424248b4424280374244c40035c2450e92bffffff8b6c24108b74241c0374242c8b5c
            24588b4c24444d896c24108974241c3beb0f8d02ffffff8b44244c8b7c246847897c24683b7c245c0f8de60200008b6c2418
            e9c2feffff83f8070f85670100008b7c245c4f897c24683b7c24540f8cc10200008b6c24608b5c24588b44244c8b4c24444d
            896c241890896c24103beb0f8c1a0100008bf50faff0f7d88974241c8944242ceb038d490033c033db89742424895c242089
            4424283b4424480f8d96f9ffff33c08944241485c90f8e9f0000008b5424688b7c24408beb8d34968b54246403dfeb038d49
            00b803000000803c18008b442414745e8b44243c0fb67c2f020fb64c06028d04113bf87f752bca3bf97c6f8b44243c0fb64c
            06018b4424400fb67c28018d04113bf87f562bca3bf97c508b44243c0fb63b0fb60c068d04113bf87f3e2bca3bf97c388b44
            24148b7c24408b4c24444083c50483c30483c604894424143bc17c818b5c24208b7424248b4424280374244c40035c2450e9
            2bffffff8b6c24108b74241c0374242c8b5c24588b4c24444d896c24108974241c3beb0f8d02ffffff8b44244c8b7c24684f
            897c24683b7c24540f8c760100008b6c2418e9c2feffff83f8080f85640100008b7c245c4f897c24683b7c24540f8c510100
            008b5c24608b6c24588b44244c8b4c24448d9b00000000896c24103beb0f8d200100008be80faf6c2458896c241c33c033db
            8bf5896c2424895c2420894424283b4424480f8d9dfcffff33c08944241485c90f8ea60000008b5424688b7c24408beb8d34
            968b54246403dfeb0a8da424000000008d4900b803000000803c03008b442414745e8b44243c0fb67c2f020fb64c06028d04
            113bf87f792bca3bf97c738b44243c0fb64c06018b4424400fb67c28018d04113bf87f5a2bca3bf97c548b44243c0fb63b0f
            b604068d0c103bf97f422bc23bf87c3c8b4424148b7c24408b4c24444083c50483c30483c604894424143bc17c818b5c2420
            8b7424240374244c8b44242840035c245089742424e924ffffff8b7c24108b6c241c8b44244c8b5c24608b4c24444703e889
            7c2410896c241c3bfb0f8cf3feffff8b7c24688b6c24584f897c24683b7c24540f8dc5feffff8b4424345fc700ffffffff8b
            4424345e5dc700ffffffffb85ff0ffff5b83c420c3,4c894c24204c89442418488954241048894c24085355565741544
            155415641574883ec188b8424c80000004d8bd94d8bd0488bda83f8010f85b3010000448b8c24a800000044890c24443b8c2
            4b80000000f8d66010000448bac24900000008b9424c0000000448b8424b00000008bbc2480000000448b9424a0000000418
            bcd410fafc9894c24040f1f84000000000044899424c8000000453bd00f8dfb000000468d2495000000000f1f80000000003
            3ed448bf933f6660f1f8400000000003bac24880000000f8d1701000033db85ff7e7e458bf4448bce442bf64503f7904d63c
            14d03c34180780300745a450fb65002438d040e4c63d84c035c2470410fb64b028d0411443bd07f572bca443bd17c50410fb
            64b01450fb650018d0411443bd07f3e2bca443bd17c37410fb60b450fb6108d0411443bd07f272bca443bd17c204c8b5c247
            8ffc34183c1043bdf7c8fffc54503fd03b42498000000e95effffff8b8424c8000000448b8424b00000008b4c24044c8b5c2
            478ffc04183c404898424c8000000413bc00f8c20ffffff448b0c24448b9424a000000041ffc14103cd44890c24894c24044
            43b8c24b80000000f8cd8feffff488b5c2468488b4c2460b85ff0ffffc701ffffffffc703ffffffff4883c418415f415e415
            d415c5f5e5d5bc38b8424c8000000e9860b000083f8020f858c010000448b8c24b800000041ffc944890c24443b8c24a8000
            0007cab448bac2490000000448b8424c00000008b9424b00000008bbc2480000000448b9424a0000000418bc9410fafcd418
            bc5894c2404f7d8894424080f1f400044899424c8000000443bd20f8d02010000468d2495000000000f1f80000000004533f
            6448bf933f60f1f840000000000443bb424880000000f8d56ffffff33db85ff0f8e81000000418bec448bd62bee4103ef496
            3d24903d3807a03007460440fb64a02418d042a4c63d84c035c2470410fb64b02428d0401443bc87f5d412bc8443bc97c554
            10fb64b01440fb64a01428d0401443bc87f42412bc8443bc97c3a410fb60b440fb60a428d0401443bc87f29412bc8443bc97
            c214c8b5c2478ffc34183c2043bdf7c8a41ffc64503fd03b42498000000e955ffffff8b8424c80000008b9424b00000008b4
            c24044c8b5c2478ffc04183c404898424c80000003bc20f8c19ffffff448b0c24448b9424a0000000034c240841ffc9894c2
            40444890c24443b8c24a80000000f8dd0feffffe933feffff83f8030f85c4010000448b8c24b800000041ffc944898c24c80
            00000443b8c24a80000000f8c0efeffff8b842490000000448b9c24b0000000448b8424c00000008bbc248000000041ffcb4
            18bc98bd044895c24080fafc8f7da890c24895424048b9424a0000000448b542404458beb443bda0f8c13010000468d249d0
            000000066660f1f84000000000033ed448bf933f6660f1f8400000000003bac24880000000f8d0801000033db85ff0f8e960
            00000488b4c2478458bf4448bd6442bf64503f70f1f8400000000004963d24803d1807a03007460440fb64a02438d04164c6
            3d84c035c2470410fb64b02428d0401443bc87f63412bc8443bc97c5b410fb64b01440fb64a01428d0401443bc87f48412bc
            8443bc97c40410fb60b440fb60a428d0401443bc87f2f412bc8443bc97c27488b4c2478ffc34183c2043bdf7c8a8b8424900
            00000ffc54403f803b42498000000e942ffffff8b9424a00000008b8424900000008b0c2441ffcd4183ec04443bea0f8d11f
            fffff448b8c24c8000000448b542404448b5c240841ffc94103ca44898c24c8000000890c24443b8c24a80000000f8dc2fef
            fffe983fcffff488b4c24608b8424c8000000448929488b4c2468890133c0e981fcffff83f8040f857f010000448b8c24a80
            0000044890c24443b8c24b80000000f8d48fcffff448bac2490000000448b9424b00000008b9424c0000000448b8424a0000
            0008bbc248000000041ffca418bcd4489542408410fafc9894c2404669044899424c8000000453bd00f8cf8000000468d249
            5000000000f1f800000000033ed448bf933f6660f1f8400000000003bac24880000000f8df7fbffff33db85ff7e7e458bf44
            48bce442bf64503f7904d63c14d03c34180780300745a450fb65002438d040e4c63d84c035c2470410fb64b028d0411443bd
            07f572bca443bd17c50410fb64b01450fb650018d0411443bd07f3e2bca443bd17c37410fb60b450fb6108d0411443bd07f2
            72bca443bd17c204c8b5c2478ffc34183c1043bdf7c8fffc54503fd03b42498000000e95effffff8b8424c8000000448b842
            4a00000008b4c24044c8b5c2478ffc84183ec04898424c8000000413bc00f8d20ffffff448b0c24448b54240841ffc14103c
            d44890c24894c2404443b8c24b80000000f8cdbfeffffe9defaffff83f8050f85ab010000448b8424a000000044890424443
            b8424b00000000f8dc0faffff8b9424c0000000448bac2498000000448ba424900000008bbc2480000000448b8c24a800000
            0428d0c8500000000898c24c800000044894c2404443b8c24b80000000f8d09010000418bc4410fafc18944240833ed448bf
            833f6660f1f8400000000003bac24880000000f8d0501000033db85ff0f8e87000000448bf1448bce442bf64503f74d63c14
            d03c34180780300745d438d040e4c63d84d03da450fb65002410fb64b028d0411443bd07f5f2bca443bd17c58410fb64b014
            50fb650018d0411443bd07f462bca443bd17c3f410fb60b450fb6108d0411443bd07f2f2bca443bd17c284c8b5c24784c8b5
            42470ffc34183c1043bdf7c8c8b8c24c8000000ffc54503fc4103f5e955ffffff448b4424048b4424088b8c24c80000004c8
            b5c24784c8b54247041ffc04103c4448944240489442408443b8424b80000000f8c0effffff448b0424448b8c24a80000004
            1ffc083c10444890424898c24c8000000443b8424b00000000f8cc5feffffe946f9ffff488b4c24608b042489018b4424044
            88b4c2468890133c0e945f9ffff83f8060f85aa010000448b8c24a000000044894c2404443b8c24b00000000f8d0bf9ffff8
            b8424b8000000448b8424c0000000448ba424900000008bbc2480000000428d0c8d00000000ffc88944240c898c24c800000
            06666660f1f840000000000448be83b8424a80000000f8c02010000410fafc4418bd4f7da891424894424084533f6448bf83
            3f60f1f840000000000443bb424880000000f8df900000033db85ff0f8e870000008be9448bd62bee4103ef4963d24903d38
            07a03007460440fb64a02418d042a4c63d84c035c2470410fb64b02428d0401443bc87f64412bc8443bc97c5c410fb64b014
            40fb64a01428d0401443bc87f49412bc8443bc97c41410fb60b440fb60a428d0401443bc87f30412bc8443bc97c284c8b5c2
            478ffc34183c2043bdf7c8a8b8c24c800000041ffc64503fc03b42498000000e94fffffff8b4424088b8c24c80000004c8b5
            c247803042441ffcd89442408443bac24a80000000f8d17ffffff448b4c24048b44240c41ffc183c10444894c2404898c24c
            8000000443b8c24b00000000f8ccefeffffe991f7ffff488b4c24608b4424048901488b4c246833c0448929e992f7ffff83f
            8070f858d010000448b8c24b000000041ffc944894c2404443b8c24a00000000f8c55f7ffff8b8424b8000000448b8424c00
            00000448ba424900000008bbc2480000000428d0c8d00000000ffc8890424898c24c8000000660f1f440000448be83b8424a
            80000000f8c02010000410fafc4418bd4f7da8954240c8944240833ed448bf833f60f1f8400000000003bac24880000000f8
            d4affffff33db85ff0f8e89000000448bf1448bd6442bf64503f74963d24903d3807a03007460440fb64a02438d04164c63d
            84c035c2470410fb64b02428d0401443bc87f63412bc8443bc97c5b410fb64b01440fb64a01428d0401443bc87f48412bc84
            43bc97c40410fb60b440fb60a428d0401443bc87f2f412bc8443bc97c274c8b5c2478ffc34183c2043bdf7c8a8b8c24c8000
            000ffc54503fc03b42498000000e94fffffff8b4424088b8c24c80000004c8b5c24780344240c41ffcd89442408443bac24a
            80000000f8d17ffffff448b4c24048b042441ffc983e90444894c2404898c24c8000000443b8c24a00000000f8dcefeffffe
            9e1f5ffff83f8080f85ddf5ffff448b8424b000000041ffc84489442404443b8424a00000000f8cbff5ffff8b9424c000000
            0448bac2498000000448ba424900000008bbc2480000000448b8c24a8000000428d0c8500000000898c24c800000044890c2
            4443b8c24b80000000f8d08010000418bc4410fafc18944240833ed448bf833f6660f1f8400000000003bac24880000000f8
            d0501000033db85ff0f8e87000000448bf1448bce442bf64503f74d63c14d03c34180780300745d438d040e4c63d84d03da4
            50fb65002410fb64b028d0411443bd07f5f2bca443bd17c58410fb64b01450fb650018d0411443bd07f462bca443bd17c3f4
            10fb603450fb6108d0c10443bd17f2f2bc2443bd07c284c8b5c24784c8b542470ffc34183c1043bdf7c8c8b8c24c8000000f
            fc54503fc4103f5e955ffffff448b04248b4424088b8c24c80000004c8b5c24784c8b54247041ffc04103c44489042489442
            408443b8424b80000000f8c10ffffff448b442404448b8c24a800000041ffc883e9044489442404898c24c8000000443b842
            4a00000000f8dc6feffffe946f4ffff8b442404488b4c246089018b0424488b4c2468890133c0e945f4ffff
            )"
        if ( A_PtrSize == 8 ) ; x64, after comma
            MCode_ImageSearch := SubStr(MCode_ImageSearch,InStr(MCode_ImageSearch,",")+1)
        else ; x86, before comma
            MCode_ImageSearch := SubStr(MCode_ImageSearch,1,InStr(MCode_ImageSearch,",")-1)
        VarSetCapacity(_ImageSearch, LEN := StrLen(MCode_ImageSearch)//2, 0)
        Loop, %LEN%
            NumPut("0x" . SubStr(MCode_ImageSearch,(2*A_Index)-1,2), _ImageSearch, A_Index-1, "uchar")
        MCode_ImageSearch := ""
        DllCall("VirtualProtect", Ptr,&_ImageSearch, Ptr,VarSetCapacity(_ImageSearch), "uint",0x40, PtrA,0)
    }

    ; Abort if an initial coordinates is located before a final coordinate
    If ( sx2 < sx1 )
        return -3001
    If ( sy2 < sy1 )
        return -3002

    ; Check the search box. "sx2,sy2" will be the last pixel evaluated
    ; as possibly matching with the needle's first pixel. So, we must
    ; avoid going beyond this maximum final coordinate.
    If ( sx2 > (hWidth-nWidth+1) )
        return -3003
    If ( sy2 > (hHeight-nHeight+1) )
        return -3004

    ; Abort if the width or height of the search box is 0
    If ( sx2-sx1 == 0 )
        return -3005
    If ( sy2-sy1 == 0 )
        return -3006

    ; The DllCall parameters are the same for easier C code modification,
    ; even though they aren't all used on the _ImageSearch version
    x := 0, y := 0
    , E := DllCall( &_ImageSearch, "int*",x, "int*",y, Ptr,hScan, Ptr,nScan, "int",nWidth, "int",nHeight
    , "int",hStride, "int",nStride, "int",sx1, "int",sy1, "int",sx2, "int",sy2, "int",Variation
    , "int",sd, "cdecl int")
    Return ( E == "" ? -3007 : E )
}

После вызова, вернёт в третьем параметре массив вида: [x1, y1, x2, y2, x3, y3, ...]
Перебрать можно например так:


i := 1
Loop,% G_Search(fileID,"screen",result,0, 0, 500, 500,15,0,,100) {
	MsgBox,,Координаты,% "Элемент №" A_Index ":`nx = '" result[i++] "' <|> y = '" result[i++] "'"
}

19 (изменено: Vicoriyan, 2018-04-16 15:57:38)

Re: AHK: ImageSearch без файла картинки

Ответ пуст.
Что-то не так видимо делаю или вообще все не правильно делаю.

#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include Retrieve.ahk

1_png := Retrieve_1_png()

hwnd := WinExist("1.png")
gdipToken := Gdip_Startup()
Haystack := Gdip_BitmapFromHWND(hwnd)
needle := Retrieve_1_png()

G_Search(fileID,"screen",result,0, 0, 500, 500,15,0,,100) 
MsgBox,,Координаты,% "Элемент №" A_Index ":`nx = '" result[i++] "' <|> y = '" result[i++] "'"

G_Search(needle,haystack,ByRef outResult,x:=0,y:=0,w:=0,h:=0,vari:=0,trans:="",direction:=1,count:=1) {
    token := Gdip_Startup()
	if needle is number
		needlePointer := Gdip_CreateBitmapFromHBITMAP(needle)
	else
		needlePointer := Gdip_CreateBitmapFromFile(needle)
		
	if haystack is number
		haystackPointer := Gdip_BitmapFromHWND(haystack)
	else if (haystack == "screen")
		haystackPointer := Gdip_Bitmapfromscreen(Format("180|150|300|300",x,y,w,h))
	else
		haystackPointer := Gdip_CreateBitmapFromFile(haystack)
	
	found := Gdip_ImageSearch(haystackPointer,needlePointer, outResult,0,0,0,0,vari,trans,direction,count,x,y)
   
    Gdip_DisposeImage(haystackPointer)
    Gdip_DisposeImage(needlePointer)
    Gdip_Shutdown(token)
    return found
}

20 (изменено: KusochekDobra, 2018-04-16 17:20:47)

Re: AHK: ImageSearch без файла картинки

Убедитесь вначале, что искомый элемент находится в области '0, 0, 500, 500' экрана. Для визуализации, будет создана рамка на 1 секунду, внутри которой и производится сканирование.


#SingleInstance, Force
#NoEnv

CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetWorkingDir, A_ScriptDir

SetBatchLines, -1

#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include Retrieve.ahk

needle := Retrieve_1_png()
xx := 0, yy := 0
ww := 500, hh := 500
result := []

^F1::	; Ctrl+F1
	SetSquare(xx, yy, ww, hh)
	Sleep, 1000
	count := G_Search(needle, "screen", result, xx, yy, ww, hh, 15,,, 100) 
	SetSquare()
	i := 1
	MsgBox,,Координаты,% "Элемент №" i ":`nx = '" result[i++] "' <|> y = '" result[i++] "'`nВсего = " count
return

G_Search(needle,haystack,ByRef outResult,x:=0,y:=0,w:=0,h:=0,vari:=0,trans:="",direction:=1,count:=1) {
    token := Gdip_Startup()
	if needle is number
		needlePointer := Gdip_CreateBitmapFromHBITMAP(needle)
	else
		needlePointer := Gdip_CreateBitmapFromFile(needle)
		
	if haystack is number
		haystackPointer := Gdip_BitmapFromHWND(haystack)
	else if (haystack == "screen")
		haystackPointer := Gdip_Bitmapfromscreen(Format("{1}|{2}|{3}|{4}",x,y,w,h))
	else
		haystackPointer := Gdip_CreateBitmapFromFile(haystack)
	
	found := Gdip_ImageSearch(haystackPointer,needlePointer, outResult,0,0,0,0,vari,trans,direction,count,x,y)
   
    Gdip_DisposeImage(haystackPointer)
    Gdip_DisposeImage(needlePointer)
    Gdip_Shutdown(token)
    return found
}
SetSquare(x := "", y := "", w := "", h := "", boldLine := 1, clr := "FF0000") {
	if (x == "") {
		SplashImage 1:, Hide
		SplashImage 2:, Hide
		SplashImage 3:, Hide
		SplashImage 4:, Hide
	} else {
		width := w - x, heigth := h - y
		SplashImage 1:, % "CW" clr " B x" x " y" y " w" width + boldLine " h" boldLine
		SplashImage 2:, % "CW" clr " B x" x " y" h " w" width + boldLine " h" boldLine
		SplashImage 3:, % "CW" clr " B x" x " y" y " w" boldLine " h" heigth
		SplashImage 4:, % "CW" clr " B x" w " y" y + 1 " w" boldLine " h" heigth
	}
}

Вопрос: Gdip_ImageSearch() - используется из модифицированного примера выше, или Ваш вариант?

21 (изменено: Vicoriyan, 2018-04-16 20:22:39)

Re: AHK: ImageSearch без файла картинки

Так работает:

i := 1
MsgBox,,Координаты,% "Элемент №" A_Index ":`nx = '" result[i++] "' <|> y = '" result[i++] "'"

А вот, чтоб составить список, нет:

i := 1
Loop,% G_Search(fileID,"screen",result,0, 0, 500, 500,15,0,,100) {
     MsgBox,,Координаты,% "Элемент №" A_Index ":`nx = '" result[i++] "' <|> y = '" result[i++] "'"
}

22

Re: AHK: ImageSearch без файла картинки

Обращаю Ваше внимание на то, что первым параметром, функция получает значение, идентифицирующее объект, который будет искомым в сканировании. В Вашем примере, указатель на него возвращает функция:

needle := Retrieve_1_png()

И далее, переменная "needle" выступает в роли этого идентификатора. Если вторая часть примера, которая по Вашему, НЕ работает, была скопирована без изменений из НЕ работающего кода, но идентификатор получается прежним способом, сохраняясь в "needle", то Вы передаёте в G_Search() - недействительное значение.


#SingleInstance, Force
#NoEnv

CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetWorkingDir, A_ScriptDir
SetTitleMatchMode, 2

SetBatchLines, -1

#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include Retrieve.ahk

needle := Retrieve_1_png()
xx := 0, yy := 0
ww := 1500, hh := 1500
result := []

^F1::	; Ctrl+F1
	SetSquare(xx, yy, ww, hh)
	Sleep, 1000
	count := G_Search(needle, "screen", result, xx, yy, ww, hh, 15,,, 100) 
	SetSquare()
	i := 1
	Loop,% count {
		MsgBox,,Координаты,% "Элемент №" A_Index ":`nx = '" result[i++] "' <|> y = '" result[i++] "'`nВсего = " count
	}
	
return

G_Search(needle,haystack,ByRef outResult,x:=0,y:=0,w:=0,h:=0,vari:=0,trans:="",direction:=1,count:=1) {
    token := Gdip_Startup()
	if needle is number
		needlePointer := Gdip_CreateBitmapFromHBITMAP(needle)
	else
		needlePointer := Gdip_CreateBitmapFromFile(needle)
		
	if haystack is number
		haystackPointer := Gdip_BitmapFromHWND(haystack)
	else if (haystack == "screen")
		haystackPointer := Gdip_Bitmapfromscreen(Format("{1}|{2}|{3}|{4}",x,y,w,h))
	else
		haystackPointer := Gdip_CreateBitmapFromFile(haystack)
	
	found := Gdip_ImageSearch(haystackPointer,needlePointer, outResult,0,0,0,0,vari,trans,direction,count,x,y)
   
    Gdip_DisposeImage(haystackPointer)
    Gdip_DisposeImage(needlePointer)
    Gdip_Shutdown(token)
    return found
}
SetSquare(x := "", y := "", w := "", h := "", boldLine := 1, clr := "FF0000") {
	if (x == "") {
		SplashImage 1:, Hide
		SplashImage 2:, Hide
		SplashImage 3:, Hide
		SplashImage 4:, Hide
	} else {
		width := w - x, heigth := h - y, workArr := []
		SplashImage 1:, % "CW" clr " B x" x " y" y " w" width + boldLine " h" boldLine
		SplashImage 2:, % "CW" clr " B x" x " y" h " w" width + boldLine " h" boldLine
		SplashImage 3:, % "CW" clr " B x" x " y" y " w" boldLine " h" heigth
		SplashImage 4:, % "CW" clr " B x" w " y" y + 1 " w" boldLine " h" heigth
		return workArr := [x, y, w, h]
	}
}
Escape::
	ExitApp

23

Re: AHK: ImageSearch без файла картинки

Да, ошибку свою понял.
Есть вопрос. Сейчас код ищет в заданной области экрана. Как задать, чтоб искал в заданном активном окне в Вашем примере?

24

Re: AHK: ImageSearch без файла картинки

В "haystack" передайте хендл окна.
Пост №17, под примером.

25

Re: AHK: ImageSearch без файла картинки

Ищет по всему экране, но не в конкретном окне. Узнаю это изменением координат. Специально перетаскиваю окно в слепую зону области указанных координат. Когда окно находится в пределах - находит. За пределами - ответа нет.

#SingleInstance, Force
#NoEnv

CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetWorkingDir, A_ScriptDir
SetTitleMatchMode, 2

SetBatchLines, -1

#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include Retrieve.ahk

WinActivate, 1
hwnd := WinExist("1")
token := Gdip_Startup()
haystack := Gdip_BitmapFromHWND(hwnd)
needle := Retrieve_1_png()

xx := 0, yy := 0
ww := 500, hh := 500
result := []

count := G_Search(needle, "screen", result, xx, yy, ww, hh, 15,,, 100) 

i := 1
Loop,% count {
   MsgBox,,Координаты,% "Элемент №" A_Index ":`nx = '" result[i++] "' <|> y = '" result[i++] "'`nВсего = " count
}
	
return

G_Search(needle,haystack,ByRef outResult,x:=0,y:=0,w:=0,h:=0,vari:=0,trans:="",direction:=1,count:=1) {
    token := Gdip_Startup()
	if needle is number
		needlePointer := Gdip_CreateBitmapFromHBITMAP(needle)
	else
		needlePointer := Gdip_CreateBitmapFromFile(needle)
		
	if haystack is number
		haystackPointer := Gdip_BitmapFromHWND(haystack)
	else if (haystack == "screen")
		haystackPointer := Gdip_Bitmapfromscreen(Format("{1}|{2}|{3}|{4}",x,y,w,h))
	else
		haystackPointer := Gdip_CreateBitmapFromFile(haystack)
	
	found := Gdip_ImageSearch(haystackPointer,needlePointer, outResult,0,0,0,0,vari,trans,direction,count,x,y)
   
    Gdip_DisposeImage(haystackPointer)
    Gdip_DisposeImage(needlePointer)
    Gdip_Shutdown(token)
    return found
}

Gdip_DisposeImage(haystack)
Gdip_DisposeImage(needle)
Gdip_Shutdown(token)