ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

Post your working scripts, libraries and tools.
robodesign
Posts: 941
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

28 Feb 2024, 18:04

@iseahound .impressive work!
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
gdqb521
Posts: 13
Joined: 15 Aug 2015, 08:01

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

12 Mar 2024, 06:21

Hey!

I want to take a screenshot and run an imagesearch on it from a Application thats not currently in the foreground/ covered by other applications.
how to do used imageput ()?

Code: Select all

; 窗口类
ImagePutWindow("ahk_class notepad")

Code: Select all

Error: Image type could not be identified.

	---- d:\LibV2\ImagePut.ah2
	565: If ComObjQuery(image, "{A2296057-EA42-4099-983B-539FB6505426}")
	566: Return "D2dBitmap"
▶	569: Throw Error("Image type could not be identified.")
	570: }
	572: {

The current thread will exit.
=========================================================

Code: Select all

; 或将类型声明为截屏:
ImagePutWindow({screenshot: "Untitled - Notepad", crop: [0, 0, 100, 100]}) ; 使用 BitBlt 进行屏幕捕捉

Code: Select all

Error: This value of type "String" has no method named "Has".

	---- d:\LibV2\ImagePut.ah2
	1422: image := [x, y, w, h]
	1423: }
▶	1429: If image.Has(5) and WinExist(image[5])
	1429: {
	1430: Try
=======================================================================

Code: Select all

; 或将类型声明为截屏:
ImagePutWindow({window: "Untitled - Notepad", crop: [0, 0, 100, 100]})     ; 使用 PrintWindow 进行窗口捕获

Code: Select all

Error: pBitmap cannot be zero.

	---- d:\LibV2\ImagePut.ah2
	314: cleanup := "stream"
	318: If !(pBitmap := this.ImageToBitmap(type, image, keywords))
▶	319: Throw Error("pBitmap cannot be zero.")
	323: (validate) && DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap)
	324: (crop) && this.BitmapCrop(&pBitmap, crop)

The current thread will exit.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

12 Mar 2024, 09:49

That's not me... WinExist() is case sensitive. Try ahk_class Notepad on Windows 11. I think before, it used to be lowercase on Windows 7 and I never changed the documentation.
sushibagel
Posts: 7
Joined: 21 Jun 2024, 12:43

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

21 Jun 2024, 13:15

Thanks for the awesome script iseahound.

I was hoping someone could help me with ImageSearch function in it. I'm able to get it to successfully recognize images if I just feed it an image path for matching. However, I'd like to add a variation allowance but if I feed it a variation amount it seems to always give a match with the top left of my display if the match isn't found.

This seems like it must be a bug but I could also be doing something wrong. Below is the code I've been using for testing this.

This Works

Code: Select all

x::
{
	pic := ImagePutBuffer(0)
	If pic.ImageSearch("C:\Users\User\Desktop\test.png")
		MsgBox "Test"
}
This always gives a match (top left) even if the image is not on the screen.

Code: Select all

	pic := ImagePutBuffer(0)
	If xy := pic.ImageSearch("C:\Users\User\Desktop\test.png", 30)
		MouseMove xy[1], xy[2]
Thanks in advance for any help.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

21 Jun 2024, 17:06

While the PixelSearch module is fully complete, the ImageSearch module might be a little bugged. I should probably review the code and release the next version of ImagePut already. Would you be willing to help test benchmarks and changes?
sushibagel
Posts: 7
Joined: 21 Jun 2024, 12:43

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

21 Jun 2024, 18:16

@iseahound
Sure I'd be happy to help test.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

04 Jul 2024, 16:30

I know this isn't ImageSearch, but I need testers for multithreading (yes, this is real OS level threads) when saving files to disk.

@sushibagel Would you be able to help with this?

Code: Select all

#include ImagePut.ahk

thread_count := InputBox("Number of OS level threads to use:",,, 8).Value
buf := ImagePutBuffer(f := FileSelect())
extension := "png" ; try "jpg" or "bmp"

try DirDelete("yyy", 1)
try DirDelete("zzz", 1)

n := 100
DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0)

DllCall("QueryPerformanceCounter", "int64*", &start:=0)
loop n
   ImagePut.BitmapToFile(buf.pBitmap, "yyy\1." extension)
