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)

26 (изменено: KusochekDobra, 2018-04-17 21:36:56)

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

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

"haystack" - второй параметр функции G_Search(), следовательно, HWND окна нужно передать ей вторым параметром. Первым передаёте "ЧТО ищете", вторым "ГДЕ ищете". В случае с окном, координаты передавать не нужно, оставьте пустое место после запятых вместо значений. Поиск производится во всём окне. Окно может быть не активно и скрыто другими окнами, но не свёрнуто. Так же, существуют известные проблемы, связанные с получением изображения таким образом.

Наглядно проверить, корректное ли получается изображение окна, можно, например, так:


#SingleInstance, Force
#NoEnv
SetTitleMatchMode, 2

#Include Gdip.ahk

if (hwnd := WinExist("ahk_class ClassName")) {
	wToken := Gdip_Startup()
	pWin := Gdip_BitmapFromHWND(hwnd)
	Gui,1: Add, Picture,,% "HBITMAP:*" (hPic := Gdip_CreateHBITMAPFromBitmap(pWin))
	Gui,1: Show,,MyWindow
} else {
	MsgBox,,Title,Окно не найдено
	ExitApp
}
return
Escape::
GuiClose:
	DeleteObject(hPic)
	Gdip_DisposeImage(pWin)
	Gdip_Shutdown(wToken)
	ExitApp

27

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

KusochekDobra, забыли объект удалить Gdip_CreateHBITMAPFromBitmap(pWin).

28

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

Решил все же делать снимок всего экрана, а не отдельного окна. Так, как проблемы с черным окном появляются часто.
Составил код и вроде как я начал получать то, что хочу.

Сам код:

#NoEnv
#SingleInstance, Force
#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include G_Search.ahk
#Include Retrieve.ahk

CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetWorkingDir, A_ScriptDir
SetTitleMatchMode, 2
SetBatchLines, -1
xx := 0, yy := 0
ww := 2500, hh := 2500

loop, 6
{
   LIST := ""
   result := []
   needle := Retrieve_%A_Index%_png()
   count := G_Search(needle, "screen", result, xx, yy, ww, hh, 15,,, 100)
   i := 1
   LIST := result[i++]","result[i++]
   Loop, Parse, LIST, `n
   {
      StringSplit, Coord, A_LoopField, `,
      MouseClick, , %Coord1%, %Coord2%, 1 , 0.5
   }
}

Но возникает две проблемы:
1. Скрипт в упор не хочет искать картинки не по порядку. У меня пронумерованы картинки от 1 до 6. Если сначала появится картинка 1, то скрипт будет и дальше все искать как нужно и спокойно найдет и 5 и 6 и 3, но если появится сначала картинка например 2 и выше, то скрипт ничего не ищет дальше. Просто делает 6 попыток и стоит.
2. Скрипт всегда при каждой попытке по новому делает снимок экрана, так как писалось в примере от KusochekDobra, что сначала передаем, что ищем, а потом передаем где ищем. А можно использовать один снимок для всех шести попыток поиска?

29

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


#NoEnv
#SingleInstance, Force
#Include Gdip.ahk
#Include Gdip_ImageSearch.ahk
#Include G_Search.ahk
#Include Retrieve.ahk

CoordMode, Pixel
CoordMode, Mouse
CoordMode, ToolTip
SetWorkingDir, A_ScriptDir
SetTitleMatchMode, 2
SetBatchLines, -1

xx := 0, yy := 0
ww := 2500, hh := 2500
images := [Retrieve_1_png(), Retrieve_2_png(), Retrieve_3_png(), Retrieve_4_png(), Retrieve_5_png(), Retrieve_6_png()]

F1::	; F1
	SetSquare(xx, yy, ww, hh)
	if (count := G_Search(images, "screen", result, xx, yy, ww, hh, 15,,, 100)) {
		SetSquare()
		MsgBox,,Результат,% "Всего = " count
		i := 1
		Loop,% count {
			ToMove(result[i++], result[i++])
			Sleep, 500
		}
	} else
		MsgBox,,Title,Ничего не найдено.
return

G_Search(images,haystack,ByRef outResult,x:=0,y:=0,w:=0,h:=0,vari:=0,trans:="",direction:=1,count:=1) {
    token := Gdip_Startup(), outResult := [], total := 0
	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)
	
	for item, needle in images
	{
		if needle is number
			needlePointer := Gdip_CreateBitmapFromHBITMAP(needle)
		else
			needlePointer := Gdip_CreateBitmapFromFile(needle)
		if (found := Gdip_ImageSearch(haystackPointer,needlePointer,result,0,0,0,0,vari,trans,direction,count,x,y)) {
			total += found
			outResult.Push(result*)
		} Gdip_DisposeImage(needlePointer)
	}
   
    Gdip_DisposeImage(haystackPointer)
    Gdip_Shutdown(token)
    return total
}
ToMove(xx, yy) {
	Send {Click,%xx%,%yy%,0}
}
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

30

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

KusochekDobra Находит, но координаты не определяет. Ответ пуст. Заменил ToMove(result[i++], result[i++]) как было у меня кодом на LIST := result[i++]","result[i++], тоже пусто. Как получить результат с ToMove? Пробовал через MsgBox, тоже пусто. Везде пусто.