DllCall("QueryPerformanceCounter", "int64*", &end:=0)
a := n / ((end - start) / frequency)

DllCall("QueryPerformanceCounter", "int64*", &start:=0)
loop n
   fn2(buf, "zzz\" A_Index "." extension)
DllCall("QueryPerformanceCounter", "int64*", &end:=0)
b := n / ((end - start) / frequency)

last_file := "zzz\" n "." extension
;MsgBox FileExist(last_file) ? "Exists" : "Doesn't exist"
;MsgBox s

MsgBox "BitmapToFile:`t`t"    Round(a, 2)   " fps"
   . "`nThread Pool:`t`t"    Round(b, 2)   " fps"
   . "`nNumber of Threads:`t`t" thread_count
   . "`nConvert Extension:`t`t" extension
   . "`nFrames per second (Higher is better)"
   , f



fn(clone, &filepath, &pCodec, &ep, &hThread) {
   pBitmap := clone.pBitmap
   extension := "png"
   quality := ""
   ImagePut.select_filepath(&filepath, &extension)
   ImagePut.select_codec(pBitmap, extension, quality, &pCodec, &ep)
   pcb := callback(pBitmap, &filepath, pCodec, ep)
   ;DllCall(pcb)
   hThread := DllCall("CreateThread", "ptr", 0, "ptr", 0, "ptr", pcb, "ptr", 456, "uint", 0, "uint*", 0, "ptr")

   ; Export objects to manage lifetimes.
   return 
}

fn2(buf, filepath2) {
   clone := buf.Clone()
   pCodec := &pCodec
   ep := &ep
   filepath := &filepath2
   hThread := &hThread2

   static queue := []

   fn(clone, filepath, pCodec, ep, hThread)

   if queue.length >= thread_count {
      c := queue.RemoveAt(1)
      check := %c.hThread%
      start := A_TickCount
      DllCall("WaitForSingleObject", "ptr", check, "uint", 0xFFFFFFFF)
      global s .=  "`n" A_TickCount - start
   ; lifetimes eliminated here.   
   }

   if filepath2 ~= "^zzz\\" n {
      for c in queue
         DllCall("WaitForSingleObject", "ptr", %c.hThread%, "uint", 0xFFFFFFFF)
   }

   continuation := {
      clone: clone,
      pCodec: pCodec,
      ep: ep,
      filepath: filepath,
      hThread: hThread,
      __Delete: (self) => Tooltip(%self.filepath%)
   }

   queue.push(continuation)
}

Esc:: Reload
;DllCall(pcb)
;DllCall(GdipSaveImageToFile, "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "ptr", ep)




callback( pBitmap, &filepath, pCodec, ep) {
   gdiplus := DllCall("GetModuleHandle", "str", "gdiplus.dll", "ptr")
   GdipSaveImageToFile := DllCall("GetProcAddress", "ptr", gdiplus, "astr", "GdipSaveImageToFile", "ptr")

   ncb := (A_PtrSize = 4) ? 28 : 81
   pcb := DllCall("GlobalAlloc", "uint", 0, "uptr", ncb, "ptr")
   DllCall("VirtualProtect", "ptr", pcb, "ptr", ncb, "uint", 0x40, "uint*", 0)

   ; Retract the hex representation to binary.
   ;if (A_PtrSize = 8) {
      assembly := "
         ( Join`s Comments
         48 89 4c 24 08                 ;   0: mov [rsp+8], rcx
         48 89 54 24 10                 ;   5: mov [rsp+16], rdx
         4c 89 44 24 18                 ;  10: mov [rsp+24], r8
         4c 89 4c 24 20                 ;  15: mov [rsp+32], r9
         48 83 ec 28                    ;  20: sub rsp, 40
         49 b9 00 00 00 00 00 00 00 00  ;  24: mov r9, .. (ep)
         49 b8 00 00 00 00 00 00 00 00  ;  34: mov r8, .. (pCodec)
         48 ba 00 00 00 00 00 00 00 00  ;  44: mov edx, .. (&filepath)
         48 b9 00 00 00 00 00 00 00 00  ;  54: mov ecx, .. (pBitmap)
         48 b8 00 00 00 00 00 00 00 00  ;  64: mov rax, .. (GdipSaveImageToFile)
         ff d0                          ;  74: call rax
         48 83 c4 28                    ;  76: add rsp, 40
         c3                             ;  80: ret
         )"                             ;  81:
      DllCall("crypt32\CryptStringToBinary", "str", assembly, "uint", 0, "uint", 0x4, "ptr", pcb, "uint*", ncb, "ptr", 0, "ptr", 0)
      NumPut("ptr", GdipSaveImageToFile, pcb + 66)
      NumPut("ptr", pBitmap, pcb + 56)
      NumPut("ptr", StrPtr(filepath), pcb + 46)
      NumPut("ptr", pCodec.ptr, pcb + 36)
      NumPut("ptr", ep, pcb + 26)

/*
   }
   else {
      assembly := "
         ( Join`s Comments
         68 00 00 00 00                 ; push .. (lParam)
         68 00 00 00 00                 ; push .. (wParam)
         68 00 00 00 00                 ; push .. (uMsg)
         68 00 00 00 00                 ; push .. (hwnd)
         b8 00 00 00 00                 ; mov eax, .. (SendMessageW)
         ff d0                          ; call eax
         c3                             ; ret
         )"
      DllCall("crypt32\CryptStringToBinary", "str", assembly, "uint", 0, "uint", 0x4, "ptr", pcb, "uint*", ncb, "ptr", 0, "ptr", 0)
      NumPut("int", SendMessageW, pcb + 21)
      NumPut("int", hwnd, pcb + 16)
      NumPut("int", uMsg, pcb + 11)
      NumPut("int", wParam, pcb + 6)
      NumPut("int", lParam, pcb + 1)
   }
*/
   ; return pcb
   return pcb
}
Anyone is free to test this. I'm looking for a good default number of threads to use, but I don't have large number of computers to test this on. A zip file is included to make things easier to test. The purpose of this is to increase the screen capture and save to file frame rate to over 60 fps. Eskitit!!!!!
Attachments
Save Image To File (multi-threaded).zip
(59.32 KiB) Downloaded 54 times
sushibagel
Posts: 7
Joined: 21 Jun 2024, 12:43

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

04 Jul 2024, 17:33

iseahound wrote:
04 Jul 2024, 16:30
I know this isn't ImageSearch, but I need testers for multithreading (yes, this is real OS level threads) when saving files to disk.

@sushibagel Would you be able to help with this?

Code: Select all

#include ImagePut.ahk

thread_count := InputBox("Number of OS level threads to use:",,, 8).Value
buf := ImagePutBuffer(f := FileSelect())
extension := "png" ; try "jpg" or "bmp"

try DirDelete("yyy", 1)
try DirDelete("zzz", 1)

n := 100
DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0)

DllCall("QueryPerformanceCounter", "int64*", &start:=0)
loop n
   ImagePut.BitmapToFile(buf.pBitmap, "yyy\1." extension)
DllCall("QueryPerformanceCounter", "int64*", &end:=0)
a := n / ((end - start) / frequency)

DllCall("QueryPerformanceCounter", "int64*", &start:=0)
loop n
   fn2(buf, "zzz\" A_Index "." extension)
DllCall("QueryPerformanceCounter", "int64*", &end:=0)
b := n / ((end - start) / frequency)

last_file := "zzz\" n "." extension
;MsgBox FileExist(last_file) ? "Exists" : "Doesn't exist"
;MsgBox s

MsgBox "BitmapToFile:`t`t"    Round(a, 2)   " fps"
   . "`nThread Pool:`t`t"    Round(b, 2)   " fps"
   . "`nNumber of Threads:`t`t" thread_count
   . "`nConvert Extension:`t`t" extension
   . "`nFrames per second (Higher is better)"
   , f



fn(clone, &filepath, &pCodec, &ep, &hThread) {
   pBitmap := clone.pBitmap
   extension := "png"
   quality := ""
   ImagePut.select_filepath(&filepath, &extension)
   ImagePut.select_codec(pBitmap, extension, quality, &pCodec, &ep)
   pcb := callback(pBitmap, &filepath, pCodec, ep)
   ;DllCall(pcb)
   hThread := DllCall("CreateThread", "ptr", 0, "ptr", 0, "ptr", pcb, "ptr", 456, "uint", 0, "uint*", 0, "ptr")

   ; Export objects to manage lifetimes.
   return 
}

fn2(buf, filepath2) {
   clone := buf.Clone()
   pCodec := &pCodec
   ep := &ep
   filepath := &filepath2
   hThread := &hThread2

   static queue := []

   fn(clone, filepath, pCodec, ep, hThread)

   if queue.length >= thread_count {
      c := queue.RemoveAt(1)
      check := %c.hThread%
      start := A_TickCount
      DllCall("WaitForSingleObject", "ptr", check, "uint", 0xFFFFFFFF)
      global s .=  "`n" A_TickCount - start
   ; lifetimes eliminated here.   
   }

   if filepath2 ~= "^zzz\\" n {
      for c in queue
         DllCall("WaitForSingleObject", "ptr", %c.hThread%, "uint", 0xFFFFFFFF)
   }

   continuation := {
      clone: clone,
      pCodec: pCodec,
      ep: ep,
      filepath: filepath,
      hThread: hThread,
      __Delete: (self) => Tooltip(%self.filepath%)
   }

   queue.push(continuation)
}

Esc:: Reload
;DllCall(pcb)
;DllCall(GdipSaveImageToFile, "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "ptr", ep)




callback( pBitmap, &filepath, pCodec, ep) {
   gdiplus := DllCall("GetModuleHandle", "str", "gdiplus.dll", "ptr")
   GdipSaveImageToFile := DllCall("GetProcAddress", "ptr", gdiplus, "astr", "GdipSaveImageToFile", "ptr")

   ncb := (A_PtrSize = 4) ? 28 : 81
   pcb := DllCall("GlobalAlloc", "uint", 0, "uptr", ncb, "ptr")
   DllCall("VirtualProtect", "ptr", pcb, "ptr", ncb, "uint", 0x40, "uint*", 0)

   ; Retract the hex representation to binary.
   ;if (A_PtrSize = 8) {
      assembly := "
         ( Join`s Comments
         48 89 4c 24 08                 ;   0: mov [rsp+8], rcx
         48 89 54 24 10                 ;   5: mov [rsp+16], rdx
         4c 89 44 24 18                 ;  10: mov [rsp+24], r8
         4c 89 4c 24 20                 ;  15: mov [rsp+32], r9
         48 83 ec 28                    ;  20: sub rsp, 40
         49 b9 00 00 00 00 00 00 00 00  ;  24: mov r9, .. (ep)
         49 b8 00 00 00 00 00 00 00 00  ;  34: mov r8, .. (pCodec)
         48 ba 00 00 00 00 00 00 00 00  ;  44: mov edx, .. (&filepath)
         48 b9 00 00 00 00 00 00 00 00  ;  54: mov ecx, .. (pBitmap)
         48 b8 00 00 00 00 00 00 00 00  ;  64: mov rax, .. (GdipSaveImageToFile)
         ff d0                          ;  74: call rax
         48 83 c4 28                    ;  76: add rsp, 40
         c3                             ;  80: ret
         )"                             ;  81:
      DllCall("crypt32\CryptStringToBinary", "str", assembly, "uint", 0, "uint", 0x4, "ptr", pcb, "uint*", ncb, "ptr", 0, "ptr", 0)
      NumPut("ptr", GdipSaveImageToFile, pcb + 66)
      NumPut("ptr", pBitmap, pcb + 56)
      NumPut("ptr", StrPtr(filepath), pcb + 46)
      NumPut("ptr", pCodec.ptr, pcb + 36)
      NumPut("ptr", ep, pcb + 26)

/*
   }
   else {
      assembly := "
         ( Join`s Comments
         68 00 00 00 00                 ; push .. (lParam)
         68 00 00 00 00                 ; push .. (wParam)
         68 00 00 00 00                 ; push .. (uMsg)
         68 00 00 00 00                 ; push .. (hwnd)
         b8 00 00 00 00                 ; mov eax, .. (SendMessageW)
         ff d0                          ; call eax
         c3                             ; ret
         )"
      DllCall("crypt32\CryptStringToBinary", "str", assembly, "uint", 0, "uint", 0x4, "ptr", pcb, "uint*", ncb, "ptr", 0, "ptr", 0)
      NumPut("int", SendMessageW, pcb + 21)
      NumPut("int", hwnd, pcb + 16)
      NumPut("int", uMsg, pcb + 11)
      NumPut("int", wParam, pcb + 6)
      NumPut("int", lParam, pcb + 1)
   }
*/
   ; return pcb
   return pcb
}
Anyone is free to test this. I'm looking for a good default number of threads to use, but I don't have large number of computers to test this on. A zip file is included to make things easier to test. The purpose of this is to increase the screen capture and save to file frame rate to over 60 fps. Eskitit!!!!!
Ran it twice. First time was while my laptop was running on battery with a lower performance mode (53 FPS), second time while plugged in (119 FPS).
Attachments
Screenshot 2024-07-04 152914.png
Screenshot 2024-07-04 152914.png (13.48 KiB) Viewed 2454 times
Screenshot 2024-07-04 152255.png
Screenshot 2024-07-04 152255.png (11.91 KiB) Viewed 2454 times
TraitorJoes
Posts: 3
Joined: 12 Apr 2021, 18:21

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

12 Jul 2024, 18:26

Not sure if you need any system details.. lmk or if you'd like more tests run?

Here's it run on 3 different images.
Attachments
2024_07_12_18_25_04.PNG
2024_07_12_18_25_04.PNG (5.13 KiB) Viewed 2348 times
2024_07_12_18_24_30.PNG
2024_07_12_18_24_30.PNG (5.1 KiB) Viewed 2348 times
2024_07_12_18_15_51.PNG
2024_07_12_18_15_51.PNG (5.12 KiB) Viewed 2348 times
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

14 Jul 2024, 02:00

@TraitorJoes @sushibagel Thanks for the benchmarks!

New Benchmarks For Testing - Capture Screen and Save To File at 60 FPS

The following is an updated set of benchmarks that now uses the Desktop Duplication API to capture the screen. Because the Desktop duplication API only updates when there is a new image, your values should be capped at 60fps - which is what I'm aiming for across all computers whether they be fast or slow.
image.png
image.png (474.02 KiB) Viewed 2260 times
Attachments
DirectX Screen Capture Benchmark.zip
(60.37 KiB) Downloaded 49 times
sushibagel
Posts: 7
Joined: 21 Jun 2024, 12:43

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

14 Jul 2024, 10:14

@iseahound

Here are my test runs.
image.png
image.png (33.61 KiB) Viewed 2184 times
image.png
image.png (38.54 KiB) Viewed 2184 times
image.png
image.png (33.22 KiB) Viewed 2184 times

[Mod edit: Removed img tags from around attachments which resulted in broken image icons. They are only for use with URLs to image files.]
songdg
Posts: 699
Joined: 04 Oct 2017, 20:04

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

12 Aug 2024, 04:18

Thanks for sharing, can use this library to convert an image to black-and-white?
User avatar
Komrad Toast
Posts: 51
Joined: 28 Jun 2024, 02:19
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

16 Aug 2024, 05:57

@iseahound
Awesome work! Just for fun I used the example on the github of looping through pixels with my new Color library, and it works perfectly! My library is a bit slow in this regard, but it wasn't really meant for Image Manipulation anyways. A 256x256 image takes ~6 seconds to invert :lol:.

Code: Select all

#Include <Classes/Color>
#Include ImagePut.ahk

pic :=  ImagePutBuffer([0, 0, 256, 256])
pic.Show()

for x, y, curColor in pic
    pic[x, y] := Color(curColor).Invert().ToHex("0xFF{R}{G}{B}").Full

pic.Show()
Image

Again, Awesome work!
Last edited by Komrad Toast on 16 Aug 2024, 07:02, edited 1 time in total.

My GitHub
My Projects
  • KeyChord - A class for writing Key Chords (key strings, key sequences, key chains, etc...)
  • YACS - Yet Another Color Selector (A fast GDI color selector)
  • Color - A class to facilitate Color operations. Used by YACS.
User avatar
Komrad Toast
Posts: 51
Joined: 28 Jun 2024, 02:19
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

16 Aug 2024, 06:43

Actually, this is surprising...
Image

I used my current implementation of the Inversion algorithm, then a GDI+ ColorMatrix, then GdipBlendColor. These are the results from one test, but I ran it many times and the current implementation was consistently faster.

Edit: Oof, just using this gets a 256x256 pixel image inverted in 0.27 seconds.

Code: Select all

#Include ImagePut.ahk

pic :=  ImagePutBuffer([0, 0, 256, 256])
pic.Show()

for x, y, curColor in pic
    pic[x, y] := curColor ^ 0xFFFFFFFF

pic.Show()

My GitHub
My Projects
  • KeyChord - A class for writing Key Chords (key strings, key sequences, key chains, etc...)
  • YACS - Yet Another Color Selector (A fast GDI color selector)
  • Color - A class to facilitate Color operations. Used by YACS.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

16 Aug 2024, 07:59

Since you're on the topic of optimizing, do you think https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-colorhlstorgb would be faster?

The for color; for x, y; and for x, y, color syntax is convenient yet slow.
User avatar
Komrad Toast
Posts: 51
Joined: 28 Jun 2024, 02:19
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

16 Aug 2024, 09:22

I've been looking in to shlwapi. I tried using the ColorRGBToHSL func, but it was spitting out incorrect results. Probably just me not giving it input in the right format. But I have almost no doubt it would be faster. The GDI calls that I made were honestly only that slow because of the way that my color class stores the color data (I made it to work with single colors, mainly for web development, etc).

My GitHub
My Projects
  • KeyChord - A class for writing Key Chords (key strings, key sequences, key chains, etc...)
  • YACS - Yet Another Color Selector (A fast GDI color selector)
  • Color - A class to facilitate Color operations. Used by YACS.
dostroll
Posts: 52
Joined: 03 Nov 2021, 08:56

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

13 Sep 2024, 10:42

I am creating an emoji display that smoothly follows the mouse along with a tooltip.
The tooltip was successful, but the imageshow is behaving less than ideally.
Are there any best practices?

I tried my best to implement it, but the movement is awkward.

Code: Select all

global hWnd := 0
UpdateImagePosition() {
  MouseGetPos(&X, &Y)
  X -= 10
  Y += 16
  if (hWnd) {
    WinMove(X, Y, , , "ahk_id " hWnd)
  } else {
    hWnd := ImageShow(LoadPicture("C:\Windows\System32\shell32.dll", "Icon44"), , [X, Y, 40, 40])
  }
}
SetTimer(UpdateImagePosition, 5)
User avatar
kczx3
Posts: 1677
Joined: 06 Oct 2015, 21:39

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

13 Sep 2024, 11:50

Stop calling LoadPicture inside your function... Either call it outside and reference the global variable inside your function or assign it to a static variable inside the function.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

13 Sep 2024, 14:53

@dostroll Yeah this disgusting code:

Faster?

Code: Select all

#include ImagePut.ahk

hWnd := ImageShow(LoadPicture("C:\Windows\System32\shell32.dll", "Icon44"), , [0, 0, 40, 40])

; Creates a user defined callback using multimedia timers with a resolution of 1ms.
; The callback is placed in the wParam and called when the window message receives 0x8003.
DllCall("winmm\timeSetEvent"
         , "uint", 1             ; uDelay
         , "uint", 1             ; uResolution
         ,  "ptr", ImagePut.SyncWindowProc(hwnd, 0x8003, ObjPtr(UpdateImagePosition)) ; lpTimeProc
         , "uptr", 0             ; dwUser
         , "uint", 1             ; fuEvent
         , "uint")

UpdateImagePosition(hwnd) {
   DllCall("GetCursorPos", "ptr", point := Buffer(8))
      , x := NumGet(point, 0, "int") - 10
      , y := NumGet(point, 4, "int") + 16

   ; Don't know why UpdateLayeredWindow is faster compared to WinMove.
   DllCall("UpdateLayeredWindow"
         ,    "ptr", hwnd                     ; hWnd
         ,    "ptr", 0                        ; hdcDst
         ,"uint64*", x << 32 >>> 32 | y << 32 ; *pptDst
         ,    "ptr", 0                        ; *psize
         ,    "ptr", 0                        ; hdcSrc
         ,    "ptr", 0                        ; *pptSrc
         ,   "uint", 0                        ; crKey
         ,  "uint*", 0xFF << 16 | 0x01 << 24  ; *pblend
         ,   "uint", 2)                       ; dwFlags
}
Slower?

Code: Select all

#include ImagePut.ahk

hWnd := ImageShow(LoadPicture("C:\Windows\System32\shell32.dll", "Icon44"), , [0, 0, 40, 40])

; Using this causes some "jumping" when moving the image.
SetTimer(UpdateImagePosition.bind(hwnd), 1) ; Updates every tick (10 or 15.6 ms)

UpdateImagePosition(hwnd) {
   DllCall("GetCursorPos", "ptr", point := Buffer(8))
      , x := NumGet(point, 0, "int") - 10
      , y := NumGet(point, 4, "int") + 16

   ; Don't know why UpdateLayeredWindow is faster compared to WinMove.
   DllCall("UpdateLayeredWindow"
         ,    "ptr", hwnd                     ; hWnd
         ,    "ptr", 0                        ; hdcDst
         ,"uint64*", x << 32 >>> 32 | y << 32 ; *pptDst
         ,    "ptr", 0                        ; *psize
         ,    "ptr", 0                        ; hdcSrc
         ,    "ptr", 0                        ; *pptSrc
         ,   "uint", 0                        ; crKey
         ,  "uint*", 0xFF << 16 | 0x01 << 24  ; *pblend
         ,   "uint", 2)                       ; dwFlags
}
I've pushed an update to ImagePut to support this hack, you'll need to download a new copy: https://github.com/iseahound/ImagePut/blob/master/ImagePut.ahk (can't be posted on the forum due to size)
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: ImagePut - A core library for images in AutoHotkey (Now supports HEIC & WEBP)

13 Sep 2024, 15:53

Animation.gif
Animation.gif (162.76 KiB) Viewed 1173 times
Animation2.gif
Animation2.gif (569.45 KiB) Viewed 1173 times

Code: Select all

#include ImagePut.ahk

AnimatedCursor("https://media.tenor.com/6ceOmdT7SHkAAAAi/emoji-emojis.gif", -15, 32,, 100)
AnimatedCursor("https://media.tenor.com/rbIQJHPHD6UAAAAi/cat-shoot.gif", 32, -50)
; AnimatedCursor("https://media.tenor.com/dmYlPVcctp8AAAAi/discord-emoji.gif")

AnimatedCursor(image, dx := 0, dy := 0, width?, height?) {

   ; Omit width or height to keep aspect ratio
   hwnd := ImageShow(image,, [0, 0, width?, height?],, 0x80088 | 0x20) ; Clickthrough

   ; Creates a user defined callback using multimedia timers with a resolution of 1ms.
   ; The callback is placed in the wParam and called when the window message receives 0x8003.
   callback := ObjPtrAddRef(UpdateImagePosition.bind(dx, dy))
   pTimeProc := ImagePut.SyncWindowProc(hwnd, 0x8003, callback)
   timer := DllCall("winmm\timeSetEvent"
            , "uint", 1             ; uDelay
            , "uint", 1             ; uResolution
            ,  "ptr", pTimeProc     ; lpTimeProc
            , "uptr", 0             ; dwUser
            , "uint", 1             ; fuEvent
            , "uint")

   free() => (
      DllCall("winmm\timeKillEvent", "uint", timer),
      DllCall("GlobalFree", "ptr", pTimeProc),
      ObjRelease(callback),
      DllCall("DestroyWindow", "ptr", hwnd)
   )
   return free

   UpdateImagePosition(dx, dy, hwnd) {
      DllCall("GetCursorPos", "ptr", point := Buffer(8))
         , x := NumGet(point, 0, "int") + dx
         , y := NumGet(point, 4, "int") + dy

      ; Don't know why UpdateLayeredWindow is faster compared to WinMove.
      DllCall("UpdateLayeredWindow"
            ,    "ptr", hwnd                     ; hWnd
            ,    "ptr", 0                        ; hdcDst
            ,"uint64*", x << 32 >>> 32 | y << 32 ; *pptDst
            ,    "ptr", 0                        ; *psize
            ,    "ptr", 0                        ; hdcSrc
            ,    "ptr", 0                        ; *pptSrc
            ,   "uint", 0                        ; crKey
            ,  "uint*", 0xFF << 16 | 0x01 << 24  ; *pblend
            ,   "uint", 2)                       ; dwFlags
   }
}

Return to “Scripts and Functions (v2)”

Who is online

Users browsing this forum: gdqb521 and 40 guests