31

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

Прошу прощения. Моя вина.
Для возврата по ссылке результата, переменную, которая используется при вызове, нужно инициализировать пустым массивом. Чтобы этого не делать постоянно, я добавил это в тело функции Gdip_ImageSearch() в 18 сообщении, но забыл об этом упомянуть. Обновите пожалуйста код своей Gdip_ImageSearch(), кодом из того примера. Заработает.

32

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

Тоже самое: картинку находит, но в координатах пусто.

33

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

У меня такой результат только в том случае, если возвращающая по ссылке переменная не была инициализирована пустым массивом, о чём говорил выше. Если это сделать, работает как часы. Проверял: два графических элемента, которые в совокупности повторяются 32 раза. Пример выше показывает сообщение с этим количеством и возит курсором по всем 32-м точкам.
Посмотрите внимательно, есть ли в Вашей Gdip_ImageSearch(), в 76 строке, следующее:

OutputList := []

34

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

KusochekDobra Использую Ваш Gdip_ImageSearch() с поста 18 http://forum.script-coding.com/viewtopi … 52#p124752 Прошелся поиском и там нет сочетания OutputList := [].

35

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

При всём желании, я бы не смог удалить эту строку из Вашего файла. Означать это может только то, что после упоминания мной о сделанных изменениях в 18 сообщении, Вы не скопировали содержимое кода из того примера.

Чтобы убедиться в том, что обсуждаемая правка в нём действительно есть, перейдите на страницу с этим сообщением и выполните поиск в браузере используя сочетание "Ctrl+F", после чего, в поле поиска вставьте "OutputList := []".

Последняя правка сообщения №18 с добавлением искомой строки была 16 числа. Обсуждалось это изменение лишь начиная с 19.

36

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

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

37 (изменено: Vicoriyan, 2018-04-27 23:05:06)

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

Вставил рабочий код в свой проект и получаю это: https://ibb.co/eyj9wx. Отдельно работает, а если вставить, получаю ошибку. Что может повлиять? Или с чем может быть конфликт?

38

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

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

Первая строка на скрине, по мнению гугл-переводчика, говорит, что: -"Слишком много параметров передано функции"-. Ниже представляется строкой запись в Вашем коде, поясняющая детали, вызов какой именно функции привёл к этому, а ещё ниже, стрелочкой (--->) указан номер строки в Вашем коде, где эта функция вызывается.

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

39

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

Malcev пишет:

KusochekDobra, забыли объект удалить Gdip_CreateHBITMAPFromBitmap(pWin).

Оказывается, просто так удалить этот объект нельзя, если он побывал в употреблении GUI:


#NoEnv
#SingleInstance, Force

tst_b := "iVBORw0KGgoAAAANSUhEUgAAABcAAAAKCAYAAABfYsXlAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADQSURBVDhPjZFLDsIwDETLpyAhJH73PxgSB2DVLRtEmHE8wQ2JYKTnesZJIO2QUuoitWb/kAseHRbga1MP37PRntYQrfWmal5U5/5kKX+oXsSC1npqCWhe4ArWgOIBthY8GEDyhp3BIuLA/Q3s2UBbMNXrpJAfi2cRPkQ78xN4em8hxBsxp7fX4KL//c6DN4VMOgDe6g52DCAu4A3zWm3yjSxoZ360xn3IpROIOX9oNM8ifIjWekofVEhnEPMLoFaAPn8bHVwjtTIq5nH2ydLwBmR0cKR+ONfmAAAAAElFTkSuQmCC"

tst_r := "iVBORw0KGgoAAAANSUhEUgAAABcAAAAKCAYAAABfYsXlAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAAAlUlEQVQ4T7WQ0QpCMQxDgy/iD/j//+iDoMJMtrWrYQ9ewcLpbZqsiGit/Y0x6LOD/RD2Zhni16PB4ePAnTzIy/bsE9dzp74oRmgAV6I6p+e5wHbLEP4odEV74Tp2RS9D+APO81evjGP5nEkOHUkL8+4pj4dXMqwL+9P33auiSwvkbqJrrPH/D267fE99GF8QtfMqAPAGCQVH5DPl+gUAAAAASUVORK5CYII="

b := H_Func(tst_b)
r := H_Func(tst_r)
Gui,1: Add, Picture,, HBITMAP:%r%
Gui,1: Show,w150 h50
return

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
}
DeleteObject(hObject) {
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}

GuiClose:
GuiEscape:
	result_b := DeleteObject(b)
	result_r := DeleteObject(r)
	MsgBox,,Title,% "result_b = " result_b "`nresult_r = " result_r
	ExitApp

Это вызывает вопросы: удаляется ли потом объект вместе с завершением сценария и если нет, то как его удалить?

40

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

Этот хендл удаляется автоматически при закрытии окна:

a bitmap used on a Picture control is deleted when the GUI is destroyed, and an image will generally be deleted immediately if it needs to be resized. To avoid this, put an asterisk between the colon and handle. For example: hbitmap:*%handle% (or "hbitmap:*" handle in an expression). With the exception of ImageSearch, this forces the command to take a copy of the image.

